bind.c 24.3 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-2006 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

#include "portable.h"

#include <stdio.h>

Pierangelo Masarati's avatar
Pierangelo Masarati committed
27
#include <ac/errno.h>
Pierangelo Masarati's avatar
Pierangelo Masarati committed
28
29
30
31
32
33
34
35
36
37
#include <ac/socket.h>
#include <ac/string.h>


#define AVL_INTERNAL
#include "slap.h"
#include "../back-ldap/back-ldap.h"
#include "back-meta.h"

int
38
meta_back_bind( Operation *op, SlapReply *rs )
Pierangelo Masarati's avatar
Pierangelo Masarati committed
39
{
40
	metainfo_t	*mi = ( metainfo_t * )op->o_bd->be_private;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
41
	metaconn_t	*mc = NULL;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
42

43
	int		rc = LDAP_OTHER,
44
45
46
			i,
			gotit = 0,
			isroot = 0;
47

Pierangelo Masarati's avatar
Pierangelo Masarati committed
48
	SlapReply	*candidates = meta_back_candidates_get( op );
49
50

	rs->sr_err = LDAP_SUCCESS;
51

52
53
	Debug( LDAP_DEBUG_ARGS, "%s meta_back_bind: dn=\"%s\".\n",
		op->o_log_prefix, op->o_req_dn.bv_val, 0 );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
54

55
	/* the test on the bind method should be superfluous */
56
57
58
59
60
61
62
63
64
	if ( op->orb_method == LDAP_AUTH_SIMPLE
		&& be_isroot_dn( op->o_bd, &op->o_req_ndn ) )
	{
		if ( !be_isroot_pw( op ) ) {
			rs->sr_err = LDAP_INVALID_CREDENTIALS;
			rs->sr_text = NULL;
			send_ldap_result( op, rs );
			return rs->sr_err;
		}
65
66
67
68

		if ( META_BACK_DEFER_ROOTDN_BIND( mi ) ) {
			rs->sr_err = LDAP_SUCCESS;
			rs->sr_text = NULL;
69
			/* frontend will return success */
70
71
72
			return rs->sr_err;
		}

73
74
		isroot = 1;
	}
75
76
77
78

	/* we need meta_back_getconn() not send result even on error,
	 * because we want to intercept the error and make it
	 * invalidCredentials */
79
	mc = meta_back_getconn( op, rs, NULL, LDAP_BACK_BIND_DONTSEND );
80
	if ( !mc ) {
81
82
83
84
85
86
87
88
		char	buf[ SLAP_TEXT_BUFLEN ];

		snprintf( buf, sizeof( buf ),
			"meta_back_bind: no target "
			"for dn \"%s\" (%d%s%s).",
			op->o_req_dn.bv_val, rs->sr_err,
			rs->sr_text ? ". " : "",
			rs->sr_text ? rs->sr_text : "" );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
89
		Debug( LDAP_DEBUG_ANY,
90
91
92
			"%s %s\n",
			op->o_log_prefix, buf, 0 );

93
94
95
96
97
98
99
100
101
		/* FIXME: there might be cases where we don't want
		 * to map the error onto invalidCredentials */
		switch ( rs->sr_err ) {
		case LDAP_NO_SUCH_OBJECT:
		case LDAP_UNWILLING_TO_PERFORM:
			rs->sr_err = LDAP_INVALID_CREDENTIALS;
			rs->sr_text = NULL;
			break;
		}
102
		send_ldap_result( op, rs );
103
		return rs->sr_err;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
104
105
106
107
108
	}

	/*
	 * Each target is scanned ...
	 */
109
	mc->mc_authz_target = META_BOUND_NONE;
110
	for ( i = 0; i < mi->mi_ntargets; i++ ) {
111
		metatarget_t	*mt = mi->mi_targets[ i ];
112
		int		lerr;
113
		Operation	op2 = *op;
114
		int		massage = 1;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
115
116
117
118

		/*
		 * Skip non-candidates
		 */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
119
		if ( candidates[ i ].sr_tag != META_CANDIDATE ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
120
121
122
123
			continue;
		}

		if ( gotit == 0 ) {
124
125
126
			/* set rc to LDAP_SUCCESS only if at least
			 * one candidate has been tried */
			rc = LDAP_SUCCESS;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
127
			gotit = 1;
128
129

		} else if ( isroot == 0 ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
130
131
132
133
134
			/*
			 * A bind operation is expected to have
			 * ONE CANDIDATE ONLY!
			 */
			Debug( LDAP_DEBUG_ANY,
135
				"### %s meta_back_bind: more than one"
136
				" candidate selected...\n",
137
				op->o_log_prefix, 0, 0 );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
138
139
		}

140
		if ( isroot ) {
141
			if ( BER_BVISNULL( &mt->mt_pseudorootdn ) )
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
			{
				metasingleconn_t	*msc = &mc->mc_conns[ i ];

				/* skip the target if no pseudorootdn is provided */
				if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) {
					ch_free( msc->msc_bound_ndn.bv_val );
					BER_BVZERO( &msc->msc_bound_ndn );
				}

				if ( LDAP_BACK_SAVECRED( mi ) &&
					!BER_BVISNULL( &msc->msc_cred ) )
				{
					/* destroy sensitive data */
					memset( msc->msc_cred.bv_val, 0,
						msc->msc_cred.bv_len );
					ch_free( msc->msc_cred.bv_val );
					BER_BVZERO( &msc->msc_cred );
				}

				continue;
			}

164
165
166
			op2.o_req_dn = mt->mt_pseudorootdn;
			op2.o_req_ndn = mt->mt_pseudorootdn;
			op2.orb_cred = mt->mt_pseudorootpw;
167
			op2.orb_method = LDAP_AUTH_SIMPLE;
168
169

			massage = 0;
170
171
		}
		
172
173
		lerr = meta_back_single_bind( &op2, rs, mc, i, massage );

Pierangelo Masarati's avatar
Pierangelo Masarati committed
174
		if ( lerr != LDAP_SUCCESS ) {
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
175
			rc = rs->sr_err = lerr;
176
177
178
179
			/* FIXME: in some cases (e.g. unavailable)
			 * do not assume it's not candidate; rather
			 * mark this as an error to be eventually
			 * reported to client */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
180
			candidates[ i ].sr_tag = META_NOT_CANDIDATE;
181
			break;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
182
183
184
		}
	}

