search.c 63.5 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/>.
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
4
 * Copyright 1999-2010 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
	/* 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 );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
194
195
196
197
		switch ( rc ) {
		case LDAP_SUCCESS:
			break;
		case LDAP_UNAVAILABLE:
198
			goto down;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
199
200
		default:
			goto other;
201
		}
202

203
204
205
206
		/* 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 );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
207
			if ( META_BACK_TGT_SAVECRED( mt ) && !BER_BVISNULL( &cred ) ) {
208
209
210
211
212
				if ( !BER_BVISNULL( &msc->msc_cred ) ) {
					memset( msc->msc_cred.bv_val, 0,
						msc->msc_cred.bv_len );
				}
				ber_bvreplace( &msc->msc_cred, &cred );
213
214
215
216
			}
		}

		if ( LDAP_BACK_CONN_ISBOUND( msc ) ) {
217
218
			/* apparently, idassert was configured with SASL bind,
			 * so bind occurred inside meta_back_proxy_authz_cred() */
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
			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;
		}
236
237
	}

238
239
	assert( msc->msc_ld != NULL );

240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
	if ( !BER_BVISEMPTY( &binddn ) && BER_BVISEMPTY( &cred ) ) {
		/* bind anonymously? */
		Debug( LDAP_DEBUG_ANY, "%s meta_search_dobind_init[%d] mc=%p: "
			"non-empty dn with empty cred; binding anonymously\n",
			op->o_log_prefix, candidate, (void *)mc );
		cred = slap_empty_bv;
		
	} else if ( BER_BVISEMPTY( &binddn ) && !BER_BVISEMPTY( &cred ) ) {
		/* error */
		Debug( LDAP_DEBUG_ANY, "%s meta_search_dobind_init[%d] mc=%p: "
			"empty dn with non-empty cred: error\n",
			op->o_log_prefix, candidate, (void *)mc );
		goto other;
	}

255
	/* connect must be async only the first time... */
256
257
	ldap_set_option( msc->msc_ld, LDAP_OPT_CONNECT_ASYNC, LDAP_OPT_ON );

258
retry:;
259
	rc = ldap_sasl_bind( msc->msc_ld, binddn.bv_val, LDAP_SASL_SIMPLE, &cred,
260
			NULL, NULL, &candidates[ candidate ].sr_msgid );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
261
262
263
264
265
266
267
268
269
270
271
272

#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 */

273
274
	switch ( rc ) {
	case LDAP_SUCCESS:
275
		assert( candidates[ candidate ].sr_msgid >= 0 );
276
		META_BINDING_SET( &candidates[ candidate ] );
277
278
		return META_SEARCH_BINDING;

279
280
	case LDAP_X_CONNECTING:
		/* must retry, same conn */
281
		candidates[ candidate ].sr_msgid = META_MSGID_CONNECTING;
282
283
284
		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 );
285
		return META_SEARCH_CONNECTING;
286

287
	case LDAP_SERVER_DOWN:
288
down:;
289
290
		/* This is the worst thing that could happen:
		 * the search will wait until the retry is over. */
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
		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 );

324
325
326
327
			if ( rc == LDAP_SUCCESS ) {
				LDAP_BACK_CONN_BINDING_SET( msc );
			}

328
329
			ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );

330
331
332
333
			if ( rc == LDAP_SUCCESS ) {
				candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
				goto retry;
			}
334
335
336
337
338
		}

		if ( *mcp == NULL ) {
			retcode = META_SEARCH_ERR;
			rs->sr_err = LDAP_UNAVAILABLE;
339
			candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
340
341
342
343
344
			break;
		}
		/* fall thru */

	default:
345
other:;
346
347
348
349
		rs->sr_err = rc;
		rc = slap_map_api2result( rs );

		ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
350
		meta_clear_one_candidate( op, mc, candidate );
351
		candidates[ candidate ].sr_err = rc;
352
353
		if ( META_BACK_ONERR_STOP( mi ) ) {
			LDAP_BACK_CONN_TAINTED_SET( mc );
354
			meta_back_release_conn_lock( mi, mc, 0 );
355
			*mcp = NULL;
356
			rs->sr_err = rc;
357
358
359
360
361
362

			retcode = META_SEARCH_ERR;

		} else {
			retcode = META_SEARCH_NOT_CANDIDATE;
		}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
