bind.c 75.8 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/>.
 *
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
5
 * Copyright 1999-2019 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:
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>

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
#include "lutil.h"
36
#include "lutil_ldap.h"
37

Pierangelo Masarati's avatar
Pierangelo Masarati committed
38
#define LDAP_CONTROL_OBSOLETE_PROXY_AUTHZ	"2.16.840.1.113730.3.4.12"
Pierangelo Masarati's avatar
Pierangelo Masarati committed
39

40
41
42
43
#ifdef LDAP_DEVEL
#define SLAP_AUTH_DN 1
#endif

44
#if LDAP_BACK_PRINT_CONNTREE > 0
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

static const struct {
	slap_mask_t	f;
	char		c;
} flagsmap[] = {
	{ LDAP_BACK_FCONN_ISBOUND,	'B' },
	{ LDAP_BACK_FCONN_ISANON,	'A' },
	{ LDAP_BACK_FCONN_ISPRIV,	'P' },
	{ LDAP_BACK_FCONN_ISTLS,	'T' },
	{ LDAP_BACK_FCONN_BINDING,	'X' },
	{ LDAP_BACK_FCONN_TAINTED,	'E' },
	{ LDAP_BACK_FCONN_ABANDON,	'N' },
	{ LDAP_BACK_FCONN_ISIDASR,	'S' },
	{ LDAP_BACK_FCONN_CACHED,	'C' },
	{ 0,				'\0' }
};

static void
ldap_back_conn_print( ldapconn_t *lc, const char *avlstr )
{
	char buf[ SLAP_TEXT_BUFLEN ];
	char fbuf[ sizeof("BAPTIENSC") ];
	int i;

	ldap_back_conn2str( &lc->lc_base, buf, sizeof( buf ) );
	for ( i = 0; flagsmap[ i ].c != '\0'; i++ ) {
		if ( lc->lc_lcflags & flagsmap[i].f ) {
			fbuf[i] = flagsmap[i].c;

		} else {
			fbuf[i] = '.';
		}
	}
	fbuf[i] = '\0';
	
	fprintf( stderr, "lc=%p %s %s flags=0x%08x (%s)\n",
		(void *)lc, buf, avlstr, lc->lc_lcflags, fbuf );
}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
84
static void
85
ldap_back_ravl_print( Avlnode *root, int depth )
Pierangelo Masarati's avatar
Pierangelo Masarati committed
86
87
88
89
90
91
92
93
{
	int		i;
	ldapconn_t	*lc;
	
	if ( root == 0 ) {
		return;
	}
	
94
	ldap_back_ravl_print( root->avl_right, depth+1 );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
95
96
97
98
99
100
	
	for ( i = 0; i < depth; i++ ) {
		fprintf( stderr, "-" );
	}

	lc = root->avl_data;
101
102
103
	ldap_back_conn_print( lc, avl_bf2str( root->avl_bf ) );

	ldap_back_ravl_print( root->avl_left, depth + 1 );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
104
105
}

106
107
108
109
110
111
112
113
114
115
static char* priv2str[] = {
	"privileged",
	"privileged/TLS",
	"anonymous",
	"anonymous/TLS",
	"bind",
	"bind/TLS",
	NULL
};

116
void
117
ldap_back_print_conntree( ldapinfo_t *li, char *msg )
Pierangelo Masarati's avatar
Pierangelo Masarati committed
118
{
119
120
	int	c;

Pierangelo Masarati's avatar
Pierangelo Masarati committed
121
	fprintf( stderr, "========> %s\n", msg );
122
123
124
125
126
127
128
129
130

	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 )
		{
131
132
			fprintf( stderr, "    [%d] ", i );
			ldap_back_conn_print( lc, "" );
133
134
135
			i++;
		}
	}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
136
	
137
	if ( li->li_conninfo.lai_tree == 0 ) {
138
		fprintf( stderr, "\t(empty)\n" );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
139
140

	} else {
141
		ldap_back_ravl_print( li->li_conninfo.lai_tree, 0 );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
142
143
144
145
	}
	
	fprintf( stderr, "<======== %s\n", msg );
}
146
147
#endif /* LDAP_BACK_PRINT_CONNTREE */

148
static int
Pierangelo Masarati's avatar
Pierangelo Masarati committed
149
ldap_back_freeconn( ldapinfo_t *li, ldapconn_t *lc, int dolock );
150