185
186
187
188
189
190
191
192
	/* must re-insert if local DN changed as result of bind */
	if ( rc == LDAP_SUCCESS ) {
		if ( isroot ) {
			mc->mc_authz_target = META_BOUND_ALL;
			ber_dupbv( &op->orb_edn, be_root_dn( op->o_bd ) );
		}

		if ( !dn_match( &op->o_req_ndn, &mc->mc_local_ndn ) ) {
193
			metaconn_t	*tmpmc;
194
195
196
197
			int		lerr;

			/* wait for all other ops to release the connection */
retry_lock:;
198
			ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
199
			if ( mc->mc_refcnt > 1 ) {
200
				ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
201
202
203
204
205
				ldap_pvt_thread_yield();
				goto retry_lock;
			}

			assert( mc->mc_refcnt == 1 );
206
207
208
			tmpmc = avl_delete( &mi->mi_conninfo.lai_tree, (caddr_t)mc,
				meta_back_conndn_cmp );
			assert( tmpmc == mc );
209

210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
			/* delete all cached connections with the current connection */
			if ( LDAP_BACK_SINGLECONN( mi ) ) {
				while ( ( tmpmc = avl_delete( &mi->mi_conninfo.lai_tree, (caddr_t)mc, meta_back_conn_cmp ) ) != NULL )
				{
					Debug( LDAP_DEBUG_TRACE,
						"=>meta_back_bind: destroying conn %ld (refcnt=%u)\n",
						LDAP_BACK_PCONN_ID( mc->mc_conn ), mc->mc_refcnt, 0 );

					if ( mc->mc_refcnt != 0 ) {
						/* taint it */
						LDAP_BACK_CONN_TAINTED_SET( tmpmc );

					} else {
						/*
						 * Needs a test because the handler may be corrupted,
						 * and calling ldap_unbind on a corrupted header results
						 * in a segmentation fault
						 */
						meta_back_conn_free( tmpmc );
					}
				}
			}

233
			ber_bvreplace( &mc->mc_local_ndn, &op->o_req_ndn );
234
235
236
			if ( be_isroot_dn( op->o_bd, &op->o_req_ndn ) ) {
				mc->mc_conn = LDAP_BACK_PCONN_SET( op );
			}
237
			lerr = avl_insert( &mi->mi_conninfo.lai_tree, (caddr_t)mc,
238
				meta_back_conndn_cmp, meta_back_conndn_dup );
239
			ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
240
			if ( lerr == -1 ) {
241
				meta_clear_candidates( op, mc );
242
243
244
245
246
247
248

				/* we can do this because mc_refcnt == 1 */
				mc->mc_refcnt = 0;
				meta_back_conn_free( mc );
				mc = NULL;
			}
		}
249
250
	}

251
252
253
	if ( mc != NULL ) {
		meta_back_release_conn( op, mc );
	}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
254

255
256
257
	/*
	 * rc is LDAP_SUCCESS if at least one bind succeeded,
	 * err is the last error that occurred during a bind;
258
	 * if at least (and at most?) one bind succeeds, fine.
259
	 */
