bind.c 80.7 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-2021 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
#include "ldap_rq.h"
38

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

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

45
#if LDAP_BACK_PRINT_CONNTREE > 0
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63

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
64
ldap_back_conn_print( ldapconn_t *lc )
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
{
	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';
	
81
82
	fprintf( stderr, "lc=%p %s flags=0x%08x (%s)\n",
		(void *)lc, buf, lc->lc_lcflags, fbuf );
83
84
}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
85

86
87
88
89
90
91
92
93
94
95
static char* priv2str[] = {
	"privileged",
	"privileged/TLS",
	"anonymous",
	"anonymous/TLS",
	"bind",
	"bind/TLS",
	NULL
};

96
void
97
ldap_back_print_conntree( ldapinfo_t *li, char *msg )
Pierangelo Masarati's avatar
Pierangelo Masarati committed
98
{
99
100
	int	c;

Pierangelo Masarati's avatar
Pierangelo Masarati committed
101
	fprintf( stderr, "========> %s\n", msg );
102
103
104
105
106
107
108
109
110

	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 )
		{
111
			fprintf( stderr, "    [%d] ", i );
112
			ldap_back_conn_print( lc );
113
114
115
			i++;
		}
	}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
116
	
117
	if ( li->li_conninfo.lai_tree == 0 ) {
118
		fprintf( stderr, "\t(empty)\n" );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
119
120

	} else {
Ondřej Kuzník's avatar
Ondřej Kuzník committed
121
		TAvlnode *edge = ldap_tavl_end( li->li_conninfo.lai_tree, TAVL_DIR_LEFT );
122
123
		while ( edge ) {
			ldap_back_conn_print( (ldapconn_t *)edge->avl_data );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
124
			edge = ldap_tavl_next( edge, TAVL_DIR_RIGHT );
125
		}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
126
127
128
129
	}
	
	fprintf( stderr, "<======== %s\n", msg );
}
130
131
#endif /* LDAP_BACK_PRINT_CONNTREE */

132
static int
Pierangelo Masarati's avatar
Pierangelo Masarati committed
133
ldap_back_freeconn( ldapinfo_t *li, ldapconn_t *lc, int dolock );
134

135
136
137
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
138

139
static int
140
141
ldap_back_is_proxy_authz( Operation *op, SlapReply *rs, ldap_back_send_t sendok,
	struct berval *binddn, struct berval *bindcred );
142

143
static int
144
145
146
147
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
148
ldap_back_prepare_conn( ldapconn_t *lc, Operation *op, SlapReply *rs,
149
	ldap_back_send_t sendok );
150

Pierangelo Masarati's avatar
Pierangelo Masarati committed
151
152
153
static int
ldap_back_conndnlc_cmp( const void *c1, const void *c2 );

154
155
156
157
158
159
static void
ldap_back_conn_prune( ldapinfo_t *li );

static void
ldap_back_schedule_conn_expiry( ldapinfo_t *li, ldapconn_t *lc );

Pierangelo Masarati's avatar
Pierangelo Masarati committed
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
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 ) );
Ondřej Kuzník's avatar
Ondřej Kuzník committed
182
			tmplc = ldap_tavl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc,
Pierangelo Masarati's avatar
Pierangelo Masarati committed
183
184
185
186
187
188
189
190
191
192
193
				ldap_back_conndnlc_cmp );
			assert( tmplc == lc );
			LDAP_BACK_CONN_CACHED_CLEAR( lc );
		}

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

	return lc;
}

194
int
195
ldap_back_bind( Operation *op, SlapReply *rs )
196
{
197
198
	ldapinfo_t		*li = (ldapinfo_t *) op->o_bd->be_private;
	ldapconn_t		*lc;
199

200
201
202
203
	LDAPControl		**ctrls = NULL;
	struct berval		save_o_dn;
	int			save_o_do_not_cache,
				rc = 0;
204
205
	ber_int_t		msgid;
	ldap_back_send_t	retrying = LDAP_BACK_RETRYING;
206

207
208
209
210
211
212
213
214
215
216
	/* 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;
	}

217
	lc = ldap_back_getconn( op, rs, LDAP_BACK_BIND_SERR, NULL, NULL );
218
	if ( !lc ) {
219
		return rs->sr_err;
220
221
	}

222
223
	/* we can do (almost) whatever we want with this conn,
	 * because either it's temporary, or it's marked as binding */
224
225
226
	if ( !BER_BVISNULL( &lc->lc_bound_ndn ) ) {
		ch_free( lc->lc_bound_ndn.bv_val );
		BER_BVZERO( &lc->lc_bound_ndn );
227
	}
228
229
230
231
232
	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 );
	}
