bind.c 60 KB
Newer Older
1
/* bind.c - ldap backend bind function */
2
/* $OpenLDAP$ */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
3
4
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
5
 * Copyright 1999-2007 The OpenLDAP Foundation.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
6
7
 * Portions Copyright 2000-2003 Pierangelo Masarati.
 * Portions Copyright 1999-2003 Howard Chu.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
8
9
10
11
12
13
14
15
16
17
18
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted only as authorized by the OpenLDAP
 * Public License.
 *
 * A copy of this license is available in the file LICENSE in the
 * top-level directory of the distribution or, alternatively, at
 * <http://www.OpenLDAP.org/license.html>.
 */
/* ACKNOWLEDGEMENTS:
Kurt Zeilenga's avatar
Kurt Zeilenga committed
19
 * This work was initially developed by Howard Chu for inclusion
Kurt Zeilenga's avatar
Kurt Zeilenga committed
20
21
 * in OpenLDAP Software and subsequently enhanced by Pierangelo
 * Masarati.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
22
 */
23
24
25
26
27

#include "portable.h"

#include <stdio.h>

Kurt Zeilenga's avatar
Kurt Zeilenga committed
28
#include <ac/errno.h>
29
30
31
#include <ac/socket.h>
#include <ac/string.h>

32
#define AVL_INTERNAL
33
34
#include "slap.h"
#include "back-ldap.h"
35
36
#undef ldap_debug	/* silence a warning in ldap-int.h */
#include "../../../libraries/libldap/ldap-int.h"
37

38
#include "lutil_ldap.h"
39
40

#define LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ	"2.16.840.1.113730.3.4.12"
Pierangelo Masarati's avatar
Pierangelo Masarati committed
41

42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#if LDAP_BACK_PRINT_CONNTREE > 0
static void
ldap_back_ravl_print( Avlnode *root, int depth )
{
	int		i;
	ldapconn_t	*lc;
	
	if ( root == 0 ) {
		return;
	}
	
	ldap_back_ravl_print( root->avl_right, depth+1 );
	
	for ( i = 0; i < depth; i++ ) {
		fprintf( stderr, "-" );
	}

	lc = root->avl_data;
	fprintf( stderr, "lc=%p local=\"%s\" conn=%p %s refcnt=%d flags=0x%08x\n",
		(void *)lc,
		lc->lc_local_ndn.bv_val ? lc->lc_local_ndn.bv_val : "",
		(void *)lc->lc_conn,
		avl_bf2str( root->avl_bf ), lc->lc_refcnt, lc->lc_lcflags );
	
	ldap_back_ravl_print( root->avl_left, depth+1 );
}

static char* priv2str[] = {
	"privileged",
	"privileged/TLS",
	"anonymous",
	"anonymous/TLS",
	"bind",
	"bind/TLS",
	NULL
};

void
ldap_back_print_conntree( ldapinfo_t *li, char *msg )
{
	int	c;

	fprintf( stderr, "========> %s\n", msg );

	for ( c = LDAP_BACK_PCONN_FIRST; c < LDAP_BACK_PCONN_LAST; c++ ) {
		int		i = 0;
		ldapconn_t	*lc;

		fprintf( stderr, "  %s[%d]\n", priv2str[ c ], li->li_conn_priv[ c ].lic_num );

		LDAP_TAILQ_FOREACH( lc, &li->li_conn_priv[ c ].lic_priv, lc_q )
		{
			fprintf( stderr, "    [%d] lc=%p local=\"%s\" conn=%p refcnt=%d flags=0x%08x\n",
				i,
				(void *)lc,
				lc->lc_local_ndn.bv_val ? lc->lc_local_ndn.bv_val : "",
				(void *)lc->lc_conn, lc->lc_refcnt, lc->lc_lcflags );
			i++;
		}
	}
	
	if ( li->li_conninfo.lai_tree == 0 ) {
		fprintf( stderr, "\t(empty)\n" );

	} else {
		ldap_back_ravl_print( li->li_conninfo.lai_tree, 0 );
	}
	
	fprintf( stderr, "<======== %s\n", msg );
}
#endif /* LDAP_BACK_PRINT_CONNTREE */

static int
115
ldap_back_freeconn( ldapinfo_t *li, ldapconn_t *lc, int dolock );
116
117
118
119

static ldapconn_t *
ldap_back_getconn( Operation *op, SlapReply *rs, ldap_back_send_t sendok,
	struct berval *binddn, struct berval *bindcred );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
120

121
122
123
static int
ldap_back_is_proxy_authz( Operation *op, SlapReply *rs, ldap_back_send_t sendok,
	struct berval *binddn, struct berval *bindcred );
124

125
static int
126
127
ldap_back_proxy_authz_bind( ldapconn_t *lc, Operation *op, SlapReply *rs,
	ldap_back_send_t sendok, struct berval *binddn, struct berval *bindcred );
128

Kurt Zeilenga's avatar
Kurt Zeilenga committed
129
static int
130
ldap_back_prepare_conn( ldapconn_t *lc, Operation *op, SlapReply *rs,
131
	ldap_back_send_t sendok );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
132

Pierangelo Masarati's avatar
Pierangelo Masarati committed
133
134
135
static int
ldap_back_conndnlc_cmp( const void *c1, const void *c2 );

136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
ldapconn_t *
ldap_back_conn_delete( ldapinfo_t *li, ldapconn_t *lc )
{
	if ( LDAP_BACK_PCONN_ISPRIV( lc ) ) {
		if ( LDAP_BACK_CONN_CACHED( lc ) ) {
			assert( lc->lc_q.tqe_prev != NULL );
			assert( li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num > 0 );
			li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num--;
			LDAP_TAILQ_REMOVE( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv, lc, lc_q );
			LDAP_TAILQ_ENTRY_INIT( lc, lc_q );
			LDAP_BACK_CONN_CACHED_CLEAR( lc );

		} else {
			assert( LDAP_BACK_CONN_TAINTED( lc ) );
			assert( lc->lc_q.tqe_prev == NULL );
		}

	} else {
		ldapconn_t	*tmplc = NULL;

		if ( LDAP_BACK_CONN_CACHED( lc ) ) {
			assert( !LDAP_BACK_CONN_TAINTED( lc ) );
			tmplc = avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc,
				ldap_back_conndnlc_cmp );
			assert( tmplc == lc );
			LDAP_BACK_CONN_CACHED_CLEAR( lc );
		}

		assert( LDAP_BACK_CONN_TAINTED( lc ) || tmplc == lc );
	}

	return lc;
}