260
	if ( rc != LDAP_SUCCESS ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
261
262
263
264
		
		/*
		 * deal with bind failure ...
		 */
265
266
267
268
269

		/*
		 * no target was found within the naming context, 
		 * so bind must fail with invalid credentials
		 */
270
271
		if ( rs->sr_err == LDAP_SUCCESS && gotit == 0 ) {
			rs->sr_err = LDAP_INVALID_CREDENTIALS;
272
273
		} else {
			rs->sr_err = slap_map_api2result( rs );
274
		}
275
		send_ldap_result( op, rs );
276
		return rs->sr_err;
277

Pierangelo Masarati's avatar
Pierangelo Masarati committed
278
279
	}

280
	return LDAP_SUCCESS;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
281
282
283
}

/*
284
 * meta_back_single_bind
Pierangelo Masarati's avatar
Pierangelo Masarati committed
285
286
287
 *
 * attempts to perform a bind with creds
 */
288
int
289
meta_back_single_bind(
290
291
292
	Operation		*op,
	SlapReply		*rs,
	metaconn_t		*mc,
293
294
	int			candidate,
	int			massage )
Pierangelo Masarati's avatar
Pierangelo Masarati committed
295
{
296
	metainfo_t		*mi = ( metainfo_t * )op->o_bd->be_private;
297
	metatarget_t		*mt = mi->mi_targets[ candidate ];
298
	struct berval		mdn = BER_BVNULL;
299
	metasingleconn_t	*msc = &mc->mc_conns[ candidate ];
300
301
	int			msgid,
				rebinding = 0;
302

Pierangelo Masarati's avatar
Pierangelo Masarati committed
303
	
304
305
306
307
308
309
310
311
312
313
314
315
	if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) {
		ch_free( msc->msc_bound_ndn.bv_val );
		BER_BVZERO( &msc->msc_bound_ndn );
	}

	if ( LDAP_BACK_SAVECRED( mi ) && !BER_BVISNULL( &msc->msc_cred ) ) {
		/* destroy sensitive data */
		memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len );
		ch_free( msc->msc_cred.bv_val );
		BER_BVZERO( &msc->msc_cred );
	}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
316
317
318
	/*
	 * Rewrite the bind dn if needed
	 */
319
320
	if ( massage ) {
		dncookie		dc;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
321

322
323
324
325
326
327
		dc.target = mt;
		dc.conn = op->o_conn;
		dc.rs = rs;
		dc.ctx = "bindDN";

		if ( ldap_back_dn_massage( &dc, &op->o_req_dn, &mdn ) ) {
328
329
330
			rs->sr_text = "DN rewrite error";
			rs->sr_err = LDAP_OTHER;
			return rs->sr_err;
331
332
333
334
		}

	} else {
		mdn = op->o_req_dn;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
335
336
	}

337
338
339
	/* FIXME: this fixes the bind problem right now; we need
	 * to use the asynchronous version to get the "matched"
	 * and more in case of failure ... */
340
	/* FIXME: should we check if at least some of the op->o_ctrls
341
	 * can/should be passed? */