233
	LDAP_BACK_CONN_ISBOUND_CLEAR( lc );
234

235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
	/* 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 );
	}

251
retry:;
252
	/* method is always LDAP_AUTH_SIMPLE if we got here */
253
254
	rs->sr_err = ldap_sasl_bind( lc->lc_ld, op->o_req_dn.bv_val,
			LDAP_SASL_SIMPLE,
255
			&op->orb_cred, ctrls, NULL, &msgid );
256
257
	/* FIXME: should we always retry, or only when piping the bind
	 * in the "override" connection pool? */
258
259
	rc = ldap_back_op_result( lc, op, rs, msgid,
		li->li_timeout[ SLAP_OP_BIND ],
260
261
262
263
264
265
		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;
		}
266
267
		if ( !lc )
			return( rc );
268
269
	}

270
271
272
273
	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 );

274
275
	ldap_back_controls_free( op, rs, &ctrls );

276
	if ( rc == LDAP_SUCCESS ) {
277
278
		op->o_conn->c_authz_cookie = op->o_bd->be_private;

279
280
		/* If defined, proxyAuthz will be used also when
		 * back-ldap is the authorizing backend; for this
281
		 * purpose, after a successful bind the connection
282
283
284
		 * is left for further binds, and further operations 
		 * on this client connection will use a default
		 * connection with identity assertion */
285
		/* NOTE: use with care */
286
		if ( li->li_idassert_flags & LDAP_BACK_AUTH_OVERRIDE ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
287
			ldap_back_release_conn( li, lc );
288
			return( rc );
289
		}
290

291
292
		/* rebind is now done inside ldap_back_proxy_authz_bind()
		 * in case of success */
293
		LDAP_BACK_CONN_ISBOUND_SET( lc );
294
		ber_dupbv( &lc->lc_bound_ndn, &op->o_req_ndn );
295

296
297
298
299
300
		if ( !BER_BVISNULL( &lc->lc_cred ) ) {
			memset( lc->lc_cred.bv_val, 0,
					lc->lc_cred.bv_len );
		}

301
		if ( LDAP_BACK_SAVECRED( li ) ) {
302
			ber_bvreplace( &lc->lc_cred, &op->orb_cred );
303
			ldap_set_rebind_proc( lc->lc_ld, li->li_rebind_f, lc );
304
305
306

		} else {
			lc->lc_cred.bv_len = 0;
307
		}
308
309
	}

310
	/* must re-insert if local DN changed as result of bind */
311
	if ( !LDAP_BACK_CONN_ISBOUND( lc )
312
313
		|| ( !dn_match( &op->o_req_ndn, &lc->lc_local_ndn )
			&& !LDAP_BACK_PCONN_ISPRIV( lc ) ) )
