search.c 36.1 KB
Newer Older
Howard Chu's avatar
Howard Chu committed
1
2
3
4
/* search.c - search operation */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 *
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
5
 * Copyright 2000-2021 The OpenLDAP Foundation.
Howard Chu's avatar
Howard Chu committed
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted only as authorized by the OpenLDAP
 * Public License.
 *
 * A copy of this license is available in the file LICENSE in the
 * top-level directory of the distribution or, alternatively, at
 * <http://www.OpenLDAP.org/license.html>.
 */

#include "portable.h"

#include <stdio.h>
#include <ac/string.h>

#include "back-mdb.h"
#include "idl.h"

static int base_candidate(
	BackendDB	*be,
	Entry	*e,
	ID		*ids );

static int search_candidates(
	Operation *op,
	SlapReply *rs,
	Entry *e,
Howard Chu's avatar
Howard Chu committed
34
	IdScopes *isc,
Howard Chu's avatar
Howard Chu committed
35
	MDB_cursor *mci,
Howard Chu's avatar
Howard Chu committed
36
	ID	*ids,
37
	ID *stack );
Howard Chu's avatar
Howard Chu committed
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100

static int parse_paged_cookie( Operation *op, SlapReply *rs );

static void send_paged_response( 
	Operation *op,
	SlapReply *rs,
	ID  *lastid,
	int tentries );

/* Dereference aliases for a single alias entry. Return the final
 * dereferenced entry on success, NULL on any failure.
 */
static Entry * deref_base (
	Operation *op,
	SlapReply *rs,
	Entry *e,
	Entry **matched,
	MDB_txn *txn,
	ID	*tmp,
	ID	*visited )
{
	struct berval ndn;

	rs->sr_err = LDAP_ALIAS_DEREF_PROBLEM;
	rs->sr_text = "maximum deref depth exceeded";

	for (;;) {
		/* Remember the last entry we looked at, so we can
		 * report broken links
		 */
		*matched = e;

		if (MDB_IDL_N(tmp) >= op->o_bd->be_max_deref_depth) {
			e = NULL;
			break;
		}

		/* If this is part of a subtree or onelevel search,
		 * have we seen this ID before? If so, quit.
		 */
		if ( visited && mdb_idl_insert( visited, e->e_id ) ) {
			e = NULL;
			break;
		}

		/* If we've seen this ID during this deref iteration,
		 * we've hit a loop.
		 */
		if ( mdb_idl_insert( tmp, e->e_id ) ) {
			rs->sr_err = LDAP_ALIAS_PROBLEM;
			rs->sr_text = "circular alias";
			e = NULL;
			break;
		}

		/* If there was a problem getting the aliasedObjectName,
		 * get_alias_dn will have set the error status.
		 */
		if ( get_alias_dn(e, &ndn, &rs->sr_err, &rs->sr_text) ) {
			e = NULL;
			break;
		}

101
		rs->sr_err = mdb_dn2entry( op, txn, NULL, &ndn, &e, NULL, 0 );
Howard Chu's avatar
Howard Chu committed
102
103
104
105
106
107
108
109
110
		if (rs->sr_err) {
			rs->sr_err = LDAP_ALIAS_PROBLEM;
			rs->sr_text = "aliasedObject not found";
			break;
		}

		/* Free the previous entry, continue to work with the
		 * one we just retrieved.
		 */
Howard Chu's avatar
Howard Chu committed
111
		mdb_entry_return( op, *matched );
Howard Chu's avatar
Howard Chu committed
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131

		/* We found a regular entry. Return this to the caller.
		 */
		if (!is_entry_alias(e)) {
			rs->sr_err = LDAP_SUCCESS;
			rs->sr_text = NULL;
			break;
		}
	}
	return e;
}

/* Look for and dereference all aliases within the search scope.
 * Requires "stack" to be able to hold 6 levels of DB_SIZE IDLs.
 * Of course we're hardcoded to require a minimum of 8 UM_SIZE
 * IDLs so this is never a problem.
 */