363
		candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
		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;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
381
	metatarget_t		*mt = mi->mi_targets[ candidate ];
382
383
384
385
386
387
	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
388
389
	assert( msc->msc_ld != NULL );

390
	/* FIXME: matched? referrals? response controls? */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
391
	rc = ldap_parse_result( msc->msc_ld, res,
392
		&candidates[ candidate ].sr_err,
393
		NULL, NULL, NULL, NULL, 0 );
394
395
	if ( rc != LDAP_SUCCESS ) {
		candidates[ candidate ].sr_err = rc;
396
	}
397
	rc = slap_map_api2result( &candidates[ candidate ] );
398
399
400
401

	ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
	LDAP_BACK_CONN_BINDING_CLEAR( msc );
	if ( rc != LDAP_SUCCESS ) {
402
403
		meta_clear_one_candidate( op, mc, candidate );
		candidates[ candidate ].sr_err = rc;
404
405
		if ( META_BACK_ONERR_STOP( mi ) ) {
	        	LDAP_BACK_CONN_TAINTED_SET( mc );
406
			meta_back_release_conn_lock( mi, mc, 0 );
407
408
			*mcp = NULL;
			retcode = META_SEARCH_ERR;
409
			rs->sr_err = rc;
410
411
412
		}

	} else {
413
		/* FIXME: check if bound as idassert authcDN! */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
414
415
416
		if ( BER_BVISNULL( &msc->msc_bound_ndn )
			|| BER_BVISEMPTY( &msc->msc_bound_ndn ) )
		{
417
			LDAP_BACK_CONN_ISANON_SET( msc );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
418
419

		} else {
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
420
421
422
423
424
425
			if ( META_BACK_TGT_SAVECRED( mt ) &&
				!BER_BVISNULL( &msc->msc_cred ) &&
				!BER_BVISEMPTY( &msc->msc_cred ) )
			{
				ldap_set_rebind_proc( msc->msc_ld, mt->mt_rebind_f, msc );
			}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
426
			LDAP_BACK_CONN_ISBOUND_SET( msc );
427
428
		}
		retcode = META_SEARCH_CANDIDATE;
429
430
431

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

Pierangelo Masarati's avatar
Pierangelo Masarati committed
434
	candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
435
436
	META_BINDING_CLEAR( &candidates[ candidate ] );

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

439
440
441
	return retcode;
}

442
static meta_search_candidate_t
443
444
445
446
meta_back_search_start(
	Operation		*op,
	SlapReply		*rs,
	dncookie		*dc,
447
	metaconn_t		**mcp,
448
	int			candidate,
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
449
450
451
	SlapReply		*candidates,
	struct berval		*prcookie,
	ber_int_t		prsize )
