search.c 55.6 KB
Newer Older
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1
2
3
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 *
4
 * Copyright 1999-2009 The OpenLDAP Foundation.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
5
6
 * Portions Copyright 2001-2003 Pierangelo Masarati.
 * Portions Copyright 1999-2003 Howard Chu.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
7
 * All rights reserved.
Pierangelo Masarati's avatar
Pierangelo Masarati committed
8
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
9
10
11
12
13
14
15
16
17
18
19
20
21
 * 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>.
 */
/* ACKNOWLEDGEMENTS:
 * This work was initially developed by the Howard Chu for inclusion
 * in OpenLDAP Software and subsequently enhanced by Pierangelo
 * Masarati.
 */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
22
23
24
25
26
27
28
29
30

#include "portable.h"

#include <stdio.h>

#include <ac/socket.h>
#include <ac/string.h>
#include <ac/time.h>

31
#include "lutil.h"
Pierangelo Masarati's avatar
Pierangelo Masarati committed
32
33
34
#include "slap.h"
#include "../back-ldap/back-ldap.h"
#include "back-meta.h"
35
#undef ldap_debug	/* silence a warning in ldap-int.h */
Julius Enarusai's avatar
   
Julius Enarusai committed
36
#include "ldap_log.h"
37
#include "../../../libraries/libldap/ldap-int.h"
Pierangelo Masarati's avatar
Pierangelo Masarati committed
38

39
40
41
42
43
/* IGNORE means that target does not (no longer) participate
 * in the search;
 * NOTREADY means the search on that target has not been initialized yet
 */
#define	META_MSGID_IGNORE	(-1)
44
#define	META_MSGID_NEED_BIND	(-2)
45
#define	META_MSGID_CONNECTING	(-3)
46

47
static int
Pierangelo Masarati's avatar
Pierangelo Masarati committed
48
meta_send_entry(
49
50
	Operation 	*op,
	SlapReply	*rs,
51
	metaconn_t	*mc,
52
53
54
	int 		i,
	LDAPMessage 	*e );

55
typedef enum meta_search_candidate_t {
56
	META_SEARCH_UNDEFINED = -2,
57
58
	META_SEARCH_ERR = -1,
	META_SEARCH_NOT_CANDIDATE,
59
60
	META_SEARCH_CANDIDATE,
	META_SEARCH_BINDING,
61
62
	META_SEARCH_NEED_BIND,
	META_SEARCH_CONNECTING
63
64
} meta_search_candidate_t;

65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
/*
 * meta_search_dobind_init()
 *
 * initiates bind for a candidate target of a search.
 */