314
	{
315
		int		lerr = -1;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
316
		ldapconn_t	*tmplc;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
317

318
		/* wait for all other ops to release the connection */
319
retry_lock:;
320
		ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
321
		if ( lc->lc_refcnt > 1 ) {
322
			ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
323
			ldap_pvt_thread_yield();
324
			goto retry_lock;
325
		}
326

327
#if LDAP_BACK_PRINT_CONNTREE > 0
328
		ldap_back_print_conntree( li, ">>> ldap_back_bind" );
329
#endif /* LDAP_BACK_PRINT_CONNTREE */
330

331
		assert( lc->lc_refcnt == 1 );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
332
		ldap_back_conn_delete( li, lc );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
333

334
335
		/* delete all cached connections with the current connection */
		if ( LDAP_BACK_SINGLECONN( li ) ) {
Ondřej Kuzník's avatar
Ondřej Kuzník committed
336
			while ( ( tmplc = ldap_tavl_delete( &li->li_conninfo.lai_tree, (caddr_t)lc, ldap_back_conn_cmp ) ) != NULL )
337
			{
338
				assert( !LDAP_BACK_PCONN_ISPRIV( lc ) );
339
				Debug( LDAP_DEBUG_TRACE,
340
					"=>ldap_back_bind: destroying conn %lu (refcnt=%u)\n",
341
					lc->lc_conn->c_connid, lc->lc_refcnt );
342

Pierangelo Masarati's avatar
Pierangelo Masarati committed
343
				if ( tmplc->lc_refcnt != 0 ) {
344
345
					/* taint it */
					LDAP_BACK_CONN_TAINTED_SET( tmplc );
346
					LDAP_BACK_CONN_CACHED_CLEAR( tmplc );
347
348
349
350
351
352
353
354
355
356
357
358

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

359
360
		if ( LDAP_BACK_CONN_ISBOUND( lc ) ) {
			ber_bvreplace( &lc->lc_local_ndn, &op->o_req_ndn );
361
			if ( be_isroot_dn( op->o_bd, &op->o_req_ndn ) ) {
362
				LDAP_BACK_PCONN_ROOTDN_SET( lc, op );
363
			}
Ondřej Kuzník's avatar
Ondřej Kuzník committed
364
			lerr = ldap_tavl_insert( &li->li_conninfo.lai_tree, (caddr_t)lc,
365
366
367
				ldap_back_conndn_cmp, ldap_back_conndn_dup );
		}

368
#if LDAP_BACK_PRINT_CONNTREE > 0
369
		ldap_back_print_conntree( li, "<<< ldap_back_bind" );
370
#endif /* LDAP_BACK_PRINT_CONNTREE */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
371
	
372
		ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
373
374
		switch ( lerr ) {
		case 0:
375
			LDAP_BACK_CONN_CACHED_SET( lc );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
376
377
378
379
380
381
			break;

		case -1:
			/* duplicate; someone else successfully bound
			 * on the same connection with the same identity;
			 * we can do this because lc_refcnt == 1 */
382
			ldap_back_conn_free( lc );
383
			lc = NULL;
384
		}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
385
	}
386

387
	if ( lc != NULL ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
388
		ldap_back_release_conn( li, lc );
389
390
	}

391
392
393
394
	return( rc );
}

/*
395
 * ldap_back_conndn_cmp
396
 *
397
398
399
 * 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
400
401
 */
int
402
ldap_back_conndn_cmp( const void *c1, const void *c2 )
403
{
404
405
	const ldapconn_t	*lc1 = (const ldapconn_t *)c1;
	const ldapconn_t	*lc2 = (const ldapconn_t *)c2;
406
	int rc;
407

408
	/* If local DNs don't match, it is definitely not a match */
409
410
411
412
413
414
	/* 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 );
415
	}
416

417
418
419
	return rc;
}

420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
/*
 * 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;
}

449
450
451
452
453
454
455
456
457
458
459
460
/*
 * 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;

461
462
463
	/* For shared sessions, conn is NULL. Only explicitly
	 * bound sessions will have non-NULL conn.
	 */
464
	return SLAP_PTRCMP( lc1->lc_conn, lc2->lc_conn );
465
466
467
}

/*
468
 * ldap_back_conndn_dup
469
 *
470
 * returns -1 in case a duplicate ldapconn_t has been inserted;
471
472
473
 * used by avl stuff
 */
int
474
ldap_back_conndn_dup( void *c1, void *c2 )
475
{
476
477
	ldapconn_t	*lc1 = (ldapconn_t *)c1;
	ldapconn_t	*lc2 = (ldapconn_t *)c2;
478

479
	/* Cannot have more than one shared session with same DN */
480
481
	if ( lc1->lc_conn == lc2->lc_conn &&
		dn_match( &lc1->lc_local_ndn, &lc2->lc_local_ndn ) )
482
483
484
	{
		return -1;
	}
485
486
		
	return 0;
487
}
488

489
static int
Pierangelo Masarati's avatar
Pierangelo Masarati committed
490
ldap_back_freeconn( ldapinfo_t *li, ldapconn_t *lc, int dolock )
491
{
492
493
494
	if ( dolock ) {
		ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
	}
495

496
#if LDAP_BACK_PRINT_CONNTREE > 0
497
	ldap_back_print_conntree( li, ">>> ldap_back_freeconn" );
498
499
#endif /* LDAP_BACK_PRINT_CONNTREE */

Pierangelo Masarati's avatar
Pierangelo Masarati committed
500
	(void)ldap_back_conn_delete( li, lc );
501

Pierangelo Masarati's avatar
Pierangelo Masarati committed
502
	if ( lc->lc_refcnt == 0 ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
503
504
		ldap_back_conn_free( (void *)lc );
	}
505

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

510
511
512
	if ( dolock ) {
		ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
	}
513

514
	return 0;
515
516
}

517
#ifdef HAVE_TLS
518
static int
519
520
521
522
523
524
ldap_back_start_tls(
	LDAP		*ld,
	int		protocol,
	int		*is_tls,
	const char	*url,
	unsigned	flags,
525
	int		timeout,
526
	const char	**text )
527
{
528
	int		rc = LDAP_SUCCESS;
529

530
	/* start TLS ("tls-[try-]{start,propagate}" statements) */
531
	if ( ( LDAP_BACK_USE_TLS_F( flags ) || ( *is_tls && LDAP_BACK_PROPAGATE_TLS_F( flags ) ) )
532
				&& !ldap_is_ldaps_url( url ) )
533
	{
534
#ifdef SLAP_STARTTLS_ASYNCHRONOUS
535
536
537
538
539
540
		/*
		 * use asynchronous StartTLS
		 * in case, chase referral (not implemented yet)
		 */
		int		msgid;

541
542
543
544
545
546
		if ( protocol == 0 ) {
			ldap_get_option( ld, LDAP_OPT_PROTOCOL_VERSION,
					(void *)&protocol );
		}

		if ( protocol < LDAP_VERSION3 ) {
547
548
549
550
551
552
553
			/* 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 );
554
555
556
		}

		if ( rc == LDAP_SUCCESS ) {
557
			LDAPMessage	*res = NULL;
558
559
			struct timeval	tv;

560
561
562
563
564
565
			if ( timeout ) {
				tv.tv_sec = timeout;
				tv.tv_usec = 0;
			} else {
				LDAP_BACK_TV_SET( &tv );
			}
566
			rc = ldap_result( ld, msgid, LDAP_MSG_ALL, &tv, &res );
567
			if ( rc <= 0 ) {
568
				rc = LDAP_UNAVAILABLE;
569

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

573
				rc = ldap_parse_extended_result( ld, res,
574
						NULL, &data, 0 );
575
				if ( rc == LDAP_SUCCESS ) {
576
577
					SlapReply rs;
					rc = ldap_parse_result( ld, res, &rs.sr_err,
578
						NULL, NULL, NULL, NULL, 1 );
579
580
					if ( rc != LDAP_SUCCESS ) {
						rs.sr_err = rc;
581
					}
582
					rc = slap_map_api2result( &rs );
583
584
					res = NULL;
					
585
586
587
588
					/* FIXME: in case a referral 
					 * is returned, should we try
					 * using it instead of the 
					 * configured URI? */
589
590
					if ( rc == LDAP_SUCCESS ) {
						rc = ldap_install_tls( ld );
591

592
					} else if ( rc == LDAP_REFERRAL ) {
593
						rc = LDAP_UNWILLING_TO_PERFORM;
594
						*text = "unwilling to chase referral returned by Start TLS exop";
595
596
					}

597
598
599
600
601
602
					if ( data ) {
						if ( data->bv_val ) {
							ber_memfree( data->bv_val );
						}
						ber_memfree( data );
					}
603
				}
604
605

			} else {
606
				rc = LDAP_OTHER;
607
608
609
610
			}

			if ( res != NULL ) {
				ldap_msgfree( res );
611
612
			}
		}
613
#else /* ! SLAP_STARTTLS_ASYNCHRONOUS */
614
615
616
		/*
		 * use synchronous StartTLS
		 */
617
		rc = ldap_start_tls_s( ld, NULL, NULL );
618
#endif /* ! SLAP_STARTTLS_ASYNCHRONOUS */
619

620
621
622
623
		/* 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 */
624
625
626
627
628
629
630
631
632
		switch ( rc ) {
		case LDAP_SUCCESS:
			*is_tls = 1;
			break;

		case LDAP_SERVER_DOWN:
			break;

		default:
633
			if ( LDAP_BACK_TLS_CRITICAL_F( flags ) ) {
634
635
636
637
638
639
640
641
				*text = "could not start TLS";
				break;
			}

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

644
645
646
647
648
649
650
651
652
	} else {
		*is_tls = 0;
	}

	return rc;
}
#endif /* HAVE_TLS */

static int
Howard Chu's avatar
Howard Chu committed
653
ldap_back_prepare_conn( ldapconn_t *lc, Operation *op, SlapReply *rs, ldap_back_send_t sendok )
654
{
655
	ldapinfo_t	*li = (ldapinfo_t *)op->o_bd->be_private;
656
	int		version;
657
	LDAP		*ld = NULL;
658
#ifdef HAVE_TLS
659
	int		is_tls = op->o_conn->c_is_tls;
660
	int		flags = li->li_flags;
661
	time_t		lctime = (time_t)(-1);
Howard Chu's avatar
Howard Chu committed
662
	slap_bindconf *sb;
663
#endif /* HAVE_TLS */
664

665
	ldap_pvt_thread_mutex_lock( &li->li_uri_mutex );
666
	rs->sr_err = ldap_initialize( &ld, li->li_uri );
667
	ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex );
668
669
670
671
	if ( rs->sr_err != LDAP_SUCCESS ) {
		goto error_return;
	}

672
673
674
675
	if ( li->li_urllist_f ) {
		ldap_set_urllist_proc( ld, li->li_urllist_f, li->li_urllist_p );
	}

676
677
678
	/* Set LDAP version. This will always succeed: If the client
	 * bound with a particular version, then so can we.
	 */
679
680
681
682
683
684
685
	if ( li->li_version != 0 ) {
		version = li->li_version;

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

	} else {
686
		/* assume it's an internal op; set to LDAPv3 */
687
		version = LDAP_VERSION3;
688
	}
689
	ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, (const void *)&version );