static int search_aliases(
	Operation *op,
	SlapReply *rs,
132
	ID e_id,
Howard Chu's avatar
Howard Chu committed
133
	IdScopes *isc,
Howard Chu's avatar
Howard Chu committed
134
	MDB_cursor *mci,
Howard Chu's avatar
Howard Chu committed
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
	ID *stack )
{
	ID *aliases, *curscop, *visited, *newsubs, *oldsubs, *tmp;
	ID cursora, ida, cursoro, ido;
	Entry *matched, *a;
	struct berval bv_alias = BER_BVC( "alias" );
	AttributeAssertion aa_alias = ATTRIBUTEASSERTION_INIT;
	Filter	af;

	aliases = stack;	/* IDL of all aliases in the database */
	curscop = aliases + MDB_IDL_DB_SIZE;	/* Aliases in the current scope */
	visited = curscop + MDB_IDL_DB_SIZE;	/* IDs we've seen in this search */
	newsubs = visited + MDB_IDL_DB_SIZE;	/* New subtrees we've added */
	oldsubs = newsubs + MDB_IDL_DB_SIZE;	/* Subtrees added previously */
	tmp = oldsubs + MDB_IDL_DB_SIZE;	/* Scratch space for deref_base() */

	af.f_choice = LDAP_FILTER_EQUALITY;
	af.f_ava = &aa_alias;
	af.f_av_desc = slap_schema.si_ad_objectClass;
	af.f_av_value = bv_alias;
	af.f_next = NULL;

	/* Find all aliases in database */
	MDB_IDL_ZERO( aliases );
Howard Chu's avatar
Howard Chu committed
159
	rs->sr_err = mdb_filter_candidates( op, isc->mt, &af, aliases,
Howard Chu's avatar
Howard Chu committed
160
		curscop, visited );
161
	if (rs->sr_err != LDAP_SUCCESS || MDB_IDL_IS_ZERO( aliases )) {
Howard Chu's avatar
Howard Chu committed
162
163
		return rs->sr_err;
	}
Howard Chu's avatar
Howard Chu committed
164
165
166
167
168
169
	if ( op->ors_limit	/* isroot == FALSE */ &&
		op->ors_limit->lms_s_unchecked != -1 &&
		MDB_IDL_N( aliases ) > (unsigned) op->ors_limit->lms_s_unchecked )
	{
		return LDAP_ADMINLIMIT_EXCEEDED;
	}
Howard Chu's avatar
Howard Chu committed
170
	oldsubs[0] = 1;
171
	oldsubs[1] = e_id;
Howard Chu's avatar
Howard Chu committed
172
173
174
175
176
177
178
179
180
181
182

	MDB_IDL_ZERO( visited );
	MDB_IDL_ZERO( newsubs );

	cursoro = 0;
	ido = mdb_idl_first( oldsubs, &cursoro );

	for (;;) {
		/* Set curscop to only the aliases in the current scope. Start with
		 * all the aliases, then get the intersection with the scope.
		 */
Howard Chu's avatar
Howard Chu committed
183
		rs->sr_err = mdb_idscope( op, isc->mt, e_id, aliases, curscop );
Howard Chu's avatar
Howard Chu committed
184
185
186
187
188
189

		/* Dereference all of the aliases in the current scope. */
		cursora = 0;
		for (ida = mdb_idl_first(curscop, &cursora); ida != NOID;
			ida = mdb_idl_next(curscop, &cursora))
		{
Howard Chu's avatar
Howard Chu committed
190
			rs->sr_err = mdb_id2entry(op, mci, ida, &a);
Howard Chu's avatar
Howard Chu committed
191
192
193
194
195
196
197
198
			if (rs->sr_err != LDAP_SUCCESS) {
				continue;
			}

			/* This should only happen if the curscop IDL has maxed out and
			 * turned into a range that spans IDs indiscriminately
			 */
			if (!is_entry_alias(a)) {
Howard Chu's avatar
Howard Chu committed
199
				mdb_entry_return(op, a);
Howard Chu's avatar
Howard Chu committed
200
201
202
203
204
				continue;
			}

			/* Actually dereference the alias */
			MDB_IDL_ZERO(tmp);
Howard Chu's avatar
Howard Chu committed
205
			a = deref_base( op, rs, a, &matched, isc->mt,
Howard Chu's avatar
Howard Chu committed
206
207
208
209
210
				tmp, visited );
			if (a) {
				/* If the target was not already in our current scopes,
				 * make note of it in the newsubs list.
				 */
Howard Chu's avatar
Howard Chu committed
211
212
213
				ID2 mid;
				mid.mid = a->e_id;
				mid.mval.mv_data = NULL;
Howard Chu's avatar
Howard Chu committed
214
215
216
217
218
219
220
221
222
				if (op->ors_scope == LDAP_SCOPE_SUBTREE) {
					isc->id = a->e_id;
					/* if ID is a child of any of our current scopes,
					 * ignore it, it's already included.
					 */
					if (mdb_idscopechk(op, isc))
						goto skip;
				}
				if (mdb_id2l_insert(isc->scopes, &mid) == 0) {
Howard Chu's avatar
Howard Chu committed
223
224
					mdb_idl_insert(newsubs, a->e_id);
				}
Howard Chu's avatar
Howard Chu committed
225
skip:			mdb_entry_return( op, a );
Howard Chu's avatar
Howard Chu committed
226
227
228
229
230

			} else if (matched) {
				/* Alias could not be dereferenced, or it deref'd to
				 * an ID we've already seen. Ignore it.
				 */
Howard Chu's avatar
Howard Chu committed
231
				mdb_entry_return( op, matched );
Howard Chu's avatar
Howard Chu committed
232
				rs->sr_text = NULL;
Howard Chu's avatar
Howard Chu committed
233
				rs->sr_err = 0;
Howard Chu's avatar
Howard Chu committed
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
			}
		}
		/* If this is a OneLevel search, we're done; oldsubs only had one
		 * ID in it. For a Subtree search, oldsubs may be a list of scope IDs.
		 */
		if ( op->ors_scope == LDAP_SCOPE_ONELEVEL ) break;
nextido:
		ido = mdb_idl_next( oldsubs, &cursoro );
		
		/* If we're done processing the old scopes, did we add any new
		 * scopes in this iteration? If so, go back and do those now.
		 */
		if (ido == NOID) {
			if (MDB_IDL_IS_ZERO(newsubs)) break;
			MDB_IDL_CPY(oldsubs, newsubs);
			MDB_IDL_ZERO(newsubs);
			cursoro = 0;
			ido = mdb_idl_first( oldsubs, &cursoro );
		}

		/* Find the entry corresponding to the next scope. If it can't
		 * be found, ignore it and move on. This should never happen;
		 * we should never see the ID of an entry that doesn't exist.
		 */
258
259
260
261
262
263
264
		{
			MDB_val edata;
			rs->sr_err = mdb_id2edata(op, mci, ido, &edata);
			if ( rs->sr_err != MDB_SUCCESS ) {
				goto nextido;
			}
			e_id = ido;
Howard Chu's avatar
Howard Chu committed
265
266
267
268
269
270
271
272
273
		}
	}
	return rs->sr_err;
}