static meta_search_candidate_t
meta_search_dobind_init(
	Operation		*op,
	SlapReply		*rs,
	metaconn_t		**mcp,
	int			candidate,
	SlapReply		*candidates )
{
	metaconn_t		*mc = *mcp;
	metainfo_t		*mi = ( metainfo_t * )op->o_bd->be_private;
80
	metatarget_t		*mt = mi->mi_targets[ candidate ];
81
82
	metasingleconn_t	*msc = &mc->mc_conns[ candidate ];

83
84
	struct berval		binddn = msc->msc_bound_ndn,
				cred = msc->msc_cred;
85
	int			method;
86
87
88
89
90

	int			rc;

	meta_search_candidate_t	retcode;

Pierangelo Masarati's avatar
Pierangelo Masarati committed
91
92
	Debug( LDAP_DEBUG_TRACE, "%s >>> meta_search_dobind_init[%d]\n",
		op->o_log_prefix, candidate, 0 );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
93

94
95
96
97
98
99
100
	/*
	 * all the targets are already bound as pseudoroot
	 */
	if ( mc->mc_authz_target == META_BOUND_ALL ) {
		return META_SEARCH_CANDIDATE;
	}

101
	retcode = META_SEARCH_BINDING;
102
103
	ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
	if ( LDAP_BACK_CONN_ISBOUND( msc ) || LDAP_BACK_CONN_ISANON( msc ) ) {
104
		/* already bound (or anonymous) */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
105
106
107
108
109
110
111
112
113

#ifdef DEBUG_205
		char	buf[ SLAP_TEXT_BUFLEN ] = { '\0' };
		int	bound = 0;

		if ( LDAP_BACK_CONN_ISBOUND( msc ) ) {
			bound = 1;
		}

114
		snprintf( buf, sizeof( buf ), " mc=%p ld=%p%s DN=\"%s\"",
Pierangelo Masarati's avatar
Pierangelo Masarati committed
115
116
117
118
119
120
121
			(void *)mc, (void *)msc->msc_ld,
			bound ? " bound" : " anonymous",
			bound == 0 ? "" : msc->msc_bound_ndn.bv_val );
		Debug( LDAP_DEBUG_ANY, "### %s meta_search_dobind_init[%d]%s\n",
			op->o_log_prefix, candidate, buf );
#endif /* DEBUG_205 */

122
		retcode = META_SEARCH_CANDIDATE;
123

124
	} else if ( META_BACK_CONN_CREATING( msc ) || LDAP_BACK_CONN_BINDING( msc ) ) {
125
		/* another thread is binding the target for this conn; wait */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
126
127
128
129

#ifdef DEBUG_205
		char	buf[ SLAP_TEXT_BUFLEN ] = { '\0' };

130
		snprintf( buf, sizeof( buf ), " mc=%p ld=%p needbind",
Pierangelo Masarati's avatar
Pierangelo Masarati committed
131
132
133
134
135
			(void *)mc, (void *)msc->msc_ld );
		Debug( LDAP_DEBUG_ANY, "### %s meta_search_dobind_init[%d]%s\n",
			op->o_log_prefix, candidate, buf );
#endif /* DEBUG_205 */

136
		candidates[ candidate ].sr_msgid = META_MSGID_NEED_BIND;
137
		retcode = META_SEARCH_NEED_BIND;
138

139
140
	} else {
		/* we'll need to bind the target for this conn */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
141
142
143
144
145
146
147
148
149
150

#ifdef DEBUG_205
		char buf[ SLAP_TEXT_BUFLEN ];

		snprintf( buf, sizeof( buf ), " mc=%p ld=%p binding",
			(void *)mc, (void *)msc->msc_ld );
		Debug( LDAP_DEBUG_ANY, "### %s meta_search_dobind_init[%d]%s\n",
			op->o_log_prefix, candidate, buf );
#endif /* DEBUG_205 */

151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
		if ( msc->msc_ld == NULL ) {
			/* for some reason (e.g. because formerly in "binding"
			 * state, with eventual connection expiration or invalidation)
			 * it was not initialized as expected */

			Debug( LDAP_DEBUG_ANY, "%s meta_search_dobind_init[%d] mc=%p ld=NULL\n",
				op->o_log_prefix, candidate, (void *)mc );

			rc = meta_back_init_one_conn( op, rs, *mcp, candidate,
				LDAP_BACK_CONN_ISPRIV( *mcp ), LDAP_BACK_DONTSEND, 0 );
			switch ( rc ) {
			case LDAP_SUCCESS:
				assert( msc->msc_ld != NULL );
				break;

			case LDAP_SERVER_DOWN:
			case LDAP_UNAVAILABLE:
				ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
				goto down;
	
			default:
				ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
				goto other;
			}
		}

177
178
		LDAP_BACK_CONN_BINDING_SET( msc );
	}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
179

180
	ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
181

182
183
184
	if ( retcode != META_SEARCH_BINDING ) {
		return retcode;
	}
185

186
187
188
189
190
191
192
193
194
195
196
	/* NOTE: this obsoletes pseudorootdn */
	if ( op->o_conn != NULL &&
		!op->o_do_not_cache &&
		( BER_BVISNULL( &msc->msc_bound_ndn ) ||
			BER_BVISEMPTY( &msc->msc_bound_ndn ) ||
			( mt->mt_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) ) )
	{
		rc = meta_back_proxy_authz_cred( mc, candidate, op, rs, LDAP_BACK_DONTSEND, &binddn, &cred, &method );
		if ( rc != LDAP_SUCCESS ) {
			goto down;
		}
197

198
199
200
201
202
		/* NOTE: we copy things here, even if bind didn't succeed yet,
		 * because the connection is not shared until bind is over */
		if ( !BER_BVISNULL( &binddn ) ) {
			ber_bvreplace( &msc->msc_bound_ndn, &binddn );
			if ( LDAP_BACK_SAVECRED( mi ) && !BER_BVISNULL( &cred ) ) {
203
204
205
206
207
				if ( !BER_BVISNULL( &msc->msc_cred ) ) {
					memset( msc->msc_cred.bv_val, 0,
						msc->msc_cred.bv_len );
				}
				ber_bvreplace( &msc->msc_cred, &cred );
208
209
210
211
			}
		}

		if ( LDAP_BACK_CONN_ISBOUND( msc ) ) {
212
213
			/* apparently, idassert was configured with SASL bind,
			 * so bind occurred inside meta_back_proxy_authz_cred() */
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
			ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
			LDAP_BACK_CONN_BINDING_CLEAR( msc );
			ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
			return META_SEARCH_CANDIDATE;
		}

		/* paranoid */
		switch ( method ) {
		case LDAP_AUTH_NONE:
		case LDAP_AUTH_SIMPLE:
			/* do a simple bind with binddn, cred */
			break;

		default:
			assert( 0 );
			break;
		}
231
232
	}

233
234
	assert( msc->msc_ld != NULL );

235
	/* connect must be async only the first time... */
236
237
	ldap_set_option( msc->msc_ld, LDAP_OPT_CONNECT_ASYNC, LDAP_OPT_ON );

238
retry:;
239
	rc = ldap_sasl_bind( msc->msc_ld, binddn.bv_val, LDAP_SASL_SIMPLE, &cred,
240
			NULL, NULL, &candidates[ candidate ].sr_msgid );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
241
242
243
244
245
246
247
248
249
250
251
252

#ifdef DEBUG_205
	{
		char buf[ SLAP_TEXT_BUFLEN ];

		snprintf( buf, sizeof( buf ), "meta_search_dobind_init[%d] mc=%p ld=%p rc=%d",
			candidate, (void *)mc, (void *)mc->mc_conns[ candidate ].msc_ld, rc );
		Debug( LDAP_DEBUG_ANY, "### %s %s\n",
			op->o_log_prefix, buf, 0 );
	}
#endif /* DEBUG_205 */

253
254
	switch ( rc ) {
	case LDAP_SUCCESS:
255
		assert( candidates[ candidate ].sr_msgid >= 0 );
256
		META_BINDING_SET( &candidates[ candidate ] );
257
258
		return META_SEARCH_BINDING;

259
260
	case LDAP_X_CONNECTING:
		/* must retry, same conn */
261
		candidates[ candidate ].sr_msgid = META_MSGID_CONNECTING;
262
263
264
		ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
		LDAP_BACK_CONN_BINDING_CLEAR( msc );
		ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
265
		return META_SEARCH_CONNECTING;
266

267
	case LDAP_SERVER_DOWN:
268
down:;
269
270
		/* This is the worst thing that could happen:
		 * the search will wait until the retry is over. */
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
		if ( !META_IS_RETRYING( &candidates[ candidate ] ) ) {
			META_RETRYING_SET( &candidates[ candidate ] );

			ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );

			assert( mc->mc_refcnt > 0 );
			if ( LogTest( LDAP_DEBUG_ANY ) ) {
				char	buf[ SLAP_TEXT_BUFLEN ];

				/* this lock is required; however,
				 * it's invoked only when logging is on */
				ldap_pvt_thread_mutex_lock( &mt->mt_uri_mutex );
				snprintf( buf, sizeof( buf ),
					"retrying URI=\"%s\" DN=\"%s\"",
					mt->mt_uri,
					BER_BVISNULL( &msc->msc_bound_ndn ) ?
						"" : msc->msc_bound_ndn.bv_val );
				ldap_pvt_thread_mutex_unlock( &mt->mt_uri_mutex );

				Debug( LDAP_DEBUG_ANY,
					"%s meta_search_dobind_init[%d]: %s.\n",
					op->o_log_prefix, candidate, buf );
			}

			meta_clear_one_candidate( op, mc, candidate );
			LDAP_BACK_CONN_ISBOUND_CLEAR( msc );

			( void )rewrite_session_delete( mt->mt_rwmap.rwm_rw, op->o_conn );

			/* mc here must be the regular mc, reset and ready for init */
			rc = meta_back_init_one_conn( op, rs, mc, candidate,
				LDAP_BACK_CONN_ISPRIV( mc ), LDAP_BACK_DONTSEND, 0 );

304
305
306
307
			if ( rc == LDAP_SUCCESS ) {
				LDAP_BACK_CONN_BINDING_SET( msc );
			}

308
309
			ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );

310
311
312
313
			if ( rc == LDAP_SUCCESS ) {
				candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
				goto retry;
			}
314
315
316
317
318
		}

		if ( *mcp == NULL ) {
			retcode = META_SEARCH_ERR;
			rs->sr_err = LDAP_UNAVAILABLE;
319
			candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
320
321
322
323
324
			break;
		}
		/* fall thru */

	default:
325
other:;
326
327
328
329
		rs->sr_err = rc;
		rc = slap_map_api2result( rs );

		ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
330
		meta_clear_one_candidate( op, mc, candidate );
331
		candidates[ candidate ].sr_err = rc;
332
333
		if ( META_BACK_ONERR_STOP( mi ) ) {
			LDAP_BACK_CONN_TAINTED_SET( mc );
334
			meta_back_release_conn_lock( mi, mc, 0 );
335
			*mcp = NULL;
336
			rs->sr_err = rc;
337
338
339
340
341
342

			retcode = META_SEARCH_ERR;

		} else {
			retcode = META_SEARCH_NOT_CANDIDATE;
		}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
343
		candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
		ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
		break;
	}

	return retcode;
}

static meta_search_candidate_t
meta_search_dobind_result(
	Operation		*op,
	SlapReply		*rs,
	metaconn_t		**mcp,
	int			candidate,
	SlapReply		*candidates,
	LDAPMessage		*res )
{
	metainfo_t		*mi = ( metainfo_t * )op->o_bd->be_private;
	metaconn_t		*mc = *mcp;
	metasingleconn_t	*msc = &mc->mc_conns[ candidate ];

	meta_search_candidate_t	retcode = META_SEARCH_NOT_CANDIDATE;
	int			rc;

Pierangelo Masarati's avatar
Pierangelo Masarati committed
367
368
	assert( msc->msc_ld != NULL );

369
	/* FIXME: matched? referrals? response controls? */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
370
	rc = ldap_parse_result( msc->msc_ld, res,
371
		&candidates[ candidate ].sr_err,
372
		NULL, NULL, NULL, NULL, 0 );
373
374
	if ( rc != LDAP_SUCCESS ) {
		candidates[ candidate ].sr_err = rc;
375
376
377

	} else {
		rc = slap_map_api2result( &candidates[ candidate ] );
378
379
380
381
382
	}

	ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
	LDAP_BACK_CONN_BINDING_CLEAR( msc );
	if ( rc != LDAP_SUCCESS ) {
383
384
		meta_clear_one_candidate( op, mc, candidate );
		candidates[ candidate ].sr_err = rc;
385
386
		if ( META_BACK_ONERR_STOP( mi ) ) {
	        	LDAP_BACK_CONN_TAINTED_SET( mc );
387
			meta_back_release_conn_lock( mi, mc, 0 );
388
389
			*mcp = NULL;
			retcode = META_SEARCH_ERR;
390
			rs->sr_err = rc;
391
392
393
		}

	} else {
394
		/* FIXME: check if bound as idassert authcDN! */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
395
396
397
		if ( BER_BVISNULL( &msc->msc_bound_ndn )
			|| BER_BVISEMPTY( &msc->msc_bound_ndn ) )
		{
398
			LDAP_BACK_CONN_ISANON_SET( msc );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
399
400
401

		} else {
			LDAP_BACK_CONN_ISBOUND_SET( msc );
402
403
		}
		retcode = META_SEARCH_CANDIDATE;
404
405
406

		/* connect must be async */
		ldap_set_option( msc->msc_ld, LDAP_OPT_CONNECT_ASYNC, LDAP_OPT_OFF );
407
408
	}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
409
	candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
410
411
	META_BINDING_CLEAR( &candidates[ candidate ] );

Pierangelo Masarati's avatar
Pierangelo Masarati committed
412
413
	ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );

414
415
416
	return retcode;
}

417
static meta_search_candidate_t
418
419
420
421
meta_back_search_start(
	Operation		*op,
	SlapReply		*rs,
	dncookie		*dc,
422
	metaconn_t		**mcp,
423
	int			candidate,
424
	SlapReply		*candidates )
425
{
426
	metainfo_t		*mi = ( metainfo_t * )op->o_bd->be_private;
427
	metatarget_t		*mt = mi->mi_targets[ candidate ];
Pierangelo Masarati's avatar
Pierangelo Masarati committed
428
	metasingleconn_t	*msc = &(*mcp)->mc_conns[ candidate ];
429
430
431
432
433
434
	struct berval		realbase = op->o_req_dn;
	int			realscope = op->ors_scope;
	struct berval		mbase = BER_BVNULL; 
	struct berval		mfilter = BER_BVNULL;
	char			**mapped_attrs = NULL;
	int			rc;
435
	meta_search_candidate_t	retcode;
436
437
	struct timeval		tv, *tvp = NULL;
	int			nretries = 1;
438
	LDAPControl		**ctrls = NULL;
439

440
441
442
443
444
445
	/* this should not happen; just in case... */
	if ( msc->msc_ld == NULL ) {
		Debug( LDAP_DEBUG_ANY,
			"%s: meta_back_search_start candidate=%d ld=NULL%s.\n",
			op->o_log_prefix, candidate,
			META_BACK_ONERR_STOP( mi ) ? "" : " (ignored)" );
446
		candidates[ candidate ].sr_err = LDAP_OTHER;
447
448
449
		if ( META_BACK_ONERR_STOP( mi ) ) {
			return META_SEARCH_ERR;
		}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
450
		candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
451
452
453
		return META_SEARCH_NOT_CANDIDATE;
	}

454
455
	Debug( LDAP_DEBUG_TRACE, "%s >>> meta_back_search_start[%d]\n", op->o_log_prefix, candidate, 0 );

456
457
458
	/*
	 * modifies the base according to the scope, if required
	 */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
459
	if ( mt->mt_nsuffix.bv_len > op->o_req_ndn.bv_len ) {
460
461
462
463
464
465
466
467
468
469
		switch ( op->ors_scope ) {
		case LDAP_SCOPE_SUBTREE:
			/*
			 * make the target suffix the new base
			 * FIXME: this is very forgiving, because
			 * "illegal" searchBases may be turned
			 * into the suffix of the target; however,
			 * the requested searchBase already passed
			 * thru the candidate analyzer...
			 */
470
471
472
			if ( dnIsSuffix( &mt->mt_nsuffix, &op->o_req_ndn ) ) {
				realbase = mt->mt_nsuffix;
				if ( mt->mt_scope == LDAP_SCOPE_SUBORDINATE ) {
473
474
					realscope = LDAP_SCOPE_SUBORDINATE;
				}
475
476
477
478
479

			} else {
				/*
				 * this target is no longer candidate
				 */
480
481
				retcode = META_SEARCH_NOT_CANDIDATE;
				goto doreturn;
482
483
484
			}
			break;

485
		case LDAP_SCOPE_SUBORDINATE:
486
487
		case LDAP_SCOPE_ONELEVEL:
		{
488
			struct berval	rdn = mt->mt_nsuffix;
489
490
			rdn.bv_len -= op->o_req_ndn.bv_len + STRLENOF( "," );
			if ( dnIsOneLevelRDN( &rdn )
491
					&& dnIsSuffix( &mt->mt_nsuffix, &op->o_req_ndn ) )
492
493
494
495
496
497
			{
				/*
				 * if there is exactly one level,
				 * make the target suffix the new
				 * base, and make scope "base"
				 */
498
				realbase = mt->mt_nsuffix;
499
				if ( op->ors_scope == LDAP_SCOPE_SUBORDINATE ) {
500
					if ( mt->mt_scope == LDAP_SCOPE_SUBORDINATE ) {
501
502
503
504
						realscope = LDAP_SCOPE_SUBORDINATE;
					} else {
						realscope = LDAP_SCOPE_SUBTREE;
					}
505
				} else {
506
507
					realscope = LDAP_SCOPE_BASE;
				}
508
509
510
511
512
513
514
515
				break;
			} /* else continue with the next case */
		}

		case LDAP_SCOPE_BASE:
			/*
			 * this target is no longer candidate
			 */
516
517
			retcode = META_SEARCH_NOT_CANDIDATE;
			goto doreturn;
518
519
520
		}
	}

521
522
523
524
525
526
	/* initiate dobind */
	retcode = meta_search_dobind_init( op, rs, mcp, candidate, candidates );

	Debug( LDAP_DEBUG_TRACE, "%s <<< meta_search_dobind_init[%d]=%d\n", op->o_log_prefix, candidate, retcode );

	if ( retcode != META_SEARCH_CANDIDATE ) {
527
		goto doreturn;
528
529
	}

530
531
532
	/*
	 * Rewrite the search base, if required
	 */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
533
	dc->target = mt;
534
535
	dc->ctx = "searchBase";
	switch ( ldap_back_dn_massage( dc, &realbase, &mbase ) ) {
536
	case LDAP_SUCCESS:
537
538
		break;

539
	case LDAP_UNWILLING_TO_PERFORM:
540
541
542
		rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
		rs->sr_text = "Operation not allowed";
		send_ldap_result( op, rs );
543
544
		retcode = META_SEARCH_ERR;
		goto doreturn;
545

546
	default:
547
548
549
550

		/*
		 * this target is no longer candidate
		 */
551
552
		retcode = META_SEARCH_NOT_CANDIDATE;
		goto doreturn;
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
	}

	/*
	 * Maps filter
	 */
	rc = ldap_back_filter_map_rewrite( dc, op->ors_filter,
			&mfilter, BACKLDAP_MAP );
	switch ( rc ) {
	case LDAP_SUCCESS:
		break;

	case LDAP_COMPARE_FALSE:
	default:
		/*
		 * this target is no longer candidate
		 */
569
		retcode = META_SEARCH_NOT_CANDIDATE;
570
571
572
573
574
575
		goto done;
	}

	/*
	 * Maps required attributes
	 */
576
	rc = ldap_back_map_attrs( &mt->mt_rwmap.rwm_at,
577
			op->ors_attrs, BACKLDAP_MAP, &mapped_attrs );
578
579
580
581
	if ( rc != LDAP_SUCCESS ) {
		/*
		 * this target is no longer candidate
		 */
582
		retcode = META_SEARCH_NOT_CANDIDATE;
583
584
585
		goto done;
	}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
586
587
588
589
590
591
	if ( op->ors_tlimit != SLAP_NO_LIMIT ) {
		tv.tv_sec = op->ors_tlimit > 0 ? op->ors_tlimit : 1;
		tv.tv_usec = 0;
		tvp = &tv;
	}

592
retry:;
593
	ctrls = op->o_ctrls;
594
	if ( meta_back_controls_add( op, rs, *mcp, candidate, &ctrls )
595
		!= LDAP_SUCCESS )
596
597
598
599
600
601
	{
		candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
		retcode = META_SEARCH_NOT_CANDIDATE;
		goto done;
	}

602
603
604
	/*
	 * Starts the search
	 */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
605
	assert( msc->msc_ld != NULL );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
606
	rc = ldap_pvt_search( msc->msc_ld,
607
608
			mbase.bv_val, realscope, mfilter.bv_val,
			mapped_attrs, op->ors_attrsonly,
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
609
			ctrls, NULL, tvp, op->ors_slimit, op->ors_deref,
610
			&candidates[ candidate ].sr_msgid ); 
611
612
	switch ( rc ) {
	case LDAP_SUCCESS:
613
		retcode = META_SEARCH_CANDIDATE;
614
615
616
617
618
		break;
	
	case LDAP_SERVER_DOWN:
		if ( nretries && meta_back_retry( op, rs, mcp, candidate, LDAP_BACK_DONTSEND ) ) {
			nretries = 0;
619
			/* if the identity changed, there might be need to re-authz */
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
620
			(void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
621
622
623
624
625
			goto retry;
		}

		if ( *mcp == NULL ) {
			retcode = META_SEARCH_ERR;
626
			candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
627
628
629
			break;
		}
		/* fall thru */
630

631
632
	default:
		candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
633
		retcode = META_SEARCH_NOT_CANDIDATE;
634
635
636
	}

done:;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
637
	(void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
638

639
640
641
642
643
644
645
646
647
648
	if ( mapped_attrs ) {
		free( mapped_attrs );
	}
	if ( mfilter.bv_val != op->ors_filterstr.bv_val ) {
		free( mfilter.bv_val );
	}
	if ( mbase.bv_val != realbase.bv_val ) {
		free( mbase.bv_val );
	}

649
650
651
doreturn:;
	Debug( LDAP_DEBUG_TRACE, "%s <<< meta_back_search_start[%d]=%d\n", op->o_log_prefix, candidate, retcode );

652
	return retcode;
653
}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
654
655

int
656
meta_back_search( Operation *op, SlapReply *rs )
Pierangelo Masarati's avatar
Pierangelo Masarati committed
657
{
658
659
	metainfo_t	*mi = ( metainfo_t * )op->o_bd->be_private;
	metaconn_t	*mc;
660
661
	struct timeval	save_tv = { 0, 0 },
			tv;
662
	time_t		stoptime = (time_t)(-1),
663
664
			lastres_time = slap_get_time(),
			timeout = 0;
665
666
	int		rc = 0, sres = LDAP_SUCCESS;
	char		*matched = NULL;
667
	int		last = 0, ncandidates = 0,
668
669
670
			initial_candidates = 0, candidate_match = 0,
			needbind = 0;
	ldap_back_send_t	sendok = LDAP_BACK_SENDERR;
671
	long		i;
672
673
674
	dncookie	dc;
	int		is_ok = 0;
	void		*savepriv;
675
	SlapReply	*candidates = NULL;
676

677
678
679
680
681
682
	/*
	 * controls are set in ldap_back_dobind()
	 * 
	 * FIXME: in case of values return filter, we might want
	 * to map attrs and maybe rewrite value
	 */
683
684
getconn:;
	mc = meta_back_getconn( op, rs, NULL, sendok );
685
	if ( !mc ) {
686
		return rs->sr_err;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
687
688
	}

689
690
691
	dc.conn = op->o_conn;
	dc.rs = rs;

692
	if ( candidates == NULL ) candidates = meta_back_candidates_get( op );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
693
694
695
	/*
	 * Inits searches
	 */
696
	for ( i = 0; i < mi->mi_ntargets; i++ ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
697
698
		/* reset sr_msgid; it is used in most loops
		 * to check if that target is still to be considered */
699
		candidates[ i ].sr_msgid = META_MSGID_IGNORE;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
700

Pierangelo Masarati's avatar
Pierangelo Masarati committed
701
702
703
704
705
706
707
		/* a target is marked as candidate by meta_back_getconn();
		 * if for any reason (an error, it's over or so) it is
		 * no longer active, sr_msgid is set to META_MSGID_IGNORE
		 * but it remains candidate, which means it has been active
		 * at some point during the operation.  This allows to 
		 * use its response code and more to compute the final
		 * response */
708
		if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
709
710
711
			continue;
		}

712
713
714
715
		candidates[ i ].sr_matched = NULL;
		candidates[ i ].sr_text = NULL;
		candidates[ i ].sr_ref = NULL;
		candidates[ i ].sr_ctrls = NULL;
716
717
718
719
720
721
722

		/* get largest timeout among candidates */
		if ( mi->mi_targets[ i ]->mt_timeout[ SLAP_OP_SEARCH ]
			&& mi->mi_targets[ i ]->mt_timeout[ SLAP_OP_SEARCH ] > timeout )
		{
			timeout = mi->mi_targets[ i ]->mt_timeout[ SLAP_OP_SEARCH ];
		}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
723
	}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
724

Pierangelo Masarati's avatar
Pierangelo Masarati committed
725
	for ( i = 0; i < mi->mi_ntargets; i++ ) {
726
		if ( !META_IS_CANDIDATE( &candidates[ i ] )
727
728
729
730
731
			|| candidates[ i ].sr_err != LDAP_SUCCESS )
		{
			continue;
		}

732
		switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates ) )
733
		{
734
		case META_SEARCH_NOT_CANDIDATE:
Pierangelo Masarati's avatar
Pierangelo Masarati committed
735
			candidates[ i ].sr_msgid = META_MSGID_IGNORE;
736
737
			break;

738
739
740
741
		case META_SEARCH_NEED_BIND:
			++needbind;
			/* fallthru */

742
		case META_SEARCH_CONNECTING:
743
		case META_SEARCH_CANDIDATE:
744
		case META_SEARCH_BINDING:
745
			candidates[ i ].sr_type = REP_INTERMEDIATE;
746
747
			++ncandidates;
			break;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
748

749
		case META_SEARCH_ERR:
750
751
752
753
			savepriv = op->o_private;
			op->o_private = (void *)i;
			send_ldap_result( op, rs );
			op->o_private = savepriv;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
754
755
			rc = -1;
			goto finish;
756
757
758
759

		default:
			assert( 0 );
			break;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
760
		}
761
	}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