151
152
153
static ldapconn_t *
ldap_back_getconn( Operation *op, SlapReply *rs, ldap_back_send_t sendok,
	struct berval *binddn, struct berval *bindcred );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
154

155
static int
156
157
ldap_back_is_proxy_authz( Operation *op, SlapReply *rs, ldap_back_send_t sendok,
	struct berval *binddn, struct berval *bindcred );
158

159
static int
160
161
162
163
ldap_back_proxy_authz_bind( ldapconn_t *lc, Operation *op, SlapReply *rs,
	ldap_back_send_t sendok, struct berval *binddn, struct berval *bindcred );

static int
Howard Chu's avatar
Howard Chu committed
164
ldap_back_prepare_conn( ldapconn_t *lc, Operation *op, SlapReply *rs,
165
	ldap_back_send_t sendok );
166

Pierangelo Masarati's avatar
Pierangelo Masarati committed
167
168
169
static int
ldap_back_conndnlc_cmp( const void *c1, const void *c2 );

Pierangelo Masarati's avatar
Pierangelo Masarati committed
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
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;
}

204
int
205
ldap_back_bind( Operation *op, SlapReply *rs )
206
{
207
208
	ldapinfo_t		*li = (ldapinfo_t *) op->o_bd->be_private;
	ldapconn_t		*lc;
209

210
211
212
213
	LDAPControl		**ctrls = NULL;
	struct berval		save_o_dn;
	int			save_o_do_not_cache,
				rc = 0;
214
215
	ber_int_t		msgid;
	ldap_back_send_t	retrying = LDAP_BACK_RETRYING;
216

217
218
219
220
221
222
223
224
225
226
	/* allow rootdn as a means to auth without the need to actually
 	 * contact the proxied DSA */
	switch ( be_rootdn_bind( op, rs ) ) {
	case SLAP_CB_CONTINUE:
		break;

	default:
		return rs->sr_err;
	}

227
	lc = ldap_back_getconn( op, rs, LDAP_BACK_BIND_SERR, NULL, NULL );
228
	if ( !lc ) {
229
		return rs->sr_err;
230
231
	}

232
233
	/* we can do (almost) whatever we want with this conn,
	 * because either it's temporary, or it's marked as binding */
234
235
236
	if ( !BER_BVISNULL( &lc->lc_bound_ndn ) ) {
		ch_free( lc->lc_bound_ndn.bv_val );
		BER_BVZERO( &lc->lc_bound_ndn );
237
	}
238
239
240
241
242
	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 );
	}
243
	LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
244

245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
	/* don't add proxyAuthz; set the bindDN */
	save_o_dn = op->o_dn;
	save_o_do_not_cache = op->o_do_not_cache;
	op->o_dn = op->o_req_dn;
	op->o_do_not_cache = 1;

	ctrls = op->o_ctrls;
	rc = ldap_back_controls_add( op, rs, lc, &ctrls );
	op->o_dn = save_o_dn;
	op->o_do_not_cache = save_o_do_not_cache;
	if ( rc != LDAP_SUCCESS ) {
		send_ldap_result( op, rs );
		ldap_back_release_conn( li, lc );
		return( rc );
	}

261
retry:;
262
	/* method is always LDAP_AUTH_SIMPLE if we got here */
263
264
	rs->sr_err = ldap_sasl_bind( lc->lc_ld, op->o_req_dn.bv_val,
			LDAP_SASL_SIMPLE,
265
			&op->orb_cred, ctrls, NULL, &msgid );
266
267
	/* FIXME: should we always retry, or only when piping the bind
	 * in the "override" connection pool? */
268
269
	rc = ldap_back_op_result( lc, op, rs, msgid,
		li->li_timeout[ SLAP_OP_BIND ],
270
271
272
273
274
275
		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;
		}
276
277
		if ( !lc )
			return( rc );
278
279
	}

280
281
282
283
	ldap_pvt_thread_mutex_lock( &li->li_counter_mutex );
	ldap_pvt_mp_add( li->li_ops_completed[ SLAP_OP_BIND ], 1 );
	ldap_pvt_thread_mutex_unlock( &li->li_counter_mutex );

284
285
	ldap_back_controls_free( op, rs, &ctrls );