/* Get the next ID from the DB. Used if the candidate list is
 * a range and simple iteration hits missing entryIDs
 */
static int
Howard Chu's avatar
Howard Chu committed
274
mdb_get_nextid(MDB_cursor *mci, ID *cursor)
Howard Chu's avatar
Howard Chu committed
275
276
277
278
279
280
281
282
{
	MDB_val key;
	ID id;
	int rc;

	id = *cursor + 1;
	key.mv_data = &id;
	key.mv_size = sizeof(ID);
Howard Chu's avatar
Howard Chu committed
283
	rc = mdb_cursor_get( mci, &key, NULL, MDB_SET_RANGE );
Howard Chu's avatar
Howard Chu committed
284
285
286
287
288
289
	if ( rc )
		return rc;
	memcpy( cursor, key.mv_data, sizeof(ID));
	return 0;
}

Howard Chu's avatar
Howard Chu committed
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
static void scope_chunk_free( void *key, void *data )
{
	ID2 *p1, *p2;
	for (p1 = data; p1; p1 = p2) {
		p2 = p1[0].mval.mv_data;
		ber_memfree_x(p1, NULL);
	}
}

static ID2 *scope_chunk_get( Operation *op )
{
	ID2 *ret = NULL;

	ldap_pvt_thread_pool_getkey( op->o_threadctx, (void *)scope_chunk_get,
			(void *)&ret, NULL );
	if ( !ret ) {
		ret = ch_malloc( MDB_IDL_UM_SIZE * sizeof( ID2 ));
	} else {
		void *r2 = ret[0].mval.mv_data;
		ldap_pvt_thread_pool_setkey( op->o_threadctx, (void *)scope_chunk_get,
			r2, scope_chunk_free, NULL, NULL );
	}
	return ret;
}

static void scope_chunk_ret( Operation *op, ID2 *scopes )
{
	void *ret = NULL;

	ldap_pvt_thread_pool_getkey( op->o_threadctx, (void *)scope_chunk_get,
			&ret, NULL );
	scopes[0].mval.mv_data = ret;
	ldap_pvt_thread_pool_setkey( op->o_threadctx, (void *)scope_chunk_get,
			(void *)scopes, scope_chunk_free, NULL, NULL );
}

326
327
static void *search_stack( Operation *op );

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
328
329
typedef struct ww_ctx {
	MDB_txn *txn;
Howard Chu's avatar
Howard Chu committed
330
331
332
	MDB_cursor *mcd;	/* if set, save cursor context */
	ID key;
	MDB_val data;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
333
	int flag;
334
	unsigned nentries;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
335
336
} ww_ctx;

Howard Chu's avatar
Howard Chu committed
337
338
339
340
341
342
343
344
345
346
/* ITS#7904 if we get blocked while writing results to client,
 * release the current reader txn and reacquire it after we
 * unblock.
 * Slight problem - if we're doing a scope-based walk (mdb_dn2id_walk)
 * to return results, we need to remember the state of the mcd cursor.
 * If the node that cursor was pointing to gets deleted while we're
 * blocked, we may be unable to restore the cursor position. In that
 * case return an LDAP_BUSY error - let the client know this search
 * couldn't succeed, but might succeed on a retry.
 */
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
static void
mdb_rtxn_snap( Operation *op, ww_ctx *ww )
{
	/* save cursor position and release read txn */
	if ( ww->mcd ) {
		MDB_val key, data;
		mdb_cursor_get( ww->mcd, &key, &data, MDB_GET_CURRENT );
		memcpy( &ww->key, key.mv_data, sizeof(ID) );
		ww->data.mv_size = data.mv_size;
		ww->data.mv_data = op->o_tmpalloc( data.mv_size, op->o_tmpmemctx );
		memcpy(ww->data.mv_data, data.mv_data, data.mv_size);
	}
	mdb_txn_reset( ww->txn );
	ww->flag = 1;
}

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
363
364
365
366
367
static void
mdb_writewait( Operation *op, slap_callback *sc )
{
	ww_ctx *ww = sc->sc_private;
	if ( !ww->flag ) {
368
		mdb_rtxn_snap( op, ww );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
369
370
371
	}
}