762

763
	if ( ncandidates > 0 && needbind == ncandidates ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
		/*
		 * give up the second time...
		 *
		 * NOTE: this should not occur the second time, since a fresh
		 * connection has ben created; however, targets may also
		 * need bind because the bind timed out or so.
		 */
		if ( sendok & LDAP_BACK_BINDING ) {
			Debug( LDAP_DEBUG_ANY,
				"%s meta_back_search: unable to initialize conn\n",
				op->o_log_prefix, 0, 0 );
			rs->sr_err = LDAP_UNAVAILABLE;
			rs->sr_text = "unable to initialize connection to remote targets";
			send_ldap_result( op, rs );
			rc = -1;
			goto finish;
		}
781
782
783
784

		/* FIXME: better create a separate connection? */
		sendok |= LDAP_BACK_BINDING;

Pierangelo Masarati's avatar
Pierangelo Masarati committed
785
786
787
788
#ifdef DEBUG_205
		Debug( LDAP_DEBUG_ANY, "*** %s drop mc=%p create new connection\n",
			op->o_log_prefix, (void *)mc, 0 );
#endif /* DEBUG_205 */
789

790
		meta_back_release_conn( mi, mc );
791
792
793
794
795
796
797
798
		mc = NULL;

		needbind = 0;
		ncandidates = 0;

		goto getconn;
	}