286
	if ( rc == LDAP_SUCCESS ) {
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
287
288
		op->o_conn->c_authz_cookie = op->o_bd->be_private;

289
290
		/* If defined, proxyAuthz will be used also when
		 * back-ldap is the authorizing backend; for this
291
		 * purpose, after a successful bind the connection
292
293
294
		 * is left for further binds, and further operations 
		 * on this client connection will use a default
		 * connection with identity assertion */
295
		/* NOTE: use with care */
296
		if ( li->li_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
297
			ldap_back_release_conn( li, lc );
298
			return( rc );
299
		}
300

301
302
		/* rebind is now done inside ldap_back_proxy_authz_bind()
		 * in case of success */
303
		LDAP_BACK_CONN_ISBOUND_SET( lc );
304
		ber_dupbv( &lc->lc_bound_ndn, &op->o_req_ndn );
305

306
307
308
309
310
		if ( !BER_BVISNULL( &lc->lc_cred ) ) {
			memset( lc->lc_cred.bv_val, 0,
					lc->lc_cred.bv_len );
		}

311
		if ( LDAP_BACK_SAVECRED( li ) ) {
312
			ber_bvreplace( &lc->lc_cred, &op->orb_cred );
313
			ldap_set_rebind_proc( lc->lc_ld, li->li_rebind_f, lc );
314
315
316

		} else {
			lc->lc_cred.bv_len = 0;
317
		}
318
319
	}

320
	/* must re-insert if local DN changed as result of bind */
321
	if ( !LDAP_BACK_CONN_ISBOUND( lc )
322
323
		|| ( !dn_match( &op->o_req_ndn, &lc->lc_local_ndn )
			&& !LDAP_BACK_PCONN_ISPRIV( lc ) ) )
324
	{
325
		int		lerr = -1;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
326
		ldapconn_t	*tmplc;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
327

328
		/* wait for all other ops to release the connection */
329
retry_lock:;
330
		ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
331
		if ( lc->lc_refcnt > 1 ) {
332
			ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
333
			ldap_pvt_thread_yield();
334
			goto retry_lock;
335
		}
336

337
#if LDAP_BACK_PRINT_CONNTREE > 0
338
		ldap_back_print_conntree( li, ">>> ldap_back_bind" );
339
#endif /* LDAP_BACK_PRINT_CONNTREE */
340

341
		assert( lc->lc_refcnt == 1 );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
342
		ldap_back_conn_delete( li, lc );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
343

344
345
346
347
		/* 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 )
			{
348
				assert( !LDAP_BACK_PCONN_ISPRIV( lc ) );
349
				Debug( LDAP_DEBUG_TRACE,
350
351
					"=>ldap_back_bind: destroying conn %lu (refcnt=%u)\n",
					lc->lc_conn->c_connid, lc->lc_refcnt, 0 );
352

Pierangelo Masarati's avatar
Pierangelo Masarati committed
353
				if ( tmplc->lc_refcnt != 0 ) {
354
355
					/* taint it */
					LDAP_BACK_CONN_TAINTED_SET( tmplc );
356
					LDAP_BACK_CONN_CACHED_CLEAR( tmplc );
357
358
359
360
361
362
363
364
365
366
367
368

				} 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 );
				}
			}
		}

369
370
		if ( LDAP_BACK_CONN_ISBOUND( lc ) ) {
			ber_bvreplace( &lc->lc_local_ndn, &op->o_req_ndn );
371
			if ( be_isroot_dn( op->o_bd, &op->o_req_ndn ) ) {
372
				LDAP_BACK_PCONN_ROOTDN_SET( lc, op );
373
			}
374
375
376
377
			lerr = avl_insert( &li->li_conninfo.lai_tree, (caddr_t)lc,
				ldap_back_conndn_cmp, ldap_back_conndn_dup );
		}

378
#if LDAP_BACK_PRINT_CONNTREE > 0
379
		ldap_back_print_conntree( li, "<<< ldap_back_bind" );
380
#endif /* LDAP_BACK_PRINT_CONNTREE */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
381
	
382
		ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
383
384
		switch ( lerr ) {
		case 0:
385
			LDAP_BACK_CONN_CACHED_SET( lc );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
386
387
388
389
390
391
			break;

		case -1:
			/* duplicate; someone else successfully bound
			 * on the same connection with the same identity;
			 * we can do this because lc_refcnt == 1 */
392
			ldap_back_conn_free( lc );
393
			lc = NULL;
394
		}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
395
	}
396

397
	if ( lc != NULL ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
398
		ldap_back_release_conn( li, lc );
399
400
	}

401
402
403
404
	return( rc );
}