690

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

695
696
697
698
699
700
701
702
	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 );
	}

703
	/* turn on network keepalive, if configured so */
704
	slap_client_keepalive(ld, &li->li_tls.sb_keepalive);
705

706
707
708
709
710
	if ( li->li_tls.sb_tcp_user_timeout > 0 ) {
		ldap_set_option( ld, LDAP_OPT_TCP_USER_TIMEOUT,
				&li->li_tls.sb_tcp_user_timeout );
	}

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

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

	} else {
Howard Chu's avatar
Howard Chu committed
724
		sb = &li->li_tls;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
725
	}
Howard Chu's avatar
Howard Chu committed
726

727
	bindconf_tls_set( sb, ld );
Howard Chu's avatar
Howard Chu committed
728

729
730
	/* if required by the bindconf configuration, force TLS */
	if ( ( sb == &li->li_acl || sb == &li->li_idassert.si_bc ) &&
Pierangelo Masarati's avatar
Pierangelo Masarati committed
731
		sb->sb_tls_ctx )
732
733
734
735
	{
		flags |= LDAP_BACK_F_USE_TLS;
	}

736
	ldap_pvt_thread_mutex_lock( &li->li_uri_mutex );
737
738
	assert( li->li_uri_mutex_do_not_lock == 0 );
	li->li_uri_mutex_do_not_lock = 1;