799
	initial_candidates = ncandidates;
800

801
	if ( LogTest( LDAP_DEBUG_TRACE ) ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
802
		char	cnd[ SLAP_TEXT_BUFLEN ];
803
		int	c;
804

805
806
807
		for ( c = 0; c < mi->mi_ntargets; c++ ) {
			if ( META_IS_CANDIDATE( &candidates[ c ] ) ) {
				cnd[ c ] = '*';
808
			} else {
809
				cnd[ c ] = ' ';
810
			}
811
		}
812
		cnd[ c ] = '\0';
813

814
		Debug( LDAP_DEBUG_TRACE, "%s meta_back_search: ncandidates=%d "
815
816
			"cnd=\"%s\"\n", op->o_log_prefix, ncandidates, cnd );
	}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
817

818
	if ( initial_candidates == 0 ) {
819
820
821
822
823
824
825
826
827
828
829
830
831
		/* NOTE: here we are not sending any matchedDN;
		 * this is intended, because if the back-meta
		 * is serving this search request, but no valid
		 * candidate could be looked up, it means that
		 * there is a hole in the mapping of the targets
		 * and thus no knowledge of any remote superior
		 * is available */
		Debug( LDAP_DEBUG_ANY, "%s meta_back_search: "
			"base=\"%s\" scope=%d: "
			"no candidate could be selected\n",
			op->o_log_prefix, op->o_req_dn.bv_val,
			op->ors_scope );

832
833
		/* FIXME: we're sending the first error we encounter;
		 * maybe we should pick the worst... */
834
		rc = LDAP_NO_SUCH_OBJECT;
835
		for ( i = 0; i < mi->mi_ntargets; i++ ) {
836
			if ( META_IS_CANDIDATE( &candidates[ i ] )
837
838
839
840
841
842
843
844
845
				&& candidates[ i ].sr_err != LDAP_SUCCESS )
			{
				rc = candidates[ i ].sr_err;
				break;
			}
		}

		send_ldap_error( op, rs, rc, NULL );

846
		goto finish;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
847
848
849
850
851
852
853
	}

	/* We pull apart the ber result, stuff it into a slapd entry, and
	 * let send_search_entry stuff it back into ber format. Slow & ugly,
	 * but this is necessary for version matching, and for ACL processing.
	 */