/*
405
 * ldap_back_conndn_cmp
406
 *
407
408
409
 * 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
410
411
 */
int
412
ldap_back_conndn_cmp( const void *c1, const void *c2 )
413
{
414
415
	const ldapconn_t	*lc1 = (const ldapconn_t *)c1;
	const ldapconn_t	*lc2 = (const ldapconn_t *)c2;
416
	int rc;
417

418
	/* If local DNs don't match, it is definitely not a match */
419
420
421
422
423
424
	/* 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 );
425
	}
426

427
428
429
	return rc;
}

430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
/*
 * 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;
}

459
460
461
462
463
464
465
466
467
468
469
470
/*
 * 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;

471
472
473
	/* For shared sessions, conn is NULL. Only explicitly
	 * bound sessions will have non-NULL conn.
	 */
474
	return SLAP_PTRCMP( lc1->lc_conn, lc2->lc_conn );
475
476
477
}

/*
478
 * ldap_back_conndn_dup
479
 *
480
 * returns -1 in case a duplicate ldapconn_t has been inserted;
481
482
483
 * used by avl stuff
 */
int
484
ldap_back_conndn_dup( void *c1, void *c2 )
485
{
486
487
	ldapconn_t	*lc1 = (ldapconn_t *)c1;
	ldapconn_t	*lc2 = (ldapconn_t *)c2;
488

489
	/* Cannot have more than one shared session with same DN */
490
491
	if ( lc1->lc_conn == lc2->lc_conn &&
		dn_match( &lc1->lc_local_ndn, &lc2->lc_local_ndn ) )
492
493
494
	{
		return -1;
	}
495
496
		
	return 0;
497
}
498

499
static int
Pierangelo Masarati's avatar
Pierangelo Masarati committed
500
ldap_back_freeconn( ldapinfo_t *li, ldapconn_t *lc, int dolock )
501
{
502
503
504
	if ( dolock ) {
		ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
	}
505

506
#if LDAP_BACK_PRINT_CONNTREE > 0
507
	ldap_back_print_conntree( li, ">>> ldap_back_freeconn" );
508
509
#endif /* LDAP_BACK_PRINT_CONNTREE */

Pierangelo Masarati's avatar
Pierangelo Masarati committed
510
	(void)ldap_back_conn_delete( li, lc );
511

Pierangelo Masarati's avatar
Pierangelo Masarati committed
512
	if ( lc->lc_refcnt == 0 ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
513
514
		ldap_back_conn_free( (void *)lc );
	}
515

516
#if LDAP_BACK_PRINT_CONNTREE > 0
517
	ldap_back_print_conntree( li, "<<< ldap_back_freeconn" );
518
519
#endif /* LDAP_BACK_PRINT_CONNTREE */

520
521
522
	if ( dolock ) {
		ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
	}
523

524
	return 0;
525
526
}

527
#ifdef HAVE_TLS
528
static int
529
530
531
532
533
534
ldap_back_start_tls(
	LDAP		*ld,
	int		protocol,
	int		*is_tls,
	const char	*url,
	unsigned	flags,
535
	int		timeout,
536
	const char	**text )