342
rebind:;
343
	rs->sr_err = ldap_sasl_bind( msc->msc_ld, mdn.bv_val,
344
345
346
347
			LDAP_SASL_SIMPLE, &op->orb_cred,
			op->o_ctrls, NULL, &msgid );
	if ( rs->sr_err == LDAP_SUCCESS ) {
		LDAPMessage	*res;
348
		struct timeval	tv;
349
		int		rc;
350
		int		nretries = mt->mt_nretries;
351
		char		buf[ SLAP_TEXT_BUFLEN ];
352

353
354
		LDAP_BACK_TV_SET( &tv );

355
356
357
358
		/*
		 * handle response!!!
		 */
retry:;
359
		switch ( ldap_result( msc->msc_ld, msgid, LDAP_MSG_ALL, &tv, &res ) ) {
360
		case 0:
361
			snprintf( buf, sizeof( buf ),
362
				"ldap_result=0 nretries=%d%s",
363
364
365
366
				nretries, rebinding ? " rebinding" : "" );
			Debug( LDAP_DEBUG_ANY,
				"%s meta_back_single_bind[%d]: %s.\n",
				op->o_log_prefix, candidate, buf );
367
368

			if ( nretries != META_RETRY_NEVER ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
369
				ldap_pvt_thread_yield();
370
371
372
				if ( nretries > 0 ) {
					nretries--;
				}
373
				tv = mt->mt_bind_timeout;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
374
375
				goto retry;
			}
376

Pierangelo Masarati's avatar
Pierangelo Masarati committed
377
			rs->sr_err = LDAP_BUSY;
378
379
380
381
382
383
384
385
386
387
388
389
			if ( rebinding ) {
				ldap_abandon_ext( msc->msc_ld, msgid, NULL, NULL );
				break;
			}

			/* FIXME: some times the request times out
			 * while the other party is not willing to
			 * send a response any more.  Give it a second
			 * chance with a freshly bound connection */
			rebinding = 1;
			nretries = mt->mt_nretries;
			/* fallthru */
390
391

		case -1:
392
			ldap_get_option( msc->msc_ld, LDAP_OPT_ERROR_NUMBER,
393
				&rs->sr_err );
394

395
396
397
398
			if ( rebinding ) {
				ldap_abandon_ext( msc->msc_ld, msgid, NULL, NULL );
			}

399
			snprintf( buf, sizeof( buf ),
400
401
				"err=%d (%s) nretries=%d",
				rs->sr_err, ldap_err2string( rs->sr_err ), nretries );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
402
			Debug( LDAP_DEBUG_ANY,
403
404
				"### %s meta_back_single_bind[%d]: %s.\n",
				op->o_log_prefix, candidate, buf );
405

406
407
			rc = slap_map_api2result( rs );
			if ( rs->sr_err == LDAP_UNAVAILABLE && nretries != META_RETRY_NEVER ) {
408
				rc = meta_back_retry( op, rs, &mc, candidate, LDAP_BACK_DONTSEND );
409
				if ( rc ) {
410
411
412
					if ( nretries > 0 ) {
						nretries--;
					}
413
414
					ldap_pvt_thread_yield();
					goto rebind;
415
				}
416
				goto return_results;
417
			}
418
419
420
			break;

		default:
421
			rc = ldap_parse_result( msc->msc_ld, res, &rs->sr_err,
422
423
424
425
426
427
428
429
					NULL, NULL, NULL, NULL, 1 );
			if ( rc != LDAP_SUCCESS ) {
				rs->sr_err = rc;
			}
			break;
		}
	}

430
	if ( rs->sr_err != LDAP_SUCCESS ) {
431
		rs->sr_err = slap_map_api2result( rs );
432
433
		goto return_results;
	}
434

435
	ber_bvreplace( &msc->msc_bound_ndn, &op->o_req_dn );
436
437
	LDAP_BACK_CONN_ISBOUND_SET( msc );
	mc->mc_authz_target = candidate;
438

439
	if ( LDAP_BACK_SAVECRED( mi ) ) {
440
		ber_bvreplace( &msc->msc_cred, &op->orb_cred );
441
		ldap_set_rebind_proc( msc->msc_ld, mt->mt_rebind_f, msc );
442
	}
443

444
	if ( mi->mi_cache.ttl != META_DNCACHE_DISABLED
445
446
			&& op->o_req_ndn.bv_len != 0 )
	{
447
		( void )meta_dncache_update_entry( &mi->mi_cache,
448
				&op->o_req_ndn, candidate );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
449
	}
450
451

return_results:;
452
	if ( mdn.bv_val != op->o_req_dn.bv_val ) {
453
		free( mdn.bv_val );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
454
455
	}

456
	return rs->sr_err;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
457
458
}

459
460
461
462
463
464
/*
 * meta_back_single_dobind
 */
int
meta_back_single_dobind(
	Operation		*op,
465
	SlapReply		*rs,
466
	metaconn_t		**mcp,
467
	int			candidate,
468
	ldap_back_send_t	sendok,
Pierangelo Masarati's avatar
Pierangelo Masarati committed
469
470
	int			nretries,
	int			dolock )