Howard Chu's avatar
Howard Chu committed
372
static int
373
mdb_waitfixup( Operation *op, ww_ctx *ww, MDB_cursor *mci, MDB_cursor *mcd, IdScopes *isc )
Howard Chu's avatar
Howard Chu committed
374
{
375
	MDB_val key;
Howard Chu's avatar
Howard Chu committed
376
377
378
379
380
	int rc = 0;
	ww->flag = 0;
	mdb_txn_renew( ww->txn );
	mdb_cursor_renew( ww->txn, mci );
	mdb_cursor_renew( ww->txn, mcd );
381

382
383
384
	key.mv_size = sizeof(ID);
	if ( ww->mcd ) {	/* scope-based search using dn2id_walk */
		MDB_val data;
385

386
387
		if ( isc->numrdns )
			mdb_dn2id_wrestore( op, isc );
388

Howard Chu's avatar
Howard Chu committed
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
		key.mv_data = &ww->key;
		data = ww->data;
		rc = mdb_cursor_get( mcd, &key, &data, MDB_GET_BOTH );
		if ( rc == MDB_NOTFOUND ) {
			data = ww->data;
			rc = mdb_cursor_get( mcd, &key, &data, MDB_GET_BOTH_RANGE );
			/* the loop will skip this node using NEXT_DUP but we want it
			 * sent, so go back one space first
			 */
			if ( rc == MDB_SUCCESS )
				mdb_cursor_get( mcd, &key, &data, MDB_PREV_DUP );
			else
				rc = LDAP_BUSY;
		} else if ( rc ) {
			rc = LDAP_OTHER;
		}
		op->o_tmpfree( ww->data.mv_data, op->o_tmpmemctx );
		ww->data.mv_data = NULL;
407
408
	} else if ( isc->scopes[0].mid > 1 ) {	/* candidate-based search */
		int i;
409
		for ( i=1; i<=isc->scopes[0].mid; i++ ) {
410
411
412
413
414
			if ( !isc->scopes[i].mval.mv_data )
				continue;
			key.mv_data = &isc->scopes[i].mid;
			mdb_cursor_get( mcd, &key, &isc->scopes[i].mval, MDB_SET );
		}
Howard Chu's avatar
Howard Chu committed
415
416
417
418
	}
	return rc;
}