537
{
538
	int		rc = LDAP_SUCCESS;
539

540
	/* start TLS ("tls-[try-]{start,propagate}" statements) */
541
	if ( ( LDAP_BACK_USE_TLS_F( flags ) || ( *is_tls && LDAP_BACK_PROPAGATE_TLS_F( flags ) ) )
542
				&& !ldap_is_ldaps_url( url ) )
543
	{
544
#ifdef SLAP_STARTTLS_ASYNCHRONOUS
545
546
547
548
549
550
		/*
		 * use asynchronous StartTLS
		 * in case, chase referral (not implemented yet)
		 */
		int		msgid;

551
552
553
554
555
556
		if ( protocol == 0 ) {
			ldap_get_option( ld, LDAP_OPT_PROTOCOL_VERSION,
					(void *)&protocol );
		}

		if ( protocol < LDAP_VERSION3 ) {
557
558
559
560
561
562
563
			/* 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 );
564
565
566
		}

		if ( rc == LDAP_SUCCESS ) {
567
			LDAPMessage	*res = NULL;
568
569
			struct timeval	tv;

570
571
572
573
574
575
			if ( timeout ) {
				tv.tv_sec = timeout;
				tv.tv_usec = 0;
			} else {
				LDAP_BACK_TV_SET( &tv );
			}
576
			rc = ldap_result( ld, msgid, LDAP_MSG_ALL, &tv, &res );
577
			if ( rc <= 0 ) {
578
				rc = LDAP_UNAVAILABLE;
579

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

583
				rc = ldap_parse_extended_result( ld, res,
584
						NULL, &data, 0 );
585
				if ( rc == LDAP_SUCCESS ) {
586
587
					SlapReply rs;
					rc = ldap_parse_result( ld, res, &rs.sr_err,
588
						NULL, NULL, NULL, NULL, 1 );
589
590
					if ( rc != LDAP_SUCCESS ) {
						rs.sr_err = rc;
591
					}
592
					rc = slap_map_api2result( &rs );
593
594
					res = NULL;
					
595
596
597
598
					/* FIXME: in case a referral 
					 * is returned, should we try
					 * using it instead of the 
					 * configured URI? */
599
600
					if ( rc == LDAP_SUCCESS ) {
						rc = ldap_install_tls( ld );
601

602
					} else if ( rc == LDAP_REFERRAL ) {
603
						rc = LDAP_UNWILLING_TO_PERFORM;
604
						*text = "unwilling to chase referral returned by Start TLS exop";
605
606
					}

607
608
609
610
611
612
					if ( data ) {
						if ( data->bv_val ) {
							ber_memfree( data->bv_val );
						}
						ber_memfree( data );
					}
613
				}
614
615

			} else {
616
				rc = LDAP_OTHER;
617
618
619
620
			}

			if ( res != NULL ) {
				ldap_msgfree( res );
621
622
			}
		}
623
#else /* ! SLAP_STARTTLS_ASYNCHRONOUS */
624
625
626
		/*
		 * use synchronous StartTLS
		 */
627
		rc = ldap_start_tls_s( ld, NULL, NULL );
628
#endif /* ! SLAP_STARTTLS_ASYNCHRONOUS */
629

630
631
632
633
		/* 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 */
634
635
636
637
638
639
640
641
642
		switch ( rc ) {
		case LDAP_SUCCESS:
			*is_tls = 1;
			break;

		case LDAP_SERVER_DOWN:
			break;

		default:
643
			if ( LDAP_BACK_TLS_CRITICAL_F( flags ) ) {
644
645
646
647
648
649
650
651
				*text = "could not start TLS";
				break;
			}

			/* in case Start TLS is not critical */
			*is_tls = 0;
			rc = LDAP_SUCCESS;
			break;
652
		}
653

654
655
656
657
658
659
660
661
662
	} else {
		*is_tls = 0;
	}

	return rc;
}
#endif /* HAVE_TLS */

static int
Howard Chu's avatar
Howard Chu committed
663
ldap_back_prepare_conn( ldapconn_t *lc, Operation *op, SlapReply *rs, ldap_back_send_t sendok )
664
{
665
	ldapinfo_t	*li = (ldapinfo_t *)op->o_bd->be_private;
666
	int		version;
667
	LDAP		*ld = NULL;
668
#ifdef HAVE_TLS
669
	int		is_tls = op->o_conn->c_is_tls;
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
670
	int		flags = li->li_flags;
671
	time_t		lctime = (time_t)(-1);
Howard Chu's avatar
Howard Chu committed
672
	slap_bindconf *sb;
673
#endif /* HAVE_TLS */
674

675
	ldap_pvt_thread_mutex_lock( &li->li_uri_mutex );
676
	rs->sr_err = ldap_initialize( &ld, li->li_uri );
677
	ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex );
678
679
680
681
	if ( rs->sr_err != LDAP_SUCCESS ) {
		goto error_return;
	}

682
683
684
685
	if ( li->li_urllist_f ) {
		ldap_set_urllist_proc( ld, li->li_urllist_f, li->li_urllist_p );
	}

686
687
688
	/* Set LDAP version. This will always succeed: If the client
	 * bound with a particular version, then so can we.
	 */
689
690
691
692
693
694
695
	if ( li->li_version != 0 ) {
		version = li->li_version;

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

	} else {
696
		/* assume it's an internal op; set to LDAPv3 */
697
		version = LDAP_VERSION3;
698
	}
699
	ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, (const void *)&version );
700

Pierangelo Masarati's avatar
Pierangelo Masarati committed
701
	/* automatically chase referrals ("chase-referrals [{yes|no}]" statement) */