854
855
856
857
	if ( op->ors_tlimit != SLAP_NO_LIMIT ) {
		stoptime = op->o_time + op->ors_tlimit;
	}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
858
859
	/*
	 * In case there are no candidates, no cycle takes place...
860
	 *
861
	 * FIXME: we might use a queue, to better balance the load 
862
	 * among the candidates
Pierangelo Masarati's avatar
Pierangelo Masarati committed
863
	 */
864
	for ( rc = 0; ncandidates > 0; ) {
865
		int	gotit = 0,
866
867
			doabandon = 0,
			alreadybound = ncandidates;
868
869

		/* check timeout */
870
871
		if ( timeout && lastres_time > 0
			&& ( slap_get_time() - lastres_time ) > timeout )
872
873
874
		{
			doabandon = 1;
			rs->sr_text = "Operation timed out";
875
876
			rc = rs->sr_err = op->o_protocol >= LDAP_VERSION3 ?
				LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
877
878
879
880
881
882
			savepriv = op->o_private;
			op->o_private = (void *)i;
			send_ldap_result( op, rs );
			op->o_private = savepriv;
			goto finish;
		}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
883

884
885
886
887
888
889
890
891
892
893
894
895
896
		/* check time limit */
		if ( op->ors_tlimit != SLAP_NO_LIMIT
				&& slap_get_time() > stoptime )
		{
			doabandon = 1;
			rc = rs->sr_err = LDAP_TIMELIMIT_EXCEEDED;
			savepriv = op->o_private;
			op->o_private = (void *)i;
			send_ldap_result( op, rs );
			op->o_private = savepriv;
			goto finish;
		}

897
		for ( i = 0; i < mi->mi_ntargets; i++ ) {
898
			meta_search_candidate_t	retcode = META_SEARCH_UNDEFINED;
899
			metasingleconn_t	*msc = &mc->mc_conns[ i ];
900
			LDAPMessage		*res = NULL, *msg;
901

Pierangelo Masarati's avatar
Pierangelo Masarati committed
902
			/* if msgid is invalid, don't ldap_result() */
903
			if ( candidates[ i ].sr_msgid == META_MSGID_IGNORE ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
904
905
				continue;
			}
906

Pierangelo Masarati's avatar
Pierangelo Masarati committed
907
			/* if target still needs bind, retry */
908
909
910
			if ( candidates[ i ].sr_msgid == META_MSGID_NEED_BIND
				|| candidates[ i ].sr_msgid == META_MSGID_CONNECTING )
			{
911
				/* initiate dobind */
912
913
				retcode = meta_search_dobind_init( op, rs, &mc, i, candidates );

914
				Debug( LDAP_DEBUG_TRACE, "%s <<< meta_search_dobind_init[%ld]=%d\n",
915
916
917
					op->o_log_prefix, i, retcode );

				switch ( retcode ) {
918
				case META_SEARCH_NEED_BIND:
919
					alreadybound--;
920
					/* fallthru */
921

922
				case META_SEARCH_CONNECTING:
923
				case META_SEARCH_BINDING:
924
925
926
					break;

				case META_SEARCH_ERR:
927
					candidates[ i ].sr_err = rs->sr_err;
928
929
930
931
932
933
934
					if ( META_BACK_ONERR_STOP( mi ) ) {
						savepriv = op->o_private;
						op->o_private = (void *)i;
						send_ldap_result( op, rs );
						op->o_private = savepriv;
						goto finish;
					}
935
936
937
938
939
940
941
942
943
944
					/* fallthru */

				case META_SEARCH_NOT_CANDIDATE:
					/*
					 * When no candidates are left,
					 * the outer cycle finishes
					 */
					candidates[ i ].sr_msgid = META_MSGID_IGNORE;
					assert( ncandidates > 0 );
					--ncandidates;
945
946
947
					break;

				case META_SEARCH_CANDIDATE:
948
					candidates[ i ].sr_msgid = META_MSGID_IGNORE;
949
950
951
					switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates ) )
					{
					case META_SEARCH_CANDIDATE:
952
						assert( candidates[ i ].sr_msgid >= 0 );
953
						break;
954
955

					case META_SEARCH_ERR:
956
						candidates[ i ].sr_err = rs->sr_err;
957
958
959
960
961
962
963
						if ( META_BACK_ONERR_STOP( mi ) ) {
							savepriv = op->o_private;
							op->o_private = (void *)i;
							send_ldap_result( op, rs );
							op->o_private = savepriv;
							goto finish;
						}
964
965
966
967
968
969
970
971
						/* fallthru */

					case META_SEARCH_NOT_CANDIDATE:
						/* means that meta_back_search_start()
						 * failed but onerr == continue */
						candidates[ i ].sr_msgid = META_MSGID_IGNORE;
						assert( ncandidates > 0 );
						--ncandidates;
972
973
974
975
976
977
978
						break;

					default:
						/* impossible */
						assert( 0 );
						break;
					}
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
979
					break;
980
981
982
983
984
985
986
987
988

				default:
					/* impossible */
					assert( 0 );
					break;
				}
				continue;
			}