Howard Chu's avatar
Howard Chu committed
419
420
421
422
int
mdb_search( Operation *op, SlapReply *rs )
{
	struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private;
Howard Chu's avatar
Howard Chu committed
423
	ID		id, cursor, nsubs, ncand, cscope;
Howard Chu's avatar
Howard Chu committed
424
425
	ID		lastid = NOID;
	ID		candidates[MDB_IDL_UM_SIZE];
Howard Chu's avatar
Howard Chu committed
426
	ID		iscopes[MDB_IDL_DB_SIZE];
Howard Chu's avatar
Howard Chu committed
427
	ID2		*scopes;
428
	void	*stack;
Howard Chu's avatar
Howard Chu committed
429
	Entry		*e = NULL, *base = NULL;
Howard Chu's avatar
Howard Chu committed
430
431
432
433
434
435
	Entry		*matched = NULL;
	AttributeName	*attrs;
	slap_mask_t	mask;
	time_t		stoptime;
	int		manageDSAit;
	int		tentries = 0;
Howard Chu's avatar
Howard Chu committed
436
	IdScopes	isc;
Howard Chu's avatar
Howard Chu committed
437
	MDB_cursor	*mci, *mcd;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
438
439
	ww_ctx wwctx;
	slap_callback cb = { 0 };
Howard Chu's avatar
Howard Chu committed
440

441
	mdb_op_info	opinfo = {{{0}}}, *moi = &opinfo;
Howard Chu's avatar
Howard Chu committed
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
	MDB_txn			*ltid = NULL;

	Debug( LDAP_DEBUG_TRACE, "=> " LDAP_XSTRING(mdb_search) "\n", 0, 0, 0);
	attrs = op->oq_search.rs_attrs;

	manageDSAit = get_manageDSAit( op );

	rs->sr_err = mdb_opinfo_get( op, mdb, 1, &moi );
	switch(rs->sr_err) {
	case 0:
		break;
	default:
		send_ldap_error( op, rs, LDAP_OTHER, "internal error" );
		return rs->sr_err;
	}

	ltid = moi->moi_txn;

Howard Chu's avatar
Howard Chu committed
460
461
462
	rs->sr_err = mdb_cursor_open( ltid, mdb->mi_id2entry, &mci );
	if ( rs->sr_err ) {
		send_ldap_error( op, rs, LDAP_OTHER, "internal error" );
Howard Chu's avatar
Howard Chu committed
463
		return rs->sr_err;
Howard Chu's avatar
Howard Chu committed
464
465
	}

Howard Chu's avatar
Howard Chu committed
466
467
468
469
470
471
472
	rs->sr_err = mdb_cursor_open( ltid, mdb->mi_dn2id, &mcd );
	if ( rs->sr_err ) {
		mdb_cursor_close( mci );
		send_ldap_error( op, rs, LDAP_OTHER, "internal error" );
		return rs->sr_err;
	}

Howard Chu's avatar
Howard Chu committed
473
	scopes = scope_chunk_get( op );
474
	stack = search_stack( op );
Howard Chu's avatar
Howard Chu committed
475
	isc.mt = ltid;
Howard Chu's avatar
Howard Chu committed
476
	isc.mc = mcd;
Howard Chu's avatar
Howard Chu committed
477
	isc.scopes = scopes;
Howard Chu's avatar
Howard Chu committed
478
	isc.oscope = op->ors_scope;
479
	isc.sctmp = stack;
Howard Chu's avatar
Howard Chu committed
480

Howard Chu's avatar
Howard Chu committed
481
482
483
484
485
	if ( op->ors_deref & LDAP_DEREF_FINDING ) {
		MDB_IDL_ZERO(candidates);
	}
dn2entry_retry:
	/* get entry with reader lock */
Howard Chu's avatar
Howard Chu committed
486
	rs->sr_err = mdb_dn2entry( op, ltid, mcd, &op->o_req_ndn, &e, &nsubs, 1 );
Howard Chu's avatar
Howard Chu committed
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513

	switch(rs->sr_err) {
	case MDB_NOTFOUND:
		matched = e;
		e = NULL;
		break;
	case 0:
		break;
	case LDAP_BUSY:
		send_ldap_error( op, rs, LDAP_BUSY, "ldap server busy" );
		goto done;
	default:
		send_ldap_error( op, rs, LDAP_OTHER, "internal error" );
		goto done;
	}

	if ( op->ors_deref & LDAP_DEREF_FINDING ) {
		if ( matched && is_entry_alias( matched )) {
			struct berval stub;

			stub.bv_val = op->o_req_ndn.bv_val;
			stub.bv_len = op->o_req_ndn.bv_len - matched->e_nname.bv_len - 1;
			e = deref_base( op, rs, matched, &matched, ltid,
				candidates, NULL );
			if ( e ) {
				build_new_dn( &op->o_req_ndn, &e->e_nname, &stub,
					op->o_tmpmemctx );
Howard Chu's avatar
Howard Chu committed
514
				mdb_entry_return(op, e);
Howard Chu's avatar
Howard Chu committed
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
				matched = NULL;
				goto dn2entry_retry;
			}
		} else if ( e && is_entry_alias( e )) {
			e = deref_base( op, rs, e, &matched, ltid,
				candidates, NULL );
		}
	}

	if ( e == NULL ) {
		struct berval matched_dn = BER_BVNULL;

		if ( matched != NULL ) {
			BerVarray erefs = NULL;

			/* return referral only if "disclose"
			 * is granted on the object */
			if ( ! access_allowed( op, matched,
						slap_schema.si_ad_entry,
						NULL, ACL_DISCLOSE, NULL ) )
			{
				rs->sr_err = LDAP_NO_SUCH_OBJECT;

			} else {
				ber_dupbv( &matched_dn, &matched->e_name );

				erefs = is_entry_referral( matched )
					? get_entry_referrals( op, matched )
					: NULL;
				if ( rs->sr_err == MDB_NOTFOUND )
					rs->sr_err = LDAP_REFERRAL;
				rs->sr_matched = matched_dn.bv_val;
			}

Howard Chu's avatar
Howard Chu committed
549
			mdb_entry_return(op, matched);
Howard Chu's avatar
Howard Chu committed
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
			matched = NULL;

			if ( erefs ) {
				rs->sr_ref = referral_rewrite( erefs, &matched_dn,
					&op->o_req_dn, op->oq_search.rs_scope );
				ber_bvarray_free( erefs );
			}

		} else {
			rs->sr_ref = referral_rewrite( default_referral,
				NULL, &op->o_req_dn, op->oq_search.rs_scope );
			rs->sr_err = rs->sr_ref != NULL ? LDAP_REFERRAL : LDAP_NO_SUCH_OBJECT;
		}

		send_ldap_result( op, rs );

		if ( rs->sr_ref ) {
			ber_bvarray_free( rs->sr_ref );
			rs->sr_ref = NULL;
		}
		if ( !BER_BVISNULL( &matched_dn ) ) {
			ber_memfree( matched_dn.bv_val );
			rs->sr_matched = NULL;
		}
		goto done;
	}

	/* NOTE: __NEW__ "search" access is required
	 * on searchBase object */
	if ( ! access_allowed_mask( op, e, slap_schema.si_ad_entry,
				NULL, ACL_SEARCH, NULL, &mask ) )
	{
		if ( !ACL_GRANT( mask, ACL_DISCLOSE ) ) {
			rs->sr_err = LDAP_NO_SUCH_OBJECT;
		} else {
			rs->sr_err = LDAP_INSUFFICIENT_ACCESS;
		}

Howard Chu's avatar
Howard Chu committed
588
		mdb_entry_return( op,e);
Howard Chu's avatar
Howard Chu committed
589
590
591
592
593
594
595
596
597
598
599
600
601
602
		send_ldap_result( op, rs );
		goto done;
	}

	if ( !manageDSAit && is_entry_referral( e ) ) {
		/* entry is a referral */
		struct berval matched_dn = BER_BVNULL;
		BerVarray erefs = NULL;
		
		ber_dupbv( &matched_dn, &e->e_name );
		erefs = get_entry_referrals( op, e );

		rs->sr_err = LDAP_REFERRAL;

Howard Chu's avatar
Howard Chu committed
603
		mdb_entry_return( op, e );
Howard Chu's avatar
Howard Chu committed
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
		e = NULL;

		if ( erefs ) {
			rs->sr_ref = referral_rewrite( erefs, &matched_dn,
				&op->o_req_dn, op->oq_search.rs_scope );
			ber_bvarray_free( erefs );

			if ( !rs->sr_ref ) {
				rs->sr_text = "bad_referral object";
			}
		}

		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(mdb_search) ": entry is referral\n",
			0, 0, 0 );

		rs->sr_matched = matched_dn.bv_val;
		send_ldap_result( op, rs );

		ber_bvarray_free( rs->sr_ref );
		rs->sr_ref = NULL;
		ber_memfree( matched_dn.bv_val );
		rs->sr_matched = NULL;
		goto done;
	}

	if ( get_assert( op ) &&
		( test_filter( op, e, get_assertion( op )) != LDAP_COMPARE_TRUE ))
	{
		rs->sr_err = LDAP_ASSERTION_FAILED;
Howard Chu's avatar
Howard Chu committed
634
		mdb_entry_return( op,e);
Howard Chu's avatar
Howard Chu committed
635
636
637
638
639
640
641
		send_ldap_result( op, rs );
		goto done;
	}

	/* compute it anyway; root does not use it */
	stoptime = op->o_time + op->ors_tlimit;