452
{
453
	metainfo_t		*mi = ( metainfo_t * )op->o_bd->be_private;
454
	metatarget_t		*mt = mi->mi_targets[ candidate ];
Pierangelo Masarati's avatar
Pierangelo Masarati committed
455
	metasingleconn_t	*msc = &(*mcp)->mc_conns[ candidate ];
456
457
458
459
460
461
	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;
462
	meta_search_candidate_t	retcode;
463
464
	struct timeval		tv, *tvp = NULL;
	int			nretries = 1;
465
	LDAPControl		**ctrls = NULL;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
466
467
468
#ifdef SLAPD_META_CLIENT_PR
	LDAPControl		**save_ctrls = NULL;
#endif /* SLAPD_META_CLIENT_PR */
469

470
471
472
473
474
475
	/* 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)" );
476
		candidates[ candidate ].sr_err = LDAP_OTHER;
477
478
479
		if ( META_BACK_ONERR_STOP( mi ) ) {
			return META_SEARCH_ERR;
		}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
480
		candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
481
482
483
		return META_SEARCH_NOT_CANDIDATE;
	}

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

486
487
488
	/*
	 * modifies the base according to the scope, if required
	 */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
489
	if ( mt->mt_nsuffix.bv_len > op->o_req_ndn.bv_len ) {
490
491
492
493
494
495
496
497
498
499
		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...
			 */
500
501
502
			if ( dnIsSuffix( &mt->mt_nsuffix, &op->o_req_ndn ) ) {
				realbase = mt->mt_nsuffix;
				if ( mt->mt_scope == LDAP_SCOPE_SUBORDINATE ) {
503
504
					realscope = LDAP_SCOPE_SUBORDINATE;
				}
505
506
507
508
509

			} else {
				/*
				 * this target is no longer candidate
				 */
510
511
				retcode = META_SEARCH_NOT_CANDIDATE;
				goto doreturn;
512
513
514
			}
			break;

515
		case LDAP_SCOPE_SUBORDINATE:
516
517
		case LDAP_SCOPE_ONELEVEL:
		{
518
			struct berval	rdn = mt->mt_nsuffix;
519
520
			rdn.bv_len -= op->o_req_ndn.bv_len + STRLENOF( "," );
			if ( dnIsOneLevelRDN( &rdn )
521
					&& dnIsSuffix( &mt->mt_nsuffix, &op->o_req_ndn ) )
522
523
524
525
526
527
			{
				/*
				 * if there is exactly one level,
				 * make the target suffix the new
				 * base, and make scope "base"
				 */
528
				realbase = mt->mt_nsuffix;
529
				if ( op->ors_scope == LDAP_SCOPE_SUBORDINATE ) {
530
					if ( mt->mt_scope == LDAP_SCOPE_SUBORDINATE ) {
531
532
533
534
						realscope = LDAP_SCOPE_SUBORDINATE;
					} else {
						realscope = LDAP_SCOPE_SUBTREE;
					}
535
				} else {
536
537
					realscope = LDAP_SCOPE_BASE;
				}
538
539
540
541
542
543
544
545
				break;
			} /* else continue with the next case */
		}

		case LDAP_SCOPE_BASE:
			/*
			 * this target is no longer candidate
			 */
546
547
			retcode = META_SEARCH_NOT_CANDIDATE;
			goto doreturn;
548
549
550
		}
	}

551
552
553
554
555
556
	/* 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 ) {
557
		goto doreturn;
558
559
	}

560
561
562
	/*
	 * Rewrite the search base, if required
	 */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
563
	dc->target = mt;
564
565
	dc->ctx = "searchBase";
	switch ( ldap_back_dn_massage( dc, &realbase, &mbase ) ) {
566
	case LDAP_SUCCESS:
567
568
		break;

569
	case LDAP_UNWILLING_TO_PERFORM:
570
571
572
		rs->sr_err = LDAP_UNWILLING_TO_PERFORM;
		rs->sr_text = "Operation not allowed";
		send_ldap_result( op, rs );
573
574
		retcode = META_SEARCH_ERR;
		goto doreturn;
575

576
	default:
577
578
579
580

		/*
		 * this target is no longer candidate
		 */
581
582
		retcode = META_SEARCH_NOT_CANDIDATE;
		goto doreturn;
583
584
585
586
587
588
	}

	/*
	 * Maps filter
	 */
	rc = ldap_back_filter_map_rewrite( dc, op->ors_filter,
589
			&mfilter, BACKLDAP_MAP, op->o_tmpmemctx );
590
591
592
593
594
595
596
597
598
	switch ( rc ) {
	case LDAP_SUCCESS:
		break;

	case LDAP_COMPARE_FALSE:
	default:
		/*
		 * this target is no longer candidate
		 */
599
		retcode = META_SEARCH_NOT_CANDIDATE;
600
601
602
603
604
605
		goto done;
	}

	/*
	 * Maps required attributes
	 */
606
	rc = ldap_back_map_attrs( &mt->mt_rwmap.rwm_at,
607
608
			op->ors_attrs, BACKLDAP_MAP, &mapped_attrs,
			op->o_tmpmemctx );
609
610
611
612
	if ( rc != LDAP_SUCCESS ) {
		/*
		 * this target is no longer candidate
		 */
613
		retcode = META_SEARCH_NOT_CANDIDATE;
614
615
616
		goto done;
	}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