471
{
472
	metainfo_t		*mi = ( metainfo_t * )op->o_bd->be_private;
473
	metatarget_t		*mt = mi->mi_targets[ candidate ];
474
	metaconn_t		*mc = *mcp;
475
476
	metasingleconn_t	*msc = &mc->mc_conns[ candidate ];
	int			rc;
477
	static struct berval	cred = BER_BVC( "" );
478
479
480
	int			msgid,
				rebinding = 0,
				save_nretries = nretries;
481

482
483
	assert( !LDAP_BACK_CONN_ISBOUND( msc ) );

484
485
486
487
	/*
	 * meta_back_single_dobind() calls meta_back_single_bind()
	 * if required.
	 */
488
	if ( be_isroot( op ) && !BER_BVISNULL( &mt->mt_pseudorootdn ) )
489
490
491
492
	{
		Operation	op2 = *op;

		op2.o_tag = LDAP_REQ_BIND;
493
494
495
		op2.o_req_dn = mt->mt_pseudorootdn;
		op2.o_req_ndn = mt->mt_pseudorootdn;
		op2.orb_cred = mt->mt_pseudorootpw;
496
497
498
499
500
501
		op2.orb_method = LDAP_AUTH_SIMPLE;

		rc = meta_back_single_bind( &op2, rs, *mcp, candidate, 0 );
		goto done;
	}

502
503
504
505
506
507
508
509
510
511
	/*
	 * Otherwise an anonymous bind is performed
	 * (note: if the target was already bound, the anonymous
	 * bind clears the previous bind).
	 */
	if ( !BER_BVISNULL( &msc->msc_bound_ndn ) ) {
		ber_memfree( msc->msc_bound_ndn.bv_val );
		BER_BVZERO( &msc->msc_bound_ndn );
	}
		
512
	if ( LDAP_BACK_SAVECRED( mi ) && !BER_BVISNULL( &msc->msc_cred ) ) {
513
514
515
516
517
518
519
520
		/* destroy sensitive data */
		memset( msc->msc_cred.bv_val, 0, msc->msc_cred.bv_len );
		ber_memfree( msc->msc_cred.bv_val );
		BER_BVZERO( &msc->msc_cred );
	}

	/* FIXME: should we check if at least some of the op->o_ctrls
	 * can/should be passed? */
521
rebind:;
522
523
524
525
	rc = ldap_sasl_bind( msc->msc_ld, "", LDAP_SASL_SIMPLE, &cred,
			NULL, NULL, &msgid );
	if ( rc == LDAP_SUCCESS ) {
		LDAPMessage	*res;
526
		struct timeval	tv;
527
		char		buf[ SLAP_TEXT_BUFLEN ];
528
529

		LDAP_BACK_TV_SET( &tv );
530
531
532
533
534

		/*
		 * handle response!!!
		 */
retry:;
535
		switch ( ldap_result( msc->msc_ld, msgid, LDAP_MSG_ALL, &tv, &res ) ) {
536
		case 0:
537
538
539
			snprintf( buf, sizeof( buf ),
				"ldap_result=0 nretries=%d%s",
				nretries, rebinding ? " rebinding" : "" );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
540
			Debug( LDAP_DEBUG_ANY,
541
542
				"%s meta_back_single_dobind[%d]: %s.\n",
				op->o_log_prefix, candidate, buf );
543
544

			if ( nretries != META_RETRY_NEVER ) {
545
				ldap_pvt_thread_yield();
546
547
548
				if ( nretries > 0 ) {
					nretries--;
				}
549
				tv = mt->mt_bind_timeout;
550
551
552
553
				goto retry;
			}

			rc = LDAP_BUSY;
554
			if ( rebinding ) {
555
				ldap_abandon_ext( msc->msc_ld, msgid, NULL, NULL );
556
557
558
559
560
561
562
563
564
565
				break;
			}

			/* FIXME: some times the request times out
			 * while the other party is not willing to
			 * send a response any more.  Give it a second
			 * chance with a freshly bound connection */
			rebinding = 1;
			nretries = save_nretries;
			/* fallthru */
566
567

		case -1:
568
569
			ldap_get_option( msc->msc_ld, LDAP_OPT_ERROR_NUMBER,
				&rs->sr_err );
570

571
572
573
574
			if ( rebinding ) {
				ldap_abandon_ext( msc->msc_ld, msgid, NULL, NULL );
			}

575
			snprintf( buf, sizeof( buf ),
576
577
				"err=%d (%s) nretries=%d",
				rs->sr_err, ldap_err2string( rs->sr_err ), nretries );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
578
			Debug( LDAP_DEBUG_ANY,
579
580
				"### %s meta_back_single_dobind[%d]: %s.\n",
				op->o_log_prefix, candidate, buf );
581
582

			rc = slap_map_api2result( rs );
583
			if ( rc == LDAP_UNAVAILABLE && nretries != META_RETRY_NEVER ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
584
				if ( dolock ) {
585
					ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
586
587
588
				}

				if ( mc->mc_refcnt == 1 ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
589
					meta_clear_one_candidate( msc );
590
				        LDAP_BACK_CONN_ISBOUND_CLEAR( msc );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
591

Pierangelo Masarati's avatar
Pierangelo Masarati committed
592
593
					( void )rewrite_session_delete( mt->mt_rwmap.rwm_rw, op->o_conn );

Pierangelo Masarati's avatar
Pierangelo Masarati committed
594
595
596
				        /* mc here must be the regular mc,
					 * reset and ready for init */
				        rc = meta_back_init_one_conn( op, rs,
597
						mt, mc, candidate,
598
599
						LDAP_BACK_CONN_ISPRIV( mc ),
						LDAP_BACK_DONTSEND );
600
601
602
					if ( rc == LDAP_SUCCESS ) {
				        	LDAP_BACK_CONN_BINDING_SET( msc );
					}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
603
604
605
606
607

				} else {
					/* can't do anything about it */
					rc = LDAP_UNAVAILABLE;
				}
608

Pierangelo Masarati's avatar
Pierangelo Masarati committed
609
				if ( dolock ) {
610
					ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
611
				}
612

613
				if ( rc == LDAP_SUCCESS ) {
614
					ldap_pvt_thread_yield();
615
616
617
					if ( nretries > 0 ) {
						nretries--;
					}
618
619
620
					goto rebind;
				}
			}
621
622
623
			break;

		default:
624
			rc = ldap_parse_result( msc->msc_ld, res, &rs->sr_err,
625
626
					NULL, NULL, NULL, NULL, 1 );
			if ( rc == LDAP_SUCCESS ) {
627
				rc = slap_map_api2result( rs );
628
629
630
			}
			break;
		}
631
632

	} else {
633
		rs->sr_err = rc;
634
		rc = slap_map_api2result( rs );
635
636
	}

637
done:;
638
	rs->sr_err = rc;
639
	if ( rc != LDAP_SUCCESS && META_BACK_ONERR_STOP( mi ) ) {
640
	        LDAP_BACK_CONN_BINDING_CLEAR( msc );
641
642
	        LDAP_BACK_CONN_TAINTED_SET( mc );
		meta_back_release_conn_lock( op, mc, dolock );
643
644
645
646
647
		*mcp = NULL;

		if ( sendok & LDAP_BACK_SENDERR ) {
			send_ldap_result( op, rs );
		}
648
649
	}

650
651
652
	return rc;
}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
653
654
655
656
/*
 * meta_back_dobind
 */