Howard Chu's avatar
Howard Chu committed
642
	base = e;
Howard Chu's avatar
Howard Chu committed
643
644
645
646
647

	e = NULL;

	/* select candidates */
	if ( op->oq_search.rs_scope == LDAP_SCOPE_BASE ) {
Howard Chu's avatar
Howard Chu committed
648
		rs->sr_err = base_candidate( op->o_bd, base, candidates );
649
		scopes[0].mid = 0;
Howard Chu's avatar
Howard Chu committed
650
		ncand = 1;
Howard Chu's avatar
Howard Chu committed
651
	} else {
Howard Chu's avatar
Howard Chu committed
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
		if ( op->ors_scope == LDAP_SCOPE_ONELEVEL ) {
			size_t nkids;
			MDB_val key, data;
			key.mv_data = &base->e_id;
			key.mv_size = sizeof( ID );
			mdb_cursor_get( mcd, &key, &data, MDB_SET );
			mdb_cursor_count( mcd, &nkids );
			nsubs = nkids - 1;
		} else if ( !base->e_id ) {
			/* we don't maintain nsubs for entryID 0.
			 * just grab entry count from id2entry stat
			 */
			MDB_stat ms;
			mdb_stat( ltid, mdb->mi_id2entry, &ms );
			nsubs = ms.ms_entries;
		}
Howard Chu's avatar
Howard Chu committed
668
		MDB_IDL_ZERO( candidates );
Howard Chu's avatar
Howard Chu committed
669
670
671
		scopes[0].mid = 1;
		scopes[1].mid = base->e_id;
		scopes[1].mval.mv_data = NULL;
Howard Chu's avatar
Howard Chu committed
672
		rs->sr_err = search_candidates( op, rs, base,
Howard Chu's avatar
Howard Chu committed
673
			&isc, mci, candidates, stack );
Howard Chu's avatar
Howard Chu committed
674
675
676
677

		if ( rs->sr_err == LDAP_ADMINLIMIT_EXCEEDED )
			goto adminlimit;

Howard Chu's avatar
Howard Chu committed
678
679
680
681
682
683
684
685
686
687
688
		ncand = MDB_IDL_N( candidates );
		if ( !base->e_id || ncand == NOID ) {
			/* grab entry count from id2entry stat
			 */
			MDB_stat ms;
			mdb_stat( ltid, mdb->mi_id2entry, &ms );
			if ( !base->e_id )
				nsubs = ms.ms_entries;
			if ( ncand == NOID )
				ncand = ms.ms_entries;
		}
Howard Chu's avatar
Howard Chu committed
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
	}

	/* start cursor at beginning of candidates.
	 */
	cursor = 0;

	if ( candidates[0] == 0 ) {
		Debug( LDAP_DEBUG_TRACE,
			LDAP_XSTRING(mdb_search) ": no candidates\n",
			0, 0, 0 );

		goto nochange;
	}

	/* if not root and candidates exceed to-be-checked entries, abort */
	if ( op->ors_limit	/* isroot == FALSE */ &&
		op->ors_limit->lms_s_unchecked != -1 &&
Howard Chu's avatar
Howard Chu committed
706
		ncand > (unsigned) op->ors_limit->lms_s_unchecked )
Howard Chu's avatar
Howard Chu committed
707
708
	{
		rs->sr_err = LDAP_ADMINLIMIT_EXCEEDED;
Howard Chu's avatar
Howard Chu committed
709
adminlimit:
Howard Chu's avatar
Howard Chu committed
710
711
712
713
714
715
716
717
		send_ldap_result( op, rs );
		rs->sr_err = LDAP_SUCCESS;
		goto done;
	}

	if ( op->ors_limit == NULL	/* isroot == TRUE */ ||
		!op->ors_limit->lms_s_pr_hide )
	{
Howard Chu's avatar
Howard Chu committed
718
		tentries = ncand;
Howard Chu's avatar
Howard Chu committed
719
720
	}

Howard Chu's avatar
Howard Chu committed
721
	wwctx.flag = 0;
Howard Chu's avatar
Howard Chu committed
722
	wwctx.nentries = 0;
Howard Chu's avatar
Howard Chu committed
723
724
725
726
727
728
729
730
731
732
	/* If we're running in our own read txn */
	if (  moi == &opinfo ) {
		cb.sc_writewait = mdb_writewait;
		cb.sc_private = &wwctx;
		wwctx.txn = ltid;
		wwctx.mcd = NULL;
		cb.sc_next = op->o_callback;
		op->o_callback = &cb;
	}