739
	rs->sr_err = ldap_back_start_tls( ld, op->o_protocol, &is_tls,
740
			li->li_uri, flags, li->li_timeout[ SLAP_OP_BIND ], &rs->sr_text );
741
	li->li_uri_mutex_do_not_lock = 0;
742
	ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex );
743
744
	if ( rs->sr_err != LDAP_SUCCESS ) {
		ldap_unbind_ext( ld, NULL, NULL );
745
		rs->sr_text = "Start TLS failed";
746
		goto error_return;
747
748
749

	} else if ( li->li_idle_timeout ) {
		/* only touch when activity actually took place... */
750
		lctime = op->o_time;
751
	}
752
#endif /* HAVE_TLS */
753

Howard Chu's avatar
Howard Chu committed
754
755
	lc->lc_ld = ld;
	lc->lc_refcnt = 1;
756
#ifdef HAVE_TLS
757
	if ( is_tls ) {
Howard Chu's avatar
Howard Chu committed
758
		LDAP_BACK_CONN_ISTLS_SET( lc );
759
	} else {
Howard Chu's avatar
Howard Chu committed
760
		LDAP_BACK_CONN_ISTLS_CLEAR( lc );
761
	}
762
763
	if ( lctime != (time_t)(-1) ) {
		lc->lc_time = lctime;
764
	}
765
#endif /* HAVE_TLS */
766
767
768
769
770
771

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 ) {
772
				rs->sr_text = "Proxy connection initialization failed";
773
774
775
			}
			send_ldap_result( op, rs );
		}
776
777
778

	} else {
		if ( li->li_conn_ttl > 0 ) {
Howard Chu's avatar
Howard Chu committed
779
			lc->lc_create_time = op->o_time;
780
		}
781
782
783
784
785
	}

	return rs->sr_err;
}