170
int
171
ldap_back_bind( Operation *op, SlapReply *rs )
172
{
173
174
	ldapinfo_t		*li = (ldapinfo_t *) op->o_bd->be_private;
	ldapconn_t		*lc;
175

176
177
178
	int			rc = 0;
	ber_int_t		msgid;
	ldap_back_send_t	retrying = LDAP_BACK_RETRYING;
179

180
	lc = ldap_back_getconn( op, rs, LDAP_BACK_BIND_SERR, NULL, NULL );
181
	if ( !lc ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
182
		return rs->sr_err;
183
184
	}

185
186
	/* we can do (almost) whatever we want with this conn,
	 * because either it's temporary, or it's marked as binding */
187
188
189
	if ( !BER_BVISNULL( &lc->lc_bound_ndn ) ) {
		ch_free( lc->lc_bound_ndn.bv_val );
		BER_BVZERO( &lc->lc_bound_ndn );
190
	}
191
192
193
194
195
	if ( !BER_BVISNULL( &lc->lc_cred ) ) {
		memset( lc->lc_cred.bv_val, 0, lc->lc_cred.bv_len );
		ch_free( lc->lc_cred.bv_val );
		BER_BVZERO( &lc->lc_cred );
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
196
	LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
197

198
retry:;
199
	/* method is always LDAP_AUTH_SIMPLE if we got here */
200
201
202
	rs->sr_err = ldap_sasl_bind( lc->lc_ld, op->o_req_dn.bv_val,
			LDAP_SASL_SIMPLE,
			&op->orb_cred, op->o_ctrls, NULL, &msgid );
203
204
205
206
207
208
209
210
211
212
213
	/* FIXME: should we always retry, or only when piping the bind
	 * in the "override" connection pool? */
	rc = ldap_back_op_result( lc, op, rs, msgid,
		li->li_timeout[ SLAP_OP_BIND ],
		LDAP_BACK_BIND_SERR | retrying );
	if ( rc == LDAP_UNAVAILABLE && retrying ) {
		retrying &= ~LDAP_BACK_RETRYING;
		if ( ldap_back_retry( &lc, op, rs, LDAP_BACK_BIND_SERR ) ) {
			goto retry;
		}
	}
214
215

	if ( rc == LDAP_SUCCESS ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
216
217
		/* If defined, proxyAuthz will be used also when
		 * back-ldap is the authorizing backend; for this
218
219
220
221
		 * purpose, after a successful bind the connection
		 * is left for further binds, and further operations 
		 * on this client connection will use a default
		 * connection with identity assertion */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
222
		/* NOTE: use with care */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
223
		if ( li->li_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) {
224
			ldap_back_release_conn( li, lc );
225
			return( rc );
226
		}
227

228
229
		/* rebind is now done inside ldap_back_proxy_authz_bind()
		 * in case of success */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
230
		LDAP_BACK_CONN_ISBOUND_SET( lc );
231
		ber_dupbv( &lc->lc_bound_ndn, &op->o_req_ndn );
232

233
234
235
236
237
		if ( !BER_BVISNULL( &lc->lc_cred ) ) {
			memset( lc->lc_cred.bv_val, 0,
					lc->lc_cred.bv_len );
		}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
238
		if ( LDAP_BACK_SAVECRED( li ) ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
239
			ber_bvreplace( &lc->lc_cred, &op->orb_cred );
240
241
242
243
			ldap_set_rebind_proc( lc->lc_ld, li->li_rebind_f, lc );

		} else {
			lc->lc_cred.bv_len = 0;
244
		}
245
246
	}

247
	/* must re-insert if local DN changed as result of bind */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
248
	if ( !LDAP_BACK_CONN_ISBOUND( lc )
249
250
		|| ( !dn_match( &op->o_req_ndn, &lc->lc_local_ndn )
			&& !LDAP_BACK_PCONN_ISPRIV( lc ) ) )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
251
	{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
252
		int		lerr = -1;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
253
		ldapconn_t	*tmplc;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
254

Kurt Zeilenga's avatar
Kurt Zeilenga committed
255
256
		/* wait for all other ops to release the connection */
retry_lock:;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
257
		ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
258
		if ( lc->lc_refcnt > 1 ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
259
			ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
260
261
262
263
			ldap_pvt_thread_yield();
			goto retry_lock;
		}

264
265
266
267
#if LDAP_BACK_PRINT_CONNTREE > 0
		ldap_back_print_conntree( li, ">>> ldap_back_bind" );
#endif /* LDAP_BACK_PRINT_CONNTREE */

Kurt Zeilenga's avatar
Kurt Zeilenga committed
268
		assert( lc->lc_refcnt == 1 );
269
		ldap_back_conn_delete( li, lc );
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293

		/* delete all cached connections with the current connection */
		if ( LDAP_BACK_SINGLECONN( li ) ) {
			while ( ( tmplc = avl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc, ldap_back_conn_cmp ) ) != NULL )
			{
				Debug( LDAP_DEBUG_TRACE,
					"=>ldap_back_bind: destroying conn %ld (refcnt=%u)\n",
					LDAP_BACK_PCONN_ID( lc ), lc->lc_refcnt, 0 );

				if ( tmplc->lc_refcnt != 0 ) {
					/* taint it */
					LDAP_BACK_CONN_TAINTED_SET( tmplc );
					LDAP_BACK_CONN_CACHED_CLEAR( tmplc );

				} else {
					/*
					 * Needs a test because the handler may be corrupted,
					 * and calling ldap_unbind on a corrupted header results
					 * in a segmentation fault
					 */
					ldap_back_conn_free( tmplc );
				}
			}
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
294

Kurt Zeilenga's avatar
Kurt Zeilenga committed
295
296
		if ( LDAP_BACK_CONN_ISBOUND( lc ) ) {
			ber_bvreplace( &lc->lc_local_ndn, &op->o_req_ndn );
297
298
299
			if ( be_isroot_dn( op->o_bd, &op->o_req_ndn ) ) {
				LDAP_BACK_PCONN_ROOTDN_SET( lc, op );
			}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
300
301
302
303
			lerr = avl_insert( &li->li_conninfo.lai_tree, (caddr_t)lc,
				ldap_back_conndn_cmp, ldap_back_conndn_dup );
		}

304
305
306
307
#if LDAP_BACK_PRINT_CONNTREE > 0
		ldap_back_print_conntree( li, "<<< ldap_back_bind" );
#endif /* LDAP_BACK_PRINT_CONNTREE */
	
Kurt Zeilenga's avatar
Kurt Zeilenga committed
308
		ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
309
310
		switch ( lerr ) {
		case 0:
311
			LDAP_BACK_CONN_CACHED_SET( lc );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
312
313
314
315
316
317
			break;

		case -1:
			/* duplicate; someone else successfully bound
			 * on the same connection with the same identity;
			 * we can do this because lc_refcnt == 1 */
318
			ldap_back_conn_free( lc );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
319
			lc = NULL;
320
		}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
321
	}
322

Kurt Zeilenga's avatar
Kurt Zeilenga committed
323
	if ( lc != NULL ) {
324
		ldap_back_release_conn( li, lc );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
325
326
	}

327
328
329
330
	return( rc );
}

/*
331
 * ldap_back_conndn_cmp
332
 *
333
334
335
 * compares two ldapconn_t based on the value of the conn pointer
 * and of the local DN; used by avl stuff for insert, lookup
 * and direct delete
336
337
 */
int
338
ldap_back_conndn_cmp( const void *c1, const void *c2 )
339
{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
340
341
	const ldapconn_t	*lc1 = (const ldapconn_t *)c1;
	const ldapconn_t	*lc2 = (const ldapconn_t *)c2;
342
	int rc;
343

344
	/* If local DNs don't match, it is definitely not a match */
345
346
347
348
349
350
	/* For shared sessions, conn is NULL. Only explicitly
	 * bound sessions will have non-NULL conn.
	 */
	rc = SLAP_PTRCMP( lc1->lc_conn, lc2->lc_conn );
	if ( rc == 0 ) {
		rc = ber_bvcmp( &lc1->lc_local_ndn, &lc2->lc_local_ndn );
351
	}
352

353
354
355
	return rc;
}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
/*
 * ldap_back_conndnlc_cmp
 *
 * compares two ldapconn_t based on the value of the conn pointer,
 * the local DN and the lc pointer; used by avl stuff for insert, lookup
 * and direct delete
 */
static int
ldap_back_conndnlc_cmp( const void *c1, const void *c2 )
{
	const ldapconn_t	*lc1 = (const ldapconn_t *)c1;
	const ldapconn_t	*lc2 = (const ldapconn_t *)c2;
	int rc;

	/* If local DNs don't match, it is definitely not a match */
	/* For shared sessions, conn is NULL. Only explicitly
	 * bound sessions will have non-NULL conn.
	 */
	rc = SLAP_PTRCMP( lc1->lc_conn, lc2->lc_conn );
	if ( rc == 0 ) {
		rc = ber_bvcmp( &lc1->lc_local_ndn, &lc2->lc_local_ndn );
		if ( rc == 0 ) {
			rc = SLAP_PTRCMP( lc1, lc2 );
		}
	}

	return rc;
}

385
386
387
388
389
390
391
392
393
394
395
396
/*
 * ldap_back_conn_cmp
 *
 * compares two ldapconn_t based on the value of the conn pointer;
 * used by avl stuff for delete of all conns with the same connid
 */
int
ldap_back_conn_cmp( const void *c1, const void *c2 )
{
	const ldapconn_t	*lc1 = (const ldapconn_t *)c1;
	const ldapconn_t	*lc2 = (const ldapconn_t *)c2;

397
398
399
	/* For shared sessions, conn is NULL. Only explicitly
	 * bound sessions will have non-NULL conn.
	 */
400
	return SLAP_PTRCMP( lc1->lc_conn, lc2->lc_conn );
401
402
403
}

/*
404
 * ldap_back_conndn_dup
405
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
406
 * returns -1 in case a duplicate ldapconn_t has been inserted;
407
408
409
 * used by avl stuff
 */
int
410
ldap_back_conndn_dup( void *c1, void *c2 )
411
{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
412
413
	ldapconn_t	*lc1 = (ldapconn_t *)c1;
	ldapconn_t	*lc2 = (ldapconn_t *)c2;
414

415
	/* Cannot have more than one shared session with same DN */
416
417
	if ( lc1->lc_conn == lc2->lc_conn &&
		dn_match( &lc1->lc_local_ndn, &lc2->lc_local_ndn ) )
418
419
420
	{
		return -1;
	}
421
422
		
	return 0;
423
}
424

425
static int
426
ldap_back_freeconn( ldapinfo_t *li, ldapconn_t *lc, int dolock )
427
{
428
429
	if ( dolock ) {
		ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
430
	}
431

432
433
434
#if LDAP_BACK_PRINT_CONNTREE > 0
	ldap_back_print_conntree( li, ">>> ldap_back_freeconn" );
#endif /* LDAP_BACK_PRINT_CONNTREE */
435

436
	(void)ldap_back_conn_delete( li, lc );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
437

Pierangelo Masarati's avatar
Pierangelo Masarati committed
438
	if ( lc->lc_refcnt == 0 ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
439
440
		ldap_back_conn_free( (void *)lc );
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
441

442
443
444
445
#if LDAP_BACK_PRINT_CONNTREE > 0
	ldap_back_print_conntree( li, "<<< ldap_back_freeconn" );
#endif /* LDAP_BACK_PRINT_CONNTREE */

Kurt Zeilenga's avatar
Kurt Zeilenga committed
446
447
448
	if ( dolock ) {
		ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
	}
449

Kurt Zeilenga's avatar
Kurt Zeilenga committed
450
	return 0;
451
452
}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
453
#ifdef HAVE_TLS
Kurt Zeilenga's avatar
Kurt Zeilenga committed
454
static int
Kurt Zeilenga's avatar
Kurt Zeilenga committed
455
456
457
458
459
460
ldap_back_start_tls(
	LDAP		*ld,
	int		protocol,
	int		*is_tls,
	const char	*url,
	unsigned	flags,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
461
	int		retries,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
462
	const char	**text )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
463
{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
464
	int		rc = LDAP_SUCCESS;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
465

Kurt Zeilenga's avatar
Kurt Zeilenga committed
466
	/* start TLS ("tls-[try-]{start,propagate}" statements) */
467
	if ( ( LDAP_BACK_USE_TLS_F( flags ) || ( *is_tls && LDAP_BACK_PROPAGATE_TLS_F( flags ) ) )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
468
				&& !ldap_is_ldaps_url( url ) )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
469
	{
470
#ifdef SLAP_STARTTLS_ASYNCHRONOUS
Kurt Zeilenga's avatar
Kurt Zeilenga committed
471
472
473
474
475
476
		/*
		 * use asynchronous StartTLS
		 * in case, chase referral (not implemented yet)
		 */
		int		msgid;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
477
478
479
480
481
482
		if ( protocol == 0 ) {
			ldap_get_option( ld, LDAP_OPT_PROTOCOL_VERSION,
					(void *)&protocol );
		}

		if ( protocol < LDAP_VERSION3 ) {
483
484
485
486
487
488
489
			/* we should rather bail out... */
			rc = LDAP_UNWILLING_TO_PERFORM;
			*text = "invalid protocol version";
		}

		if ( rc == LDAP_SUCCESS ) {
			rc = ldap_start_tls( ld, NULL, NULL, &msgid );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
490
491
492
		}

		if ( rc == LDAP_SUCCESS ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
493
			LDAPMessage	*res = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
494
495
496
			struct timeval	tv;

			LDAP_BACK_TV_SET( &tv );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
497
498
499
500

retry:;
			rc = ldap_result( ld, msgid, LDAP_MSG_ALL, &tv, &res );
			if ( rc < 0 ) {
501
				rc = LDAP_UNAVAILABLE;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
502
503

			} else if ( rc == 0 ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
504
505
506
507
508
509
				if ( retries != LDAP_BACK_RETRY_NEVER ) {
					ldap_pvt_thread_yield();
					if ( retries > 0 ) {
						retries--;
					}
					LDAP_BACK_TV_SET( &tv );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
510
511
					goto retry;
				}
512
				rc = LDAP_UNAVAILABLE;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
513
514
515
516

			} else if ( rc == LDAP_RES_EXTENDED ) {
				struct berval	*data = NULL;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
517
				rc = ldap_parse_extended_result( ld, res,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
518
						NULL, &data, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
519
				if ( rc == LDAP_SUCCESS ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
520
521
522
523
524
525
					int err;
					rc = ldap_parse_result( ld, res, &err,
						NULL, NULL, NULL, NULL, 1 );
					if ( rc == LDAP_SUCCESS ) {
						rc = err;
					}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
526
527
528
529
530
531
					res = NULL;
					
					/* FIXME: in case a referral 
					 * is returned, should we try
					 * using it instead of the 
					 * configured URI? */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
532
533
					if ( rc == LDAP_SUCCESS ) {
						rc = ldap_install_tls( ld );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
534

Kurt Zeilenga's avatar
Kurt Zeilenga committed
535
					} else if ( rc == LDAP_REFERRAL ) {
536
						rc = LDAP_UNWILLING_TO_PERFORM;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
537
						*text = "unwilling to chase referral returned by Start TLS exop";
Kurt Zeilenga's avatar
Kurt Zeilenga committed
538
539
540
541
542
543
544
545
546
547
548
					}

					if ( data ) {
						if ( data->bv_val ) {
							ber_memfree( data->bv_val );
						}
						ber_memfree( data );
					}
				}

			} else {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
549
				rc = LDAP_OTHER;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
550
551
552
553
554
555
			}

			if ( res != NULL ) {
				ldap_msgfree( res );
			}
		}
556
#else /* ! SLAP_STARTTLS_ASYNCHRONOUS */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
557
558
559
		/*
		 * use synchronous StartTLS
		 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
560
		rc = ldap_start_tls_s( ld, NULL, NULL );
561
#endif /* ! SLAP_STARTTLS_ASYNCHRONOUS */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
562

Kurt Zeilenga's avatar
Kurt Zeilenga committed
563
564
565
566
		/* if StartTLS is requested, only attempt it if the URL
		 * is not "ldaps://"; this may occur not only in case
		 * of misconfiguration, but also when used in the chain 
		 * overlay, where the "uri" can be parsed out of a referral */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
567
568
569
570
571
572
573
574
575
		switch ( rc ) {
		case LDAP_SUCCESS:
			*is_tls = 1;
			break;

		case LDAP_SERVER_DOWN:
			break;

		default:
576
			if ( LDAP_BACK_TLS_CRITICAL_F( flags ) ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
577
578
579
580
581
582
583
584
				*text = "could not start TLS";
				break;
			}

			/* in case Start TLS is not critical */
			*is_tls = 0;
			rc = LDAP_SUCCESS;
			break;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
585
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
586

Kurt Zeilenga's avatar
Kurt Zeilenga committed
587
588
589
590
591
592
593
594
595
	} else {
		*is_tls = 0;
	}

	return rc;
}
#endif /* HAVE_TLS */

static int
596
ldap_back_prepare_conn( ldapconn_t *lc, Operation *op, SlapReply *rs, ldap_back_send_t sendok )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
597
{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
598
	ldapinfo_t	*li = (ldapinfo_t *)op->o_bd->be_private;
599
	int		version;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
600
601
602
	LDAP		*ld = NULL;
#ifdef HAVE_TLS
	int		is_tls = op->o_conn->c_is_tls;
603
	time_t		lc_time = (time_t)(-1);
Kurt Zeilenga's avatar
Kurt Zeilenga committed
604
605
#endif /* HAVE_TLS */

606
	ldap_pvt_thread_mutex_lock( &li->li_uri_mutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
607
	rs->sr_err = ldap_initialize( &ld, li->li_uri );
608
	ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
609
610
611
612
613
614
615
	if ( rs->sr_err != LDAP_SUCCESS ) {
		goto error_return;
	}

	/* Set LDAP version. This will always succeed: If the client
	 * bound with a particular version, then so can we.
	 */
616
617
618
619
620
621
622
	if ( li->li_version != 0 ) {
		version = li->li_version;

	} else if ( op->o_protocol != 0 ) {
		version = op->o_protocol;

	} else {
623
		/* assume it's an internal op; set to LDAPv3 */
624
		version = LDAP_VERSION3;
625
	}
626
	ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, (const void *)&version );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
627

Kurt Zeilenga's avatar
Kurt Zeilenga committed
628
629
630
	/* automatically chase referrals ("chase-referrals [{yes|no}]" statement) */
	ldap_set_option( ld, LDAP_OPT_REFERRALS,
		LDAP_BACK_CHASE_REFERRALS( li ) ? LDAP_OPT_ON : LDAP_OPT_OFF );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
631

Pierangelo Masarati's avatar
Pierangelo Masarati committed
632
633
634
635
636
637
638
639
	if ( li->li_network_timeout > 0 ) {
		struct timeval		tv;

		tv.tv_sec = li->li_network_timeout;
		tv.tv_usec = 0;
		ldap_set_option( ld, LDAP_OPT_NETWORK_TIMEOUT, (const void *)&tv );
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
640
#ifdef HAVE_TLS
641
	ldap_pvt_thread_mutex_lock( &li->li_uri_mutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
642
	rs->sr_err = ldap_back_start_tls( ld, op->o_protocol, &is_tls,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
643
			li->li_uri, li->li_flags, li->li_nretries, &rs->sr_text );
644
	ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
645
646
	if ( rs->sr_err != LDAP_SUCCESS ) {
		ldap_unbind_ext( ld, NULL, NULL );
647
		rs->sr_text = "Start TLS failed";
Kurt Zeilenga's avatar
Kurt Zeilenga committed
648
		goto error_return;
649
650
651
652

	} else if ( li->li_idle_timeout ) {
		/* only touch when activity actually took place... */
		lc_time = op->o_time;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
653
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
654
#endif /* HAVE_TLS */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
655

656
657
	lc->lc_ld = ld;
	lc->lc_refcnt = 1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
658
#ifdef HAVE_TLS
Kurt Zeilenga's avatar
Kurt Zeilenga committed
659
	if ( is_tls ) {
660
		LDAP_BACK_CONN_ISTLS_SET( lc );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
661
	} else {
662
		LDAP_BACK_CONN_ISTLS_CLEAR( lc );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
663
	}
664
	if ( lc_time != (time_t)(-1) ) {
665
		lc->lc_time = lc_time;
666
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
667
#endif /* HAVE_TLS */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
668
669
670
671
672
673

error_return:;
	if ( rs->sr_err != LDAP_SUCCESS ) {
		rs->sr_err = slap_map_api2result( rs );
		if ( sendok & LDAP_BACK_SENDERR ) {
			if ( rs->sr_text == NULL ) {
674
				rs->sr_text = "Proxy connection initialization failed";
Kurt Zeilenga's avatar
Kurt Zeilenga committed
675
676
677
			}
			send_ldap_result( op, rs );
		}
678
679
680

	} else {
		if ( li->li_conn_ttl > 0 ) {
681
			lc->lc_create_time = op->o_time;
682
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
683
684
685
686
687
	}

	return rs->sr_err;
}

688
689
690
691
692
693
694
static ldapconn_t *
ldap_back_getconn(
	Operation		*op,
	SlapReply		*rs,
	ldap_back_send_t	sendok,
	struct berval		*binddn,
	struct berval		*bindcred )
695
{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
696
	ldapinfo_t	*li = (ldapinfo_t *)op->o_bd->be_private;
697
	ldapconn_t	*lc = NULL,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
698
			lc_curr = { 0 };
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
	int		refcnt = 1,
			lookupconn = !( sendok & LDAP_BACK_BINDING );

	/* if the server is quarantined, and
	 * - the current interval did not expire yet, or
	 * - no more retries should occur,
	 * don't return the connection */
	if ( li->li_isquarantined ) {
		slap_retry_info_t	*ri = &li->li_quarantine;
		int			dont_retry = 1;

		if ( li->li_quarantine.ri_interval ) {
			ldap_pvt_thread_mutex_lock( &li->li_quarantine_mutex );
			if ( li->li_isquarantined == LDAP_BACK_FQ_YES ) {
				dont_retry = ( ri->ri_num[ ri->ri_idx ] == SLAP_RETRYNUM_TAIL
					|| slap_get_time() < ri->ri_last + ri->ri_interval[ ri->ri_idx ] );
				if ( !dont_retry ) {
					Debug( LDAP_DEBUG_ANY,
						"%s: ldap_back_getconn quarantine "
						"retry block #%d try #%d.\n",
						op->o_log_prefix, ri->ri_idx, ri->ri_count );
					li->li_isquarantined = LDAP_BACK_FQ_RETRYING;
				}
			}
			ldap_pvt_thread_mutex_unlock( &li->li_quarantine_mutex );
		}

		if ( dont_retry ) {
			rs->sr_err = LDAP_UNAVAILABLE;
			if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) {
729
				rs->sr_text = "Target is quarantined";
730
731
732
733
734
				send_ldap_result( op, rs );
			}
			return NULL;
		}
	}
735

736
	/* Internal searches are privileged and shared. So is root. */
737
	if ( op->o_do_not_cache || be_isroot( op ) ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
738
		LDAP_BACK_CONN_ISPRIV_SET( &lc_curr );
739
		lc_curr.lc_local_ndn = op->o_bd->be_rootndn;
740
		LDAP_BACK_PCONN_ROOTDN_SET( &lc_curr, op );
741

742
	} else {
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
		struct berval	tmpbinddn,
				tmpbindcred,
				save_o_dn,
				save_o_ndn;
		int		isproxyauthz;

		/* need cleanup */
		if ( binddn == NULL ) {
			binddn = &tmpbinddn;
		}	
		if ( bindcred == NULL ) {
			bindcred = &tmpbindcred;
		}
		if ( op->o_tag == LDAP_REQ_BIND ) {
			save_o_dn = op->o_dn;
			save_o_ndn = op->o_ndn;
			op->o_dn = op->o_req_dn;
			op->o_ndn = op->o_req_ndn;
		}
		isproxyauthz = ldap_back_is_proxy_authz( op, rs, sendok, binddn, bindcred );
		if ( op->o_tag == LDAP_REQ_BIND ) {
			op->o_dn = save_o_dn;
			op->o_ndn = save_o_ndn;
		}
767
768
769
		if ( isproxyauthz == -1 ) {
			return NULL;
		}
770

771
		lc_curr.lc_local_ndn = op->o_ndn;
772
773
774
775
		/* Explicit binds must not be shared;
		 * however, explicit binds are piped in a special connection
		 * when idassert is to occur with "override" set */
		if ( op->o_tag == LDAP_REQ_BIND && !isproxyauthz ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
776
			lc_curr.lc_conn = op->o_conn;
777

Kurt Zeilenga's avatar
Kurt Zeilenga committed
778
		} else {
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
			if ( isproxyauthz && !( sendok & LDAP_BACK_BINDING ) ) {
				lc_curr.lc_local_ndn = *binddn;
				LDAP_BACK_PCONN_ROOTDN_SET( &lc_curr, op );
				LDAP_BACK_CONN_ISIDASSERT_SET( &lc_curr );

			} else if ( isproxyauthz && ( li->li_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) ) {
				lc_curr.lc_local_ndn = slap_empty_bv;
				LDAP_BACK_PCONN_BIND_SET( &lc_curr, op );
				LDAP_BACK_CONN_ISIDASSERT_SET( &lc_curr );
				lookupconn = 1;

			} else if ( SLAP_IS_AUTHZ_BACKEND( op ) ) {
				lc_curr.lc_conn = op->o_conn;

			} else {
				LDAP_BACK_PCONN_ANON_SET( &lc_curr, op );
			}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
796
		}
797
	}
798

799
	/* Explicit Bind requests always get their own conn */
800
	if ( lookupconn ) {
801
802
retry_lock:
		ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
		if ( LDAP_BACK_PCONN_ISPRIV( &lc_curr ) ) {
			/* lookup a conn that's not binding */
			LDAP_TAILQ_FOREACH( lc,
				&li->li_conn_priv[ LDAP_BACK_CONN2PRIV( &lc_curr ) ].lic_priv,
				lc_q )
			{
				if ( !LDAP_BACK_CONN_BINDING( lc ) && lc->lc_refcnt == 0 ) {
					break;
				}
			}

			if ( lc != NULL ) {
				if ( lc != LDAP_TAILQ_LAST( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv,
					ldapconn_t, lc_q ) )
				{
					LDAP_TAILQ_REMOVE( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv,
						lc, lc_q );
820
					LDAP_TAILQ_ENTRY_INIT( lc, lc_q );
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
					LDAP_TAILQ_INSERT_TAIL( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv,
						lc, lc_q );
				}

			} else if ( !LDAP_BACK_USE_TEMPORARIES( li )
				&& li->li_conn_priv[ LDAP_BACK_CONN2PRIV( &lc_curr ) ].lic_num == li->li_conn_priv_max )
			{
				lc = LDAP_TAILQ_FIRST( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( &lc_curr ) ].lic_priv );
			}
			
		} else {

			/* Searches for a ldapconn in the avl tree */
			lc = (ldapconn_t *)avl_find( li->li_conninfo.lai_tree, 
					(caddr_t)&lc_curr, ldap_back_conndn_cmp );
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
837

838
839
840
		if ( lc != NULL ) {
			/* Don't reuse connections while they're still binding */
			if ( LDAP_BACK_CONN_BINDING( lc ) ) {
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
				if ( !LDAP_BACK_USE_TEMPORARIES( li ) ) {
					ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );

					ldap_pvt_thread_yield();
					goto retry_lock;
				}
				lc = NULL;
			}

			if ( lc != NULL ) {
				if ( op->o_tag == LDAP_REQ_BIND ) {
					/* right now, this is the only possible case */
					assert( ( li->li_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) );
					LDAP_BACK_CONN_BINDING_SET( lc );
				}

				refcnt = ++lc->lc_refcnt;
858
859
860
			}
		}
		ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
861
	}
862
863

	/* Looks like we didn't get a bind. Open a new session... */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
864
	if ( lc == NULL ) {
865
866
867
868
869
		lc = (ldapconn_t *)ch_calloc( 1, sizeof( ldapconn_t ) );
		lc->lc_flags = li->li_flags;
		lc->lc_lcflags = lc_curr.lc_lcflags;
		if ( ldap_back_prepare_conn( lc, op, rs, sendok ) != LDAP_SUCCESS ) {
			ch_free( lc );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
870
			return NULL;
871
		}
872

873
874
875
		if ( sendok & LDAP_BACK_BINDING ) {
			LDAP_BACK_CONN_BINDING_SET( lc );
		}
876

877
878
		lc->lc_conn = lc_curr.lc_conn;
		ber_dupbv( &lc->lc_local_ndn, &lc_curr.lc_local_ndn );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
879

880
881
882
883
884
885
886
887
888
889
890
891
		/*
		 * the rationale is: connections as the rootdn are privileged,
		 * so acl_authcDN is to be used; however, in some cases
		 * one already configured identity assertion with a highly
		 * privileged idassert_authcDN, so if acl_authcDN is NULL
		 * and idassert_authcDN is not, use the second instead.
		 *
		 * might change in the future, because it's preferable
		 * to make clear what identity is being used, since
		 * the only drawback is that one risks to configure
		 * the same identity twice...
		 */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
892
		if ( LDAP_BACK_CONN_ISPRIV( &lc_curr ) ) {
893
894
895
896
897
898
899
900
			if ( BER_BVISNULL( &li->li_acl_authcDN ) && !BER_BVISNULL( &li->li_idassert_authcDN ) ) {
				ber_dupbv( &lc->lc_bound_ndn, &li->li_idassert_authcDN );
				ber_dupbv( &lc->lc_cred, &li->li_idassert_passwd );

			} else {
				ber_dupbv( &lc->lc_bound_ndn, &li->li_acl_authcDN );
				ber_dupbv( &lc->lc_cred, &li->li_acl_passwd );
			}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
901
			LDAP_BACK_CONN_ISPRIV_SET( lc );
902

903
904
905
906
907
908
909
		} else if ( LDAP_BACK_CONN_ISIDASSERT( &lc_curr ) ) {
			if ( !LDAP_BACK_PCONN_ISBIND( &lc_curr ) ) {
				ber_dupbv( &lc->lc_bound_ndn, &li->li_idassert_authcDN );
				ber_dupbv( &lc->lc_cred, &li->li_idassert_passwd );
			}
			LDAP_BACK_CONN_ISIDASSERT_SET( lc );

910
		} else {
911
912
			BER_BVZERO( &lc->lc_cred );
			BER_BVZERO( &lc->lc_bound_ndn );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
913
914
			if ( !BER_BVISEMPTY( &op->o_ndn )
				&& SLAP_IS_AUTHZ_BACKEND( op ) )
915
916
			{
				ber_dupbv( &lc->lc_bound_ndn, &op->o_ndn );
917
			}
918
		}
919

Kurt Zeilenga's avatar
Kurt Zeilenga committed
920
921
922
923
924
#ifdef HAVE_TLS
		/* if start TLS failed but it was not mandatory,
		 * check if the non-TLS connection was already
		 * in cache; in case, destroy the newly created
		 * connection and use the existing one */
925
		if ( LDAP_BACK_PCONN_ISTLS( lc ) 
Kurt Zeilenga's avatar
Kurt Zeilenga committed
926
927
				&& !ldap_tls_inplace( lc->lc_ld ) )
		{
928
929
			ldapconn_t	*tmplc = NULL;
			int		idx = LDAP_BACK_CONN2PRIV( &lc_curr ) - 1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
930
			
Kurt Zeilenga's avatar
Kurt Zeilenga committed
931
			ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
932
933
934
935
936
937
938
939
940
			LDAP_TAILQ_FOREACH( tmplc,
				&li->li_conn_priv[ idx ].lic_priv,
				lc_q )
			{
				if ( !LDAP_BACK_CONN_BINDING( tmplc ) ) {
					break;
				}
			}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
941
942
943
944
945
			if ( tmplc != NULL ) {
				refcnt = ++tmplc->lc_refcnt;
				ldap_back_conn_free( lc );
				lc = tmplc;
			}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
946
			ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
947
948
949
950
951
952
953

			if ( tmplc != NULL ) {
				goto done;
			}
		}
#endif /* HAVE_TLS */

954
		/* Inserts the newly created ldapconn in the avl tree */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
955
		ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
956

957
958
		LDAP_BACK_CONN_ISBOUND_CLEAR( lc );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
959
		assert( lc->lc_refcnt == 1 );
960

961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
#if LDAP_BACK_PRINT_CONNTREE > 0
		ldap_back_print_conntree( li, ">>> ldap_back_getconn(insert)" );
#endif /* LDAP_BACK_PRINT_CONNTREE */
	
		if ( LDAP_BACK_PCONN_ISPRIV( lc ) ) {
			if ( li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num < li->li_conn_priv_max ) {
				LDAP_TAILQ_INSERT_TAIL( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv, lc, lc_q );
				li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_num++;
				LDAP_BACK_CONN_CACHED_SET( lc );

			} else {
				LDAP_BACK_CONN_TAINTED_SET( lc );
			}
			rs->sr_err = 0;

		} else {
			rs->sr_err = avl_insert( &li->li_conninfo.lai_tree, (caddr_t)lc,
				ldap_back_conndn_cmp, ldap_back_conndn_dup );
			LDAP_BACK_CONN_CACHED_SET( lc );
		}

#if LDAP_BACK_PRINT_CONNTREE > 0
		ldap_back_print_conntree( li, "<<< ldap_back_getconn(insert)" );
#endif /* LDAP_BACK_PRINT_CONNTREE */
985
	
Kurt Zeilenga's avatar
Kurt Zeilenga committed
986
		ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
987

988
989
990
991
		if ( StatslogTest( LDAP_DEBUG_TRACE ) ) {
			char	buf[ SLAP_TEXT_BUFLEN ];

			snprintf( buf, sizeof( buf ),
992
993
				"lc=%p inserted refcnt=%u rc=%d",
				(void *)lc, refcnt, rs->sr_err );
994
995
996
997
998
				
			Debug( LDAP_DEBUG_TRACE,
				"=>ldap_back_getconn: %s: %s\n",
				op->o_log_prefix, buf, 0 );
		}
999
	
1000
1001
1002
1003
1004
		if ( !LDAP_BACK_PCONN_ISPRIV( lc ) ) {
			/* Err could be -1 in case a duplicate ldapconn is inserted */
			switch ( rs->sr_err ) {
			case 0:
				break;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
1005

1006
1007
1008
1009
1010
1011
1012
1013
			case -1:
				LDAP_BACK_CONN_CACHED_CLEAR( lc );
				if ( !( sendok & LDAP_BACK_BINDING ) && !LDAP_BACK_USE_TEMPORARIES( li ) ) {
					/* duplicate: free and try to get the newly created one */
					ldap_back_conn_free( lc );
					lc = NULL;
					goto retry_lock;
				}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
1014

1015
1016
1017
1018
1019
1020
1021
1022
				/* taint connection, so that it'll be freed when released */
				LDAP_BACK_CONN_TAINTED_SET( lc );
				break;

			default:
				LDAP_BACK_CONN_CACHED_CLEAR( lc );
				ldap_back_conn_free( lc );
				rs->sr_err = LDAP_OTHER;
1023
				rs->sr_text = "Proxy bind collision";
1024
1025
1026
1027
				if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) {
					send_ldap_result( op, rs );
				}
				return NULL;
1028
			}
1029
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1030

1031
	} else {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1032
1033
		int	expiring = 0;

1034
1035
1036
		if ( ( li->li_idle_timeout != 0 && op->o_time > lc->lc_time + li->li_idle_timeout )
			|| ( li->li_conn_ttl != 0 && op->o_time > lc->lc_create_time + li->li_conn_ttl ) )
		{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1037
1038
1039
1040
1041
			expiring = 1;

			/* let it be used, but taint/delete it so that 
			 * no-one else can look it up any further */
			ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
1042
1043
1044
1045
1046

#if LDAP_BACK_PRINT_CONNTREE > 0
			ldap_back_print_conntree( li, ">>> ldap_back_getconn(timeout)" );
#endif /* LDAP_BACK_PRINT_CONNTREE */

1047
			(void)ldap_back_conn_delete( li, lc );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
1048
			LDAP_BACK_CONN_TAINTED_SET( lc );
1049
1050
1051
1052
1053
1054

#if LDAP_BACK_PRINT_CONNTREE > 0
			ldap_back_print_conntree( li, "<<< ldap_back_getconn(timeout)" );
#endif /* LDAP_BACK_PRINT_CONNTREE */

			ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
1055
1056
		}

1057
1058
1059
		if ( StatslogTest( LDAP_DEBUG_TRACE ) ) {
			char	buf[ SLAP_TEXT_BUFLEN ];

Kurt Zeilenga's avatar
Kurt Zeilenga committed
1060
			snprintf( buf, sizeof( buf ),
1061
1062
1063
				"conn %p fetched refcnt=%u%s",
				(void *)lc, refcnt,
				expiring ? " expiring" : "" );
1064
			Debug( LDAP_DEBUG_TRACE,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1065
				"=>ldap_back_getconn: %s.\n", buf, 0, 0 );
1066
1067
1068
		}
	}

1069
1070
1071
#ifdef HAVE_TLS
done:;
#endif /* HAVE_TLS */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1072

Kurt Zeilenga's avatar
Kurt Zeilenga committed
1073
	return lc;
1074
1075
}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
1076
void
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1077
ldap_back_release_conn_lock(
1078
	ldapinfo_t		*li,
1079
	ldapconn_t		**lcp,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1080
	int			dolock )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1081
1082
{

1083
1084
	ldapconn_t	*lc = *lcp;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
1085
1086
1087
	if ( dolock ) {
		ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1088
	assert( lc->lc_refcnt > 0 );
1089
	LDAP_BACK_CONN_BINDING_CLEAR( lc );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
1090
1091
	lc->lc_refcnt--;
	if ( LDAP_BACK_CONN_TAINTED( lc ) ) {
1092
		ldap_back_freeconn( li, lc, 0 );
1093
		*lcp = NULL;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
1094
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1095
1096
1097
	if ( dolock ) {
		ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1098
1099
}

1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
void
ldap_back_quarantine(
	Operation	*op,
	SlapReply	*rs )
{
	ldapinfo_t		*li = (ldapinfo_t *)op->o_bd->be_private;

	slap_retry_info_t	*ri = &li->li_quarantine;

	ldap_pvt_thread_mutex_lock( &li->li_quarantine_mutex );

	if ( rs->sr_err == LDAP_UNAVAILABLE ) {
		time_t		new_last = slap_get_time();

		switch ( li->li_isquarantined ) {
		case LDAP_BACK_FQ_NO:
			if ( ri->ri_last == new_last ) {
				goto done;
			}

			Debug( LDAP_DEBUG_ANY,
				"%s: ldap_back_quarantine enter.\n",
				op->o_log_prefix, 0, 0 );

			ri->ri_idx = 0;
			ri->ri_count = 0;
			break;

		case LDAP_BACK_FQ_RETRYING:
			Debug( LDAP_DEBUG_ANY,
				"%s: ldap_back_quarantine block #%d try #%d failed.\n",
				op->o_log_prefix, ri->ri_idx, ri->ri_count );

			++ri->ri_count;
			if ( ri->ri_num[ ri->ri_idx ] != SLAP_RETRYNUM_FOREVER
				&& ri->ri_count == ri->ri_num[ ri->ri_idx ] )
			{
				ri->ri_count = 0;
				++ri->ri_idx;
			}
			break;

		default:
			break;
		}

		li->li_isquarantined = LDAP_BACK_FQ_YES;
		ri->ri_last = new_last;

	} else if ( li->li_isquarantined != LDAP_BACK_FQ_NO ) {
		if ( ri->ri_last == slap_get_time() ) {
			goto done;
		}

		Debug( LDAP_DEBUG_ANY,
			"%s: ldap_back_quarantine exit (%d) err=%d.\n",
			op->o_log_prefix, li->li_isquarantined, rs->sr_err );

		if ( li->li_quarantine_f ) {
			(void)li->li_quarantine_f( li, li->li_quarantine_p );
		}

		ri->ri_count = 0;
		ri->ri_idx = 0;
		li->li_isquarantined = LDAP_BACK_FQ_NO;
	}

done:;
	ldap_pvt_thread_mutex_unlock( &li->li_quarantine_mutex );
}

1171
/*
1172
 * ldap_back_dobind_int
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1173
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1174
 * Note: dolock indicates whether li->li_conninfo.lai_mutex must be locked or not