int
657
658
659
660
661
meta_back_dobind(
	Operation		*op,
	SlapReply		*rs,
	metaconn_t		*mc,
	ldap_back_send_t	sendok )
Pierangelo Masarati's avatar
Pierangelo Masarati committed
662
{
663
664
	metainfo_t		*mi = ( metainfo_t * )op->o_bd->be_private;

665
666
667
	int			bound = 0,
				i,
				isroot = 0;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
668

Pierangelo Masarati's avatar
Pierangelo Masarati committed
669
	SlapReply		*candidates = meta_back_candidates_get( op );
670

671
672
673
	if ( be_isroot( op ) ) {
		isroot = 1;
	}
674

675
	Debug( LDAP_DEBUG_TRACE,
676
		"%s meta_back_dobind: conn=%ld%s\n",
677
678
		op->o_log_prefix,
		LDAP_BACK_PCONN_ID( mc->mc_conn ),
679
680
		isroot ? " (isroot)" : "" );

681
682
683
	/*
	 * all the targets are bound as pseudoroot
	 */
684
	if ( mc->mc_authz_target == META_BOUND_ALL ) {
685
686
		bound = 1;
		goto done;
687
688
	}

689
	for ( i = 0; i < mi->mi_ntargets; i++ ) {
690
		metatarget_t		*mt = mi->mi_targets[ i ];
691
		metasingleconn_t	*msc = &mc->mc_conns[ i ];
692
		int			rc, do_retry = 1;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
693
694

		/*
695
		 * Not a candidate
Pierangelo Masarati's avatar
Pierangelo Masarati committed
696
		 */
697
		if ( candidates[ i ].sr_tag != META_CANDIDATE ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
698
699
700
			continue;
		}

701
702
		assert( msc->msc_ld != NULL );

Pierangelo Masarati's avatar
Pierangelo Masarati committed
703
704
705
		/*
		 * If the target is already bound it is skipped
		 */
706
707
708

retry_binding:;
		ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
709
		if ( LDAP_BACK_CONN_ISBOUND( msc ) || LDAP_BACK_CONN_ISANON( msc ) ) {
710
			ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
711
712
			++bound;
			continue;
713
714
715
716
717
718
719
720
721
722

		} else if ( LDAP_BACK_CONN_BINDING( msc ) ) {
			ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
			ldap_pvt_thread_yield();
			goto retry_binding;

		} else {
			LDAP_BACK_CONN_BINDING_SET( msc );
			ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
		} 
Pierangelo Masarati's avatar
Pierangelo Masarati committed
723

724
retry:;
725
726
727
728
729
730
		rc = meta_back_single_dobind( op, rs, &mc, i,
			LDAP_BACK_DONTSEND, mt->mt_nretries, 1 );
		/*
		 * NOTE: meta_back_single_dobind() already retries;
		 * in case of failure, it resets mc...
		 */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
731
		if ( rc != LDAP_SUCCESS ) {
732
733
			char		buf[ SLAP_TEXT_BUFLEN ];

734
735
736
737
738
739
			if ( mc == NULL ) {
				/* meta_back_single_dobind() already sent 
				 * response and released connection */
				goto send_err;
			}

740

741
742
			if ( rc == LDAP_UNAVAILABLE && do_retry ) {
				do_retry = 0;
743
				if ( meta_back_retry( op, rs, &mc, i, sendok ) ) {
744
745
					goto retry;
				}
746
747
748
749
750
751

				if ( mc != NULL ) {
					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 );
				}
752

753
				return 0;
754
755
			}

756
757
758
759
			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 );

760
			snprintf( buf, sizeof( buf ),
761
				"meta_back_dobind[%d]: (%s) err=%d (%s).",
Pierangelo Masarati's avatar
Pierangelo Masarati committed
762
				i, isroot ? op->o_bd->be_rootdn.bv_val : "anonymous",
763
				rc, ldap_err2string( rc ) );
764
765
766
			Debug( LDAP_DEBUG_ANY,
				"%s %s\n",
				op->o_log_prefix, buf, 0 );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
767
768
769
770
771
772
773
774

			/*
			 * null cred bind should always succeed
			 * as anonymous, so a failure means
			 * the target is no longer candidate possibly
			 * due to technical reasons (remote host down?)
			 * so better clear the handle
			 */
775
776
			/* leave the target candidate, but record the error for later use */
			candidates[ i ].sr_err = rc;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
777
778
779
780
			if ( META_BACK_ONERR_STOP( mi ) ) {
				bound = 0;
				goto done;
			}
781

Pierangelo Masarati's avatar
Pierangelo Masarati committed
782
783
784
			continue;
		} /* else */
		