617
618
619
620
621
622
	if ( op->ors_tlimit != SLAP_NO_LIMIT ) {
		tv.tv_sec = op->ors_tlimit > 0 ? op->ors_tlimit : 1;
		tv.tv_usec = 0;
		tvp = &tv;
	}

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
#ifdef SLAPD_META_CLIENT_PR
	save_ctrls = op->o_ctrls;
	{
		LDAPControl *pr_c = NULL;
		int i = 0, nc = 0;

		if ( save_ctrls ) {
			for ( ; save_ctrls[i] != NULL; i++ );
			nc = i;
			pr_c = ldap_control_find( LDAP_CONTROL_PAGEDRESULTS, save_ctrls, NULL );
		}

		if ( pr_c != NULL ) nc--;
		if ( mt->mt_ps > 0 || prcookie != NULL ) nc++;

		if ( mt->mt_ps > 0 || prcookie != NULL || pr_c != NULL ) {
			int src = 0, dst = 0;
			BerElementBuffer berbuf;
			BerElement *ber = (BerElement *)&berbuf;
			struct berval val = BER_BVNULL;
			ber_len_t len;

			len = sizeof( LDAPControl * )*( nc + 1 ) + sizeof( LDAPControl );

			if ( mt->mt_ps > 0 || prcookie != NULL ) {
				struct berval nullcookie = BER_BVNULL;
				ber_tag_t tag;

				if ( prsize == 0 && mt->mt_ps > 0 ) prsize = mt->mt_ps;
				if ( prcookie == NULL ) prcookie = &nullcookie;

				ber_init2( ber, NULL, LBER_USE_DER );
				tag = ber_printf( ber, "{iO}", prsize, prcookie ); 
				if ( tag == LBER_ERROR ) {
					/* error */
					(void) ber_free_buf( ber );
					goto done_pr;
				}

				tag = ber_flatten2( ber, &val, 0 );
				if ( tag == LBER_ERROR ) {
					/* error */
					(void) ber_free_buf( ber );
					goto done_pr;
				}

				len += val.bv_len + 1;
			}

			op->o_ctrls = op->o_tmpalloc( len, op->o_tmpmemctx );
			if ( save_ctrls ) {
				for ( ; save_ctrls[ src ] != NULL; src++ ) {
					if ( save_ctrls[ src ] != pr_c ) {
						op->o_ctrls[ dst ] = save_ctrls[ src ];
						dst++;
					}
				}
			}

			if ( mt->mt_ps > 0 || prcookie != NULL ) {
				op->o_ctrls[ dst ] = (LDAPControl *)&op->o_ctrls[ nc + 1 ];

				op->o_ctrls[ dst ]->ldctl_oid = LDAP_CONTROL_PAGEDRESULTS;
				op->o_ctrls[ dst ]->ldctl_iscritical = 1;

				op->o_ctrls[ dst ]->ldctl_value.bv_val = (char *)&op->o_ctrls[ dst ][ 1 ];
				AC_MEMCPY( op->o_ctrls[ dst ]->ldctl_value.bv_val, val.bv_val, val.bv_len + 1 );
				op->o_ctrls[ dst ]->ldctl_value.bv_len = val.bv_len;
				dst++;

				(void)ber_free_buf( ber );
			}

			op->o_ctrls[ dst ] = NULL;
		}
done_pr:;
	}
#endif /* SLAPD_META_CLIENT_PR */

702
retry:;
703
	ctrls = op->o_ctrls;
704
	if ( meta_back_controls_add( op, rs, *mcp, candidate, &ctrls )
705
		!= LDAP_SUCCESS )
706
707
708
709
710
711
	{
		candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
		retcode = META_SEARCH_NOT_CANDIDATE;
		goto done;
	}

712
713
714
	/*
	 * Starts the search
	 */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
715
	assert( msc->msc_ld != NULL );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
716
	rc = ldap_pvt_search( msc->msc_ld,
717
718
			mbase.bv_val, realscope, mfilter.bv_val,
			mapped_attrs, op->ors_attrsonly,
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
719
			ctrls, NULL, tvp, op->ors_slimit, op->ors_deref,
720
			&candidates[ candidate ].sr_msgid ); 