Howard Chu's avatar
Howard Chu committed
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
	if ( get_pagedresults( op ) > SLAP_CONTROL_IGNORED ) {
		PagedResultsState *ps = op->o_pagedresults_state;
		/* deferred cookie parsing */
		rs->sr_err = parse_paged_cookie( op, rs );
		if ( rs->sr_err != LDAP_SUCCESS ) {
			send_ldap_result( op, rs );
			goto done;
		}

		cursor = (ID) ps->ps_cookie;
		if ( cursor && ps->ps_size == 0 ) {
			rs->sr_err = LDAP_SUCCESS;
			rs->sr_text = "search abandoned by pagedResult size=0";
			send_ldap_result( op, rs );
			goto done;
		}
		id = mdb_idl_first( candidates, &cursor );
		if ( id == NOID ) {
			Debug( LDAP_DEBUG_TRACE, 
				LDAP_XSTRING(mdb_search)
				": no paged results candidates\n",
				0, 0, 0 );
			send_paged_response( op, rs, &lastid, 0 );

			rs->sr_err = LDAP_OTHER;
			goto done;
		}
		if ( id == (ID)ps->ps_cookie )
			id = mdb_idl_next( candidates, &cursor );
762
		nsubs = ncand;	/* always bypass scope'd search */
Howard Chu's avatar
Howard Chu committed
763
764
		goto loop_begin;
	}
Howard Chu's avatar
Howard Chu committed
765
766
767
	if ( nsubs < ncand ) {
		int rc;
		/* Do scope-based search */
Howard Chu's avatar
Howard Chu committed
768
769
770
771
772

		/* if any alias scopes were set, save them */
		if (scopes[0].mid > 1) {
			cursor = 1;
			for (cscope = 1; cscope <= scopes[0].mid; cscope++) {
773
774
775
				/* Ignore the original base */
				if (scopes[cscope].mid == base->e_id)
					continue;
Howard Chu's avatar
Howard Chu committed
776
777
				iscopes[cursor++] = scopes[cscope].mid;
			}
778
			iscopes[0] = scopes[0].mid - 1;
Howard Chu's avatar
Howard Chu committed
779
780
		} else {
			iscopes[0] = 0;
Howard Chu's avatar
Howard Chu committed
781
782
		}

Howard Chu's avatar
Howard Chu committed
783
		wwctx.mcd = mcd;
Howard Chu's avatar
Howard Chu committed
784
785
786
787
788
789
790
		isc.id = base->e_id;
		isc.numrdns = 0;
		rc = mdb_dn2id_walk( op, &isc );
		if ( rc )
			id = NOID;
		else
			id = isc.id;
791
		cscope = 0;
Howard Chu's avatar
Howard Chu committed
792
793
	} else {
		id = mdb_idl_first( candidates, &cursor );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
794
795
	}

Howard Chu's avatar
Howard Chu committed
796
	while (id != NOID)