786
787
788
789
790
791
792
static ldapconn_t *
ldap_back_getconn(
	Operation		*op,
	SlapReply		*rs,
	ldap_back_send_t	sendok,
	struct berval		*binddn,
	struct berval		*bindcred )
793
{
794
	ldapinfo_t	*li = (ldapinfo_t *)op->o_bd->be_private;
795
	ldapconn_t	*lc = NULL,
796
			lc_curr = {{ 0 }};
797
	int		refcnt = 1,
798
			lookupconn = !( sendok & LDAP_BACK_BINDING );
799

800
801
802
803
804
805
806
807
	/* 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;

808
809
810
811
812
813
814
815
816
817
818
819
		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;
				}
820
			}
821
			ldap_pvt_thread_mutex_unlock( &li->li_quarantine_mutex );
822
823
824
825
826
		}

		if ( dont_retry ) {
			rs->sr_err = LDAP_UNAVAILABLE;
			if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) {
827
				rs->sr_text = "Target is quarantined";
828
829
830
831
832
833
				send_ldap_result( op, rs );
			}
			return NULL;
		}
	}

834
	/* Internal searches are privileged and shared. So is root. */
835
	if ( op->o_do_not_cache || be_isroot( op ) ) {
836
		LDAP_BACK_CONN_ISPRIV_SET( &lc_curr );
837
		lc_curr.lc_local_ndn = op->o_bd->be_rootndn;
838
		LDAP_BACK_PCONN_ROOTDN_SET( &lc_curr, op );
839

840
	} else {
841
842
843
844
845
846
847
848
849
850
851
852
853
		struct berval	tmpbinddn,
				tmpbindcred,
				save_o_dn,
				save_o_ndn;
		int		isproxyauthz;

		/* need cleanup */
		if ( binddn == NULL ) {
			binddn = &tmpbinddn;
		}	
		if ( bindcred == NULL ) {
			bindcred = &tmpbindcred;
		}
854
		if ( op->o_tag == LDAP_REQ_BIND ) {
855
856
857
858
859
			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;
		}
860
		isproxyauthz = ldap_back_is_proxy_authz( op, rs, sendok, binddn, bindcred );
861
862
863
864
		if ( op->o_tag == LDAP_REQ_BIND ) {
			op->o_dn = save_o_dn;
			op->o_ndn = save_o_ndn;
		}
865
866
867
		if ( isproxyauthz == -1 ) {
			return NULL;
		}
868
869
870
871
872
873

		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 ) {
874
			lc_curr.lc_conn = op->o_conn;
875

876
		} else {
877
			if ( isproxyauthz && !( sendok & LDAP_BACK_BINDING ) ) {
878
				lc_curr.lc_local_ndn = *binddn;
879
				LDAP_BACK_PCONN_ROOTDN_SET( &lc_curr, op );
880
881
				LDAP_BACK_CONN_ISIDASSERT_SET( &lc_curr );

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

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

			} else {
892
				LDAP_BACK_PCONN_ANON_SET( &lc_curr, op );
893
			}
894
		}
895
	}
896

897
	/* Explicit Bind requests always get their own conn */
898
	if ( lookupconn ) {
899
900
retry_lock:
		ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
901
902
903
904
905
906
907
908
909
910
911
912
913
		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
914
					lc_conn_priv_q ) )
915
916
917
				{
					LDAP_TAILQ_REMOVE( &li->li_conn_priv[ LDAP_BACK_CONN2PRIV( lc ) ].lic_priv,
						lc, lc_q );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
918
					LDAP_TAILQ_ENTRY_INIT( lc, lc_q );
919
920
921
922
923
924
925
926
927
928
929
930
931
					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 */
Ondřej Kuzník's avatar
Ondřej Kuzník committed
932
			lc = (ldapconn_t *)ldap_tavl_find( li->li_conninfo.lai_tree, 
933
934
					(caddr_t)&lc_curr, ldap_back_conndn_cmp );
		}
935

936
937
		if ( lc != NULL ) {
			/* Don't reuse connections while they're still binding */
938
			if ( LDAP_BACK_CONN_BINDING( lc ) ) {
939
940
				if ( !LDAP_BACK_USE_TEMPORARIES( li ) ) {
					ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
941

942
943
944
945
					ldap_pvt_thread_yield();
					goto retry_lock;
				}
				lc = NULL;
946
			}
947

948
			if ( lc != NULL ) {