702
703
	ldap_set_option( ld, LDAP_OPT_REFERRALS,
		LDAP_BACK_CHASE_REFERRALS( li ) ? LDAP_OPT_ON : LDAP_OPT_OFF );
704

705
706
707
708
709
710
711
712
	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 );
	}

713
	/* turn on network keepalive, if configured so */
714
	slap_client_keepalive(ld, &li->li_tls.sb_keepalive);
715

716
#ifdef HAVE_TLS
Pierangelo Masarati's avatar
Pierangelo Masarati committed
717
	if ( LDAP_BACK_CONN_ISPRIV( lc ) ) {
718
719
720
		/* See "rationale" comment in ldap_back_getconn() */
		if ( li->li_acl_authmethod == LDAP_AUTH_NONE &&
			 li->li_idassert_authmethod != LDAP_AUTH_NONE )
721
722
723
			sb = &li->li_idassert.si_bc;
		else
			sb = &li->li_acl;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
724
725

	} else if ( LDAP_BACK_CONN_ISIDASSERT( lc ) ) {
Howard Chu's avatar
Howard Chu committed
726
		sb = &li->li_idassert.si_bc;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
727
728

	} else {
Howard Chu's avatar
Howard Chu committed
729
		sb = &li->li_tls;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
730
	}
Howard Chu's avatar
Howard Chu committed
731
732
733
734
735
736
737

	if ( sb->sb_tls_do_init ) {
		bindconf_tls_set( sb, ld );
	} else if ( sb->sb_tls_ctx ) {
		ldap_set_option( ld, LDAP_OPT_X_TLS_CTX, sb->sb_tls_ctx );
	}

Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
738
739
740
741
742
743
744
	/* if required by the bindconf configuration, force TLS */
	if ( ( sb == &li->li_acl || sb == &li->li_idassert.si_bc ) &&
		sb->sb_tls_ctx )
	{
		flags |= LDAP_BACK_F_USE_TLS;
	}

745
	ldap_pvt_thread_mutex_lock( &li->li_uri_mutex );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
746
747
	assert( li->li_uri_mutex_do_not_lock == 0 );
	li->li_uri_mutex_do_not_lock = 1;
748
	rs->sr_err = ldap_back_start_tls( ld, op->o_protocol, &is_tls,
749
			li->li_uri, flags, li->li_timeout[ SLAP_OP_BIND ], &rs->sr_text );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
750
	li->li_uri_mutex_do_not_lock = 0;
751
	ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex );
752
753
	if ( rs->sr_err != LDAP_SUCCESS ) {
		ldap_unbind_ext( ld, NULL, NULL );
754
		rs->sr_text = "Start TLS failed";
755
		goto error_return;
756
757
758

	} else if ( li->li_idle_timeout ) {
		/* only touch when activity actually took place... */
759
		lctime = op->o_time;
760
	}
761
#endif /* HAVE_TLS */
762

Howard Chu's avatar
Howard Chu committed
763
764
	lc->lc_ld = ld;
	lc->lc_refcnt = 1;
765
#ifdef HAVE_TLS
766
	if ( is_tls ) {
Howard Chu's avatar
Howard Chu committed
767
		LDAP_BACK_CONN_ISTLS_SET( lc );
768
	} else {
Howard Chu's avatar
Howard Chu committed
769
		LDAP_BACK_CONN_ISTLS_CLEAR( lc );
770
	}
771
772
	if ( lctime != (time_t)(-1) ) {
		lc->lc_time = lctime;
773
	}
774
#endif /* HAVE_TLS */
775
776
777
778
779
780

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 ) {
781
				rs->sr_text = "Proxy connection initialization failed";
782
783
784
			}
			send_ldap_result( op, rs );
		}
785
786
787

	} else {
		if ( li->li_conn_ttl > 0 ) {
Howard Chu's avatar
Howard Chu committed
788
			lc->lc_create_time = op->o_time;
789
		}
790
791
792
793
794
	}

	return rs->sr_err;
}

795
796
797
798
799
800
801
static ldapconn_t *
ldap_back_getconn(
	Operation		*op,
	SlapReply		*rs,
	ldap_back_send_t	sendok,
	struct berval		*binddn,
	struct berval		*bindcred )