Howard Chu's avatar
Howard Chu committed
797
798
	{
		int scopeok;
799
		MDB_val edata;
Howard Chu's avatar
Howard Chu committed
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830

loop_begin:

		/* check for abandon */
		if ( op->o_abandon ) {
			rs->sr_err = SLAPD_ABANDON;
			send_ldap_result( op, rs );
			goto done;
		}

		/* mostly needed by internal searches,
		 * e.g. related to syncrepl, for whom
		 * abandon does not get set... */
		if ( slapd_shutdown ) {
			rs->sr_err = LDAP_UNAVAILABLE;
			send_ldap_disconnect( op, rs );
			goto done;
		}

		/* check time limit */
		if ( op->ors_tlimit != SLAP_NO_LIMIT
				&& slap_get_time() > stoptime )
		{
			rs->sr_err = LDAP_TIMELIMIT_EXCEEDED;
			rs->sr_ref = rs->sr_v2ref;
			send_ldap_result( op, rs );
			rs->sr_err = LDAP_SUCCESS;
			goto done;
		}


Howard Chu's avatar
Howard Chu committed
831
832
833
834
835
836
837
838
839
840
		if ( nsubs < ncand ) {
			unsigned i;
			/* Is this entry in the candidate list? */
			scopeok = 0;
			if (MDB_IDL_IS_RANGE( candidates )) {
				if ( id >= MDB_IDL_RANGE_FIRST( candidates ) &&
					id <= MDB_IDL_RANGE_LAST( candidates ))
					scopeok = 1;
			} else {
				i = mdb_idl_search( candidates, id );
841
				if (i <= candidates[0] && candidates[i] == id )
Howard Chu's avatar
Howard Chu committed
842
843
844
845
846
847
848
					scopeok = 1;
			}
			if ( scopeok )
				goto scopeok;
			goto loop_continue;
		}

Howard Chu's avatar
Howard Chu committed
849
850
851
		/* Does this candidate actually satisfy the search scope?
		 */
		scopeok = 0;
Howard Chu's avatar
Howard Chu committed
852
		isc.numrdns = 0;
Howard Chu's avatar
Howard Chu committed
853
854
855
		switch( op->ors_scope ) {
		case LDAP_SCOPE_BASE:
			/* This is always true, yes? */
Howard Chu's avatar
Howard Chu committed
856
			if ( id == base->e_id ) scopeok = 1;
Howard Chu's avatar
Howard Chu committed
857
858
859
860
			break;

#ifdef LDAP_SCOPE_CHILDREN
		case LDAP_SCOPE_CHILDREN:
Howard Chu's avatar
Howard Chu committed
861
			if ( id == base->e_id ) break;
Howard Chu's avatar
Howard Chu committed
862
863
864
			/* Fall-thru */
#endif
		case LDAP_SCOPE_SUBTREE:
Howard Chu's avatar
Howard Chu committed
865
			if ( id == base->e_id ) {
Howard Chu's avatar
Howard Chu committed
866
867
868
869
870
				scopeok = 1;
				break;
			}
			/* Fall-thru */
		case LDAP_SCOPE_ONELEVEL:
Howard Chu's avatar
Howard Chu committed
871
			if ( id == base->e_id ) break;
Howard Chu's avatar
Howard Chu committed
872
			isc.id = id;
873
874
875
876
877
878
879
880
881
			isc.nscope = 0;
			rs->sr_err = mdb_idscopes( op, &isc );
			if ( rs->sr_err == MDB_SUCCESS ) {
				if ( isc.nscope )
					scopeok = 1;
			} else {
				if ( rs->sr_err == MDB_NOTFOUND )
					goto notfound;
			}
Howard Chu's avatar
Howard Chu committed
882
883
884
			break;
		}

885
886
887
888
889
890
891
892
893
894
		/* Not in scope, ignore it */
		if ( !scopeok )
		{
			Debug( LDAP_DEBUG_TRACE,
				LDAP_XSTRING(mdb_search)
				": %ld scope not okay\n",
				(long) id, 0, 0 );
			goto loop_continue;
		}

Howard Chu's avatar
Howard Chu committed
895
scopeok:
896
897
898
899
900
901
902
903
		if ( id == base->e_id ) {
			e = base;
		} else {

			/* get the entry */
			rs->sr_err = mdb_id2edata( op, mci, id, &edata );
			if ( rs->sr_err == MDB_NOTFOUND ) {
notfound:
Howard Chu's avatar
Howard Chu committed
904
905
906
				if( nsubs < ncand )
					goto loop_continue;

907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
				if( !MDB_IDL_IS_RANGE(candidates) ) {
					/* only complain for non-range IDLs */
					Debug( LDAP_DEBUG_TRACE,
						LDAP_XSTRING(mdb_search)
						": candidate %ld not found\n",
						(long) id, 0, 0 );
				} else {
					/* get the next ID from the DB */
					rs->sr_err = mdb_get_nextid( mci, &cursor );
					if ( rs->sr_err == MDB_NOTFOUND ) {
						break;
					}
					if ( rs->sr_err ) {
						rs->sr_err = LDAP_OTHER;
						rs->sr_text = "internal error in get_nextid";
						send_ldap_result( op, rs );
						goto done;
					}
					cursor--;
				}

				goto loop_continue;
			} else if ( rs->sr_err ) {
				rs->sr_err = LDAP_OTHER;
				rs->sr_text = "internal error in mdb_id2edata";
				send_ldap_result( op, rs );
				goto done;
			}

Howard Chu's avatar
Howard Chu committed
936
			rs->sr_err = mdb_entry_decode( op, ltid, &edata, &e );
937
938
			if ( rs->sr_err ) {
				rs->sr_err = LDAP_OTHER;
Howard Chu's avatar
Howard Chu committed
939
				rs->sr_text = "internal error in mdb_entry_decode";
940
941
942
				send_ldap_result( op, rs );
				goto done;
			}
Howard Chu's avatar
Howard Chu committed
943
944
945
			e->e_id = id;
			e->e_name.bv_val = NULL;
			e->e_nname.bv_val = NULL;
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
		}

		if ( is_entry_subentry( e ) ) {
			if( op->oq_search.rs_scope != LDAP_SCOPE_BASE ) {
				if(!get_subentries_visibility( op )) {
					/* only subentries are visible */
					goto loop_continue;
				}

			} else if ( get_subentries( op ) &&
				!get_subentries_visibility( op ))
			{
				/* only subentries are visible */
				goto loop_continue;
			}

		} else if ( get_subentries_visibility( op )) {
			/* only subentries are visible */
			goto loop_continue;
		}

Howard Chu's avatar
Howard Chu committed
967
968
969
970
971
972
		/* aliases were already dereferenced in candidate list */
		if ( op->ors_deref & LDAP_DEREF_SEARCHING ) {
			/* but if the search base is an alias, and we didn't
			 * deref it when finding, return it.
			 */
			if ( is_entry_alias(e) &&
Howard Chu's avatar
Howard Chu committed
973
				((op->ors_deref & LDAP_DEREF_FINDING) || e != base ))
Howard Chu's avatar
Howard Chu committed
974
975
976
977
978
979
980
981
982
			{
				goto loop_continue;
			}
		}

		if ( !manageDSAit && is_entry_glue( e )) {
			goto loop_continue;
		}

Howard Chu's avatar
Howard Chu committed
983
984
985
986
		if (e != base) {
			struct berval pdn, pndn;
			char *d, *n;
			int i;
Howard Chu's avatar
Howard Chu committed
987

Howard Chu's avatar
Howard Chu committed
988
			/* child of base, just append RDNs to base->e_name */
Howard Chu's avatar
Howard Chu committed
989
			if ( nsubs < ncand || isc.scopes[isc.nscope].mid == base->e_id ) {
Howard Chu's avatar
Howard Chu committed
990
991
992
				pdn = base->e_name;
				pndn = base->e_nname;
			} else {
993
				mdb_id2name( op, ltid, &isc.mc, scopes[isc.nscope].mid, &pdn, &pndn );
Howard Chu's avatar
Howard Chu committed
994
995
996
997
998
999
1000
			}
			e->e_name.bv_len = pdn.bv_len;
			e->e_nname.bv_len = pndn.bv_len;
			for (i=0; i<isc.numrdns; i++) {
				e->e_name.bv_len += isc.rdns[i].bv_len + 1;
				e->e_nname.bv_len += isc.nrdns[i].bv_len + 1;
			}
For faster browsing, not all history is shown. View entire blame