785
786
787
788
		Debug( LDAP_DEBUG_TRACE,
			"%s meta_back_dobind[%d]: "
			"(%s)\n",
			op->o_log_prefix, i,
Pierangelo Masarati's avatar
Pierangelo Masarati committed
789
			isroot ? op->o_bd->be_rootdn.bv_val : "anonymous" );
790

791
792
		ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
		LDAP_BACK_CONN_BINDING_CLEAR( msc );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
793
		if ( isroot ) {
794
795
796
797
			LDAP_BACK_CONN_ISBOUND_SET( msc );
		} else {
			LDAP_BACK_CONN_ISANON_SET( msc );
		}
798
		ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
799
800
801
		++bound;
	}

802
done:;
803
804
	Debug( LDAP_DEBUG_TRACE,
		"%s meta_back_dobind: conn=%ld bound=%d\n",
805
		op->o_log_prefix, LDAP_BACK_PCONN_ID( mc->mc_conn ), bound );
806

Pierangelo Masarati's avatar
Pierangelo Masarati committed
807
808
809
	if ( bound == 0 ) {
		meta_back_release_conn( op, mc );

810
send_err:;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
811
812
813
814
815
		if ( sendok & LDAP_BACK_SENDERR ) {
			if ( rs->sr_err == LDAP_SUCCESS ) {
				rs->sr_err = LDAP_BUSY;
			}
			send_ldap_result( op, rs );
816
		}
817
818

		return 0;
819
820
	}

821
	return ( bound > 0 );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
822
823
}

824
/*
825
 * meta_back_default_rebind
826
827
828
829
 *
 * This is a callback used for chasing referrals using the same
 * credentials as the original user on this session.
 */
830
int 
831
meta_back_default_rebind(
832
833
834
835
836
	LDAP			*ld,
	LDAP_CONST char		*url,
	ber_tag_t		request,
	ber_int_t		msgid,
	void			*params )
837
{
838
	metasingleconn_t	*msc = ( metasingleconn_t * )params;
839

840
841
	return ldap_sasl_bind_s( ld, msc->msc_bound_ndn.bv_val,
			LDAP_SASL_SIMPLE, &msc->msc_cred,
842
			NULL, NULL, NULL );
843
844
}

845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
/*
 * meta_back_default_urllist
 *
 * This is a callback used for mucking with the urllist
 */
int 
meta_back_default_urllist(
	LDAP		*ld,
	LDAPURLDesc	**urllist,
	LDAPURLDesc	**url,
	void		*params )
{
	metatarget_t	*mt = (metatarget_t *)params;
	LDAPURLDesc	**urltail;

	if ( urllist == url ) {
		return LDAP_SUCCESS;
	}

	for ( urltail = &(*url)->lud_next; *urltail; urltail = &(*urltail)->lud_next )
		/* count */ ;

	*urltail = *urllist;
	*urllist = *url;
	*url = NULL;

	ldap_pvt_thread_mutex_lock( &mt->mt_uri_mutex );
	if ( mt->mt_uri ) {
		ch_free( mt->mt_uri );
	}

	ldap_get_option( ld, LDAP_OPT_URI, (void *)&mt->mt_uri );
	ldap_pvt_thread_mutex_unlock( &mt->mt_uri_mutex );

	return LDAP_SUCCESS;
}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
882
883
884
885
/*
 * FIXME: error return must be handled in a cleaner way ...
 */