721
722
	switch ( rc ) {
	case LDAP_SUCCESS:
723
		retcode = META_SEARCH_CANDIDATE;
724
725
726
727
728
		break;
	
	case LDAP_SERVER_DOWN:
		if ( nretries && meta_back_retry( op, rs, mcp, candidate, LDAP_BACK_DONTSEND ) ) {
			nretries = 0;
729
			/* if the identity changed, there might be need to re-authz */
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
730
			(void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
731
732
733
734
735
			goto retry;
		}

		if ( *mcp == NULL ) {
			retcode = META_SEARCH_ERR;
736
			candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
737
738
739
			break;
		}
		/* fall thru */
740

741
742
	default:
		candidates[ candidate ].sr_msgid = META_MSGID_IGNORE;
743
		retcode = META_SEARCH_NOT_CANDIDATE;
744
745
746
	}

done:;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
747
	(void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
748
749
750
751
752
753
#ifdef SLAPD_META_CLIENT_PR
	if ( save_ctrls != op->o_ctrls ) {
		op->o_tmpfree( op->o_ctrls, op->o_tmpmemctx );
		op->o_ctrls = save_ctrls;
	}
#endif /* SLAPD_META_CLIENT_PR */
754

755
	if ( mapped_attrs ) {
756
		ber_memfree_x( mapped_attrs, op->o_tmpmemctx );
757
758
	}
	if ( mfilter.bv_val != op->ors_filterstr.bv_val ) {
759
		ber_memfree_x( mfilter.bv_val, op->o_tmpmemctx );
760
761
762
763
764
	}
	if ( mbase.bv_val != realbase.bv_val ) {
		free( mbase.bv_val );
	}

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

768
	return retcode;
769
}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
770
771

int
772
meta_back_search( Operation *op, SlapReply *rs )
Pierangelo Masarati's avatar
Pierangelo Masarati committed
773
{
774
775
	metainfo_t	*mi = ( metainfo_t * )op->o_bd->be_private;
	metaconn_t	*mc;
776
777
	struct timeval	save_tv = { 0, 0 },
			tv;
778
	time_t		stoptime = (time_t)(-1),
779
780
			lastres_time = slap_get_time(),
			timeout = 0;
781
782
	int		rc = 0, sres = LDAP_SUCCESS;
	char		*matched = NULL;
783
	int		last = 0, ncandidates = 0,
784
785
786
			initial_candidates = 0, candidate_match = 0,
			needbind = 0;
	ldap_back_send_t	sendok = LDAP_BACK_SENDERR;
787
	long		i;
788
789
790
	dncookie	dc;
	int		is_ok = 0;
	void		*savepriv;
791
	SlapReply	*candidates = NULL;
792
	int		do_taint = 0;
793

794
795
796
797
798
799
	/*
	 * controls are set in ldap_back_dobind()
	 * 
	 * FIXME: in case of values return filter, we might want
	 * to map attrs and maybe rewrite value
	 */
800
801
getconn:;
	mc = meta_back_getconn( op, rs, NULL, sendok );
802
	if ( !mc ) {
803
		return rs->sr_err;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
804
805
	}

806
807
808
	dc.conn = op->o_conn;
	dc.rs = rs;

809
	if ( candidates == NULL ) candidates = meta_back_candidates_get( op );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
810
811
812
	/*
	 * Inits searches
	 */
813
	for ( i = 0; i < mi->mi_ntargets; i++ ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
814
815
		/* reset sr_msgid; it is used in most loops
		 * to check if that target is still to be considered */
816
		candidates[ i ].sr_msgid = META_MSGID_IGNORE;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
817

Pierangelo Masarati's avatar
Pierangelo Masarati committed
818
819
820
821
822
823
824
		/* 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 */
825
		if ( !META_IS_CANDIDATE( &candidates[ i ] ) ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
826
827
828
			continue;
		}

829
830
831
832
		candidates[ i ].sr_matched = NULL;
		candidates[ i ].sr_text = NULL;
		candidates[ i ].sr_ref = NULL;
		candidates[ i ].sr_ctrls = NULL;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
833
		candidates[ i ].sr_nentries = 0;
834
835
836
837
838
839
840

		/* 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
841
	}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
842

Pierangelo Masarati's avatar
Pierangelo Masarati committed
843
	for ( i = 0; i < mi->mi_ntargets; i++ ) {
844
		if ( !META_IS_CANDIDATE( &candidates[ i ] )
845
846
847
848
849
			|| candidates[ i ].sr_err != LDAP_SUCCESS )
		{
			continue;
		}

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
850
		switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates, NULL, 0 ) )
851
		{
852
		case META_SEARCH_NOT_CANDIDATE:
Pierangelo Masarati's avatar
Pierangelo Masarati committed
853
			candidates[ i ].sr_msgid = META_MSGID_IGNORE;
854
855
			break;

856
857
858
859
		case META_SEARCH_NEED_BIND:
			++needbind;
			/* fallthru */

860
		case META_SEARCH_CONNECTING:
861
		case META_SEARCH_CANDIDATE:
862
		case META_SEARCH_BINDING:
863
			candidates[ i ].sr_type = REP_INTERMEDIATE;
864
865
			++ncandidates;
			break;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
866

867
		case META_SEARCH_ERR:
868
869
870
871
			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
872
873
			rc = -1;
			goto finish;
874
875
876
877

		default:
			assert( 0 );
			break;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
878
		}
879
	}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
880

881
	if ( ncandidates > 0 && needbind == ncandidates ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
		/*
		 * 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;
		}
899
900
901
902

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

Pierangelo Masarati's avatar
Pierangelo Masarati committed
903
904
905
906
#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 */
907

908
		meta_back_release_conn( mi, mc );
909
910
911
912
913
914
915
916
		mc = NULL;

		needbind = 0;
		ncandidates = 0;

		goto getconn;
	}

917
	initial_candidates = ncandidates;
918

919
	if ( LogTest( LDAP_DEBUG_TRACE ) ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
920
		char	cnd[ SLAP_TEXT_BUFLEN ];
921
		int	c;
922

923
924
925
		for ( c = 0; c < mi->mi_ntargets; c++ ) {
			if ( META_IS_CANDIDATE( &candidates[ c ] ) ) {
				cnd[ c ] = '*';
926
			} else {
927
				cnd[ c ] = ' ';
928
			}
929
		}
930
		cnd[ c ] = '\0';
931

932
		Debug( LDAP_DEBUG_TRACE, "%s meta_back_search: ncandidates=%d "
933
934
			"cnd=\"%s\"\n", op->o_log_prefix, ncandidates, cnd );
	}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
935

936
	if ( initial_candidates == 0 ) {
937
938
939
940
941
942
943
944
945
946
947
948
949
		/* 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 );

950
951
		/* FIXME: we're sending the first error we encounter;
		 * maybe we should pick the worst... */
952
		rc = LDAP_NO_SUCH_OBJECT;
953
		for ( i = 0; i < mi->mi_ntargets; i++ ) {
954
			if ( META_IS_CANDIDATE( &candidates[ i ] )
955
956
957
958
959
960
961
962
963
				&& candidates[ i ].sr_err != LDAP_SUCCESS )
			{
				rc = candidates[ i ].sr_err;
				break;
			}
		}

		send_ldap_error( op, rs, rc, NULL );

964
		goto finish;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
965
966
967
968
969
970
971
	}

	/* 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.
	 */

972
973
974
975
	if ( op->ors_tlimit != SLAP_NO_LIMIT ) {
		stoptime = op->o_time + op->ors_tlimit;
	}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
976
977
	/*
	 * In case there are no candidates, no cycle takes place...
978
	 *
979
	 * FIXME: we might use a queue, to better balance the load 
980
	 * among the candidates
Pierangelo Masarati's avatar
Pierangelo Masarati committed
981
	 */
982
	for ( rc = 0; ncandidates > 0; ) {
983
		int	gotit = 0,
984
985
			doabandon = 0,
			alreadybound = ncandidates;
986
987

		/* check timeout */
988
989
		if ( timeout && lastres_time > 0
			&& ( slap_get_time() - lastres_time ) > timeout )
990
991
992
		{
			doabandon = 1;
			rs->sr_text = "Operation timed out";
993
994
			rc = rs->sr_err = op->o_protocol >= LDAP_VERSION3 ?
				LDAP_ADMINLIMIT_EXCEEDED : LDAP_OTHER;
995
996
997
998
999
1000
			savepriv = op->o_private;
			op->o_private = (void *)i;
			send_ldap_result( op, rs );
			op->o_private = savepriv;
			goto finish;
		}