989
			/* check for abandon */
990
			if ( op->o_abandon || LDAP_BACK_CONN_ABANDON( mc ) ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
991
992
				break;
			}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
993
994
995
996
997
998
999

#ifdef DEBUG_205
			if ( msc->msc_ld == NULL ) {
				char	buf[ SLAP_TEXT_BUFLEN ];

				ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
				snprintf( buf, sizeof( buf ),
1000
					"%s meta_back_search[%ld] mc=%p msgid=%d%s%s%s\n",
Pierangelo Masarati's avatar
Pierangelo Masarati committed
1001
1002
1003
					op->o_log_prefix, (long)i, (void *)mc,
					candidates[ i ].sr_msgid,
					META_IS_BINDING( &candidates[ i ] ) ? " binding" : "",
1004
1005
					LDAP_BACK_CONN_BINDING( &mc->mc_conns[ i ] ) ? " connbinding" : "",
					META_BACK_CONN_CREATING( &mc->mc_conns[ i ] ) ? " conncreating" : "" );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
1006
1007
1008
1009
1010
				ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
					
				Debug( LDAP_DEBUG_ANY, "!!! %s\n", buf, 0, 0 );
			}
#endif /* DEBUG_205 */
1011
			
1012
1013
1014
1015
1016
1017
1018
			/*
			 * FIXME: handle time limit as well?
			 * Note that target servers are likely 
			 * to handle it, so at some time we'll
			 * get a LDAP_TIMELIMIT_EXCEEDED from
			 * one of them ...
			 */
1019
			tv = save_tv;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
1020
			rc = ldap_result( msc->msc_ld, candidates[ i ].sr_msgid,
1021
					LDAP_MSG_RECEIVED, &tv, &res );
1022
1023
			switch ( rc ) {
			case 0:
1024
1025
				/* FIXME: res should not need to be freed */
				assert( res == NULL );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
1026
				continue;
1027

1028
			case -1:
1029
really_bad:;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
1030
				/* something REALLY bad happened! */
1031
1032
1033
				if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
					candidates[ i ].sr_type = REP_RESULT;

1034
					if ( meta_back_retry( op, rs, &mc, i, LDAP_BACK_DONTSEND ) ) {
1035
						candidates[ i ].sr_msgid = META_MSGID_IGNORE;
1036
						switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates ) )
1037
						{
1038
							/* means that failed but onerr == continue */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
1039
						case META_SEARCH_NOT_CANDIDATE:
1040
							candidates[ i ].sr_msgid = META_MSGID_IGNORE;
1041
1042

							assert( ncandidates > 0 );
1043
1044
							--ncandidates;

1045
							candidates[ i ].sr_err = rs->sr_err;
1046
1047
1048
1049
1050
1051
1052
							if ( META_BACK_ONERR_STOP( mi ) ) {
								savepriv = op->o_private;
								op->o_private = (void *)i;
								send_ldap_result( op, rs );
								op->o_private = savepriv;
								goto finish;
							}
1053
1054
1055
1056
1057
							/* fall thru */

						case META_SEARCH_CANDIDATE:
							/* get back into business... */
							continue;
1058
1059

						case META_SEARCH_BINDING:
1060
						case META_SEARCH_CONNECTING:
1061
						case META_SEARCH_NEED_BIND:
1062
						case META_SEARCH_UNDEFINED:
Pierangelo Masarati's avatar
Pierangelo Masarati committed
1063
1064
							assert( 0 );

1065
						default:
1066
							/* unrecoverable error */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
1067
							candidates[ i ].sr_msgid = META_MSGID_IGNORE;
1068
1069
1070
1071
							rc = rs->sr_err = LDAP_OTHER;
							goto finish;
						}
					}
1072

1073
					candidates[ i ].sr_err = rs->sr_err;