802
{
803
	ldapinfo_t	*li = (ldapinfo_t *)op->o_bd->be_private;
804
	ldapconn_t	*lc = NULL,
805
			lc_curr = {{ 0 }};
806
	int		refcnt = 1,
807
			lookupconn = !( sendok & LDAP_BACK_BINDING );
808

809
810
811
812
813
814
815
816
	/* 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;

817
818
819
820
821
822
823
824
825
826
827
828
		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;
				}
829
			}
830
			ldap_pvt_thread_mutex_unlock( &li->li_quarantine_mutex );
831
832
833
834
835
		}

		if ( dont_retry ) {
			rs->sr_err = LDAP_UNAVAILABLE;
			if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) {
836
				rs->sr_text = "Target is quarantined";
837
838
839
840
841
842
				send_ldap_result( op, rs );
			}
			return NULL;
		}
	}

843
	/* Internal searches are privileged and shared. So is root. */
844
	if ( op->o_do_not_cache || be_isroot( op ) ) {
845
		LDAP_BACK_CONN_ISPRIV_SET( &lc_curr );
846
		lc_curr.lc_local_ndn = op->o_bd->be_rootndn;
847
		LDAP_BACK_PCONN_ROOTDN_SET( &lc_curr, op );
848

849
	} else {
850
851
852
853
854
855
856
857
858
859
860
861
862
		struct berval	tmpbinddn,
				tmpbindcred,
				save_o_dn,
				save_o_ndn;
		int		isproxyauthz;

		/* need cleanup */
		if ( binddn == NULL ) {
			binddn = &tmpbinddn;
		}	
		if ( bindcred == NULL ) {
			bindcred = &tmpbindcred;
		}
863
		if ( op->o_tag == LDAP_REQ_BIND ) {
864
865
866
867
868
			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;
		}
869
		isproxyauthz = ldap_back_is_proxy_authz( op, rs, sendok, binddn, bindcred );
870
871
872
873
		if ( op->o_tag == LDAP_REQ_BIND ) {
			op->o_dn = save_o_dn;
			op->o_ndn = save_o_ndn;
		}
874
875
876
		if ( isproxyauthz == -1 ) {
			return NULL;
		}
877
878
879
880
881
882

		lc_curr.lc_local_ndn = op->o_ndn;
		/* 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 ) {
883
			lc_curr.lc_conn = op->o_conn;
884

885
		} else {
886
			if ( isproxyauthz && !( sendok & LDAP_BACK_BINDING ) ) {
887
				lc_curr.lc_local_ndn = *binddn;
888
				LDAP_BACK_PCONN_ROOTDN_SET( &lc_curr, op );
889
890
				LDAP_BACK_CONN_ISIDASSERT_SET( &lc_curr );

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

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

			} else {
901
				LDAP_BACK_PCONN_ANON_SET( &lc_curr, op );
902
			}
903
		}
904
	}
905

906
	/* Explicit Bind requests always get their own conn */
907
	if ( lookupconn ) {
908
909
retry_lock:
		ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
910
911
912
913
914
915
916
917
918
919
920
921
922
		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,
Howard Chu's avatar
Howard Chu committed
923
					lc_conn_priv_q ) )
924
925
926
				{
					LDAP_TAILQ_REMOVE( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv,
						lc, lc_q );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
927
					LDAP_TAILQ_ENTRY_INIT( lc, lc_q );
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
					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 );
		}
944

945
946
		if ( lc != NULL ) {
			/* Don't reuse connections while they're still binding */
947
			if ( LDAP_BACK_CONN_BINDING( lc ) ) {
948
949
				if ( !LDAP_BACK_USE_TEMPORARIES( li ) ) {
					ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
950

951
952
953
954
					ldap_pvt_thread_yield();
					goto retry_lock;
				}
				lc = NULL;
955
			}
956

957
			if ( lc != NULL ) {
958
959
960
961
962
963
964
965
				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;
			}
966
967
		}
		ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
968
	}
969
970

	/* Looks like we didn't get a bind. Open a new session... */
971
	if ( lc == NULL ) {
Howard Chu's avatar
Howard Chu committed
972
973
974
		lc = (ldapconn_t *)ch_calloc( 1, sizeof( ldapconn_t ) );
		lc->lc_flags = li->li_flags;
		lc->lc_lcflags = lc_curr.lc_lcflags;
975
		lc->lc_ldapinfo = li;
Howard Chu's avatar
Howard Chu committed
976
977
		if ( ldap_back_prepare_conn( lc, op, rs, sendok ) != LDAP_SUCCESS ) {
			ch_free( lc );
978
			return NULL;
979
		}
980

981
		if ( sendok & LDAP_BACK_BINDING ) {