int
886
meta_back_op_result(
887
	metaconn_t	*mc,
888
889
890
	Operation	*op,
	SlapReply	*rs,
	int		candidate )
Pierangelo Masarati's avatar
Pierangelo Masarati committed
891
{
892
893
	metainfo_t		*mi = ( metainfo_t * )op->o_bd->be_private;

894
895
	int			i,
				rerr = LDAP_SUCCESS;
896
	char			*rmsg = NULL,
897
898
				*rmatch = NULL;
	const char		*save_rmsg = NULL,
899
				*save_rmatch = NULL;
900
	void			*rmatch_ctx = NULL;
901

902
903
	assert( mc != NULL );

904
	if ( candidate != META_TARGET_NONE ) {
905
		metasingleconn_t	*msc = &mc->mc_conns[ candidate ];
906

907
908
		rs->sr_err = LDAP_SUCCESS;

909
		ldap_get_option( msc->msc_ld, LDAP_OPT_ERROR_NUMBER, &rs->sr_err );
910
		if ( rs->sr_err != LDAP_SUCCESS ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
911
912
913
914
915
916
			/*
			 * better check the type of error. In some cases
			 * (search ?) it might be better to return a
			 * success if at least one of the targets gave
			 * positive result ...
			 */
917
			ldap_get_option( msc->msc_ld,
918
					LDAP_OPT_ERROR_STRING, &rmsg );
919
920
921
922
923
			if ( rmsg != NULL && rmsg[ 0 ] == '\0' ) {
				ldap_memfree( rmsg );
				rmsg = NULL;
			}

924
			ldap_get_option( msc->msc_ld,
925
					LDAP_OPT_MATCHED_DN, &rmatch );
926
927
928
			if ( rmatch != NULL && rmatch[ 0 ] == '\0' ) {
				ldap_memfree( rmatch );
				rmatch = NULL;
929
			}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
930

931
932
			rerr = rs->sr_err = slap_map_api2result( rs );

933
934
935
936
			Debug(LDAP_DEBUG_ANY,
					"==> meta_back_op_result: target"
					" <%d> sending msg \"%s\""
					" (matched \"%s\")\n", 
937
938
939
					candidate, ( rmsg ? rmsg : "" ),
					( rmatch ? rmatch : "" ) );
		}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
940

941
	} else {
942
943
944
945
		for ( i = 0; i < mi->mi_ntargets; i++ ) {
			metasingleconn_t	*msc = &mc->mc_conns[ i ];
			char			*msg = NULL;
			char			*match = NULL;
946
947
948

			rs->sr_err = LDAP_SUCCESS;

949
			ldap_get_option( msc->msc_ld, LDAP_OPT_ERROR_NUMBER, &rs->sr_err );
950
951
952
953
954
955
956
			if ( rs->sr_err != LDAP_SUCCESS ) {
				/*
				 * better check the type of error. In some cases
				 * (search ?) it might be better to return a
				 * success if at least one of the targets gave
				 * positive result ...
				 */
957
				ldap_get_option( msc->msc_ld,
958
						LDAP_OPT_ERROR_STRING, &msg );
959
960
961
962
963
				if ( msg != NULL && msg[ 0 ] == '\0' ) {
					ldap_memfree( msg );
					msg = NULL;
				}

964
				ldap_get_option( msc->msc_ld,
965
						LDAP_OPT_MATCHED_DN, &match );
966
967
968
969
970
				if ( match != NULL && match[ 0 ] == '\0' ) {
					ldap_memfree( match );
					match = NULL;
				}

971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
				rs->sr_err = slap_map_api2result( rs );
	
				Debug(LDAP_DEBUG_ANY,
						"==> meta_back_op_result: target"
						" <%d> sending msg \"%s\""
						" (matched \"%s\")\n", 
						i, ( msg ? msg : "" ),
						( match ? match : "" ) );
	
				/*
				 * FIXME: need to rewrite "match" (need rwinfo)
				 */
				switch ( rs->sr_err ) {
				default:
					rerr = rs->sr_err;
986
987
988
989
990
991
					if ( msg != NULL ) {
						if ( rmsg ) {
							ldap_memfree( rmsg );
						}
						rmsg = msg;
						msg = NULL;
992
					}
993
994
995
996
997
998
					if ( match != NULL ) {
						if ( rmatch ) {
							ldap_memfree( rmatch );
						}
						rmatch = match;
						match = NULL;
999
1000
					}
					break;
1001
				}
1002
1003
1004
1005

				if ( msg ) {
					ldap_memfree( msg );
				}
1006
1007
	
				if ( match ) {
1008
					ldap_memfree( match );
Pierangelo Masarati's avatar