bind.c 75.6 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-2013 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
276
277
		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;
		}
	}

278
279
280
281
	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 );

282
283
	ldap_back_controls_free( op, rs, &ctrls );

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

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

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

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

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

		} else {
			lc->lc_cred.bv_len = 0;
315
		}
316
317
	}

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

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

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

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

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

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

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

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

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

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

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

399
400
401
402
	return( rc );
}

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

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

425
426
427
	return rc;
}

428
429
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
/*
 * 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;
}

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

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

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

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

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

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

Pierangelo Masarati's avatar
Pierangelo Masarati committed
508
	(void)ldap_back_conn_delete( li, lc );
509

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

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

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

522
	return 0;
523
524
}

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

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

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

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

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

			LDAP_BACK_TV_SET( &tv );
569

570
retry:;
571
572
			rc = ldap_result( ld, msgid, LDAP_MSG_ALL, &tv, &res );
			if ( rc < 0 ) {
573
				rc = LDAP_UNAVAILABLE;
574
575

			} else if ( rc == 0 ) {
576
577
578
579
580
581
				if ( retries != LDAP_BACK_RETRY_NEVER ) {
					ldap_pvt_thread_yield();
					if ( retries > 0 ) {
						retries--;
					}
					LDAP_BACK_TV_SET( &tv );
582
583
					goto retry;
				}
584
				rc = LDAP_UNAVAILABLE;
585

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

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

608
					} else if ( rc == LDAP_REFERRAL ) {
609
						rc = LDAP_UNWILLING_TO_PERFORM;
610
						*text = "unwilling to chase referral returned by Start TLS exop";
611
612
					}

613
614
615
616
617
618
					if ( data ) {
						if ( data->bv_val ) {
							ber_memfree( data->bv_val );
						}
						ber_memfree( data );
					}
619
				}
620
621

			} else {
622
				rc = LDAP_OTHER;
623
624
625
626
			}

			if ( res != NULL ) {
				ldap_msgfree( res );
627
628
			}
		}
629
#else /* ! SLAP_STARTTLS_ASYNCHRONOUS */
630
631
632
		/*
		 * use synchronous StartTLS
		 */
633
		rc = ldap_start_tls_s( ld, NULL, NULL );
634
#endif /* ! SLAP_STARTTLS_ASYNCHRONOUS */
635

636
637
638
639
		/* 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 */
640
641
642
643
644
645
646
647
648
		switch ( rc ) {
		case LDAP_SUCCESS:
			*is_tls = 1;
			break;

		case LDAP_SERVER_DOWN:
			break;

		default:
649
			if ( LDAP_BACK_TLS_CRITICAL_F( flags ) ) {
650
651
652
653
654
655
656
657
				*text = "could not start TLS";
				break;
			}

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

660
661
662
663
664
665
666
667
668
	} else {
		*is_tls = 0;
	}

	return rc;
}
#endif /* HAVE_TLS */

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

681
	ldap_pvt_thread_mutex_lock( &li->li_uri_mutex );
682
	rs->sr_err = ldap_initialize( &ld, li->li_uri );
683
	ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex );
684
685
686
687
	if ( rs->sr_err != LDAP_SUCCESS ) {
		goto error_return;
	}

688
689
690
691
	if ( li->li_urllist_f ) {
		ldap_set_urllist_proc( ld, li->li_urllist_f, li->li_urllist_p );
	}

692
693
694
	/* Set LDAP version. This will always succeed: If the client
	 * bound with a particular version, then so can we.
	 */
695
696
697
698
699
700
701
	if ( li->li_version != 0 ) {
		version = li->li_version;

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

	} else {
702
		/* assume it's an internal op; set to LDAPv3 */
703
		version = LDAP_VERSION3;
704
	}
705
	ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, (const void *)&version );
706

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

711
712
713
714
715
716
717
718
	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 );
	}

719
	/* turn on network keepalive, if configured so */
720
	slap_client_keepalive(ld, &li->li_tls.sb_keepalive);
721

722
#ifdef HAVE_TLS
Pierangelo Masarati's avatar
Pierangelo Masarati committed
723
	if ( LDAP_BACK_CONN_ISPRIV( lc ) ) {
724
725
726
		/* See "rationale" comment in ldap_back_getconn() */
		if ( li->li_acl_authmethod == LDAP_AUTH_NONE &&
			 li->li_idassert_authmethod != LDAP_AUTH_NONE )
727
728
729
			sb = &li->li_idassert.si_bc;
		else
			sb = &li->li_acl;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
730
731

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

	} else {
Howard Chu's avatar
Howard Chu committed
735
		sb = &li->li_tls;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
736
	}
Howard Chu's avatar
Howard Chu committed
737
738
739
740
741
742
743

	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
744
745
746
747
748
749
750
	/* 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;
	}

751
	ldap_pvt_thread_mutex_lock( &li->li_uri_mutex );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
752
753
	assert( li->li_uri_mutex_do_not_lock == 0 );
	li->li_uri_mutex_do_not_lock = 1;
754
	rs->sr_err = ldap_back_start_tls( ld, op->o_protocol, &is_tls,
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
755
			li->li_uri, flags, li->li_nretries, &rs->sr_text );
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
756
	li->li_uri_mutex_do_not_lock = 0;
757
	ldap_pvt_thread_mutex_unlock( &li->li_uri_mutex );
758
759
	if ( rs->sr_err != LDAP_SUCCESS ) {
		ldap_unbind_ext( ld, NULL, NULL );
760
		rs->sr_text = "Start TLS failed";
761
		goto error_return;
762
763
764

	} else if ( li->li_idle_timeout ) {
		/* only touch when activity actually took place... */
765
		lctime = op->o_time;
766
	}
767
#endif /* HAVE_TLS */
768

Howard Chu's avatar
Howard Chu committed
769
770
	lc->lc_ld = ld;
	lc->lc_refcnt = 1;
771
#ifdef HAVE_TLS
772
	if ( is_tls ) {
Howard Chu's avatar
Howard Chu committed
773
		LDAP_BACK_CONN_ISTLS_SET( lc );
774
	} else {
Howard Chu's avatar
Howard Chu committed
775
		LDAP_BACK_CONN_ISTLS_CLEAR( lc );
776
	}
777
778
	if ( lctime != (time_t)(-1) ) {
		lc->lc_time = lctime;
779
	}
780
#endif /* HAVE_TLS */
781
782
783
784
785
786

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 ) {
787
				rs->sr_text = "Proxy connection initialization failed";
788
789
790
			}
			send_ldap_result( op, rs );
		}
791
792
793

	} else {
		if ( li->li_conn_ttl > 0 ) {
Howard Chu's avatar
Howard Chu committed
794
			lc->lc_create_time = op->o_time;
795
		}
796
797
798
799
800
	}

	return rs->sr_err;
}

801
802
803
804
805
806
807
static ldapconn_t *
ldap_back_getconn(
	Operation		*op,
	SlapReply		*rs,
	ldap_back_send_t	sendok,
	struct berval		*binddn,
	struct berval		*bindcred )
808
{
809
	ldapinfo_t	*li = (ldapinfo_t *)op->o_bd->be_private;
810
	ldapconn_t	*lc = NULL,
811
			lc_curr = {{ 0 }};
812
	int		refcnt = 1,
813
			lookupconn = !( sendok & LDAP_BACK_BINDING );
814

815
816
817
818
819
820
821
822
	/* 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;

823
824
825
826
827
828
829
830
831
832
833
834
		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;
				}
835
			}
836
			ldap_pvt_thread_mutex_unlock( &li->li_quarantine_mutex );
837
838
839
840
841
		}

		if ( dont_retry ) {
			rs->sr_err = LDAP_UNAVAILABLE;
			if ( op->o_conn && ( sendok & LDAP_BACK_SENDERR ) ) {
842
				rs->sr_text = "Target is quarantined";
843
844
845
846
847
848
				send_ldap_result( op, rs );
			}
			return NULL;
		}
	}

849
	/* Internal searches are privileged and shared. So is root. */
850
	if ( op->o_do_not_cache || be_isroot( op ) ) {
851
		LDAP_BACK_CONN_ISPRIV_SET( &lc_curr );
852
		lc_curr.lc_local_ndn = op->o_bd->be_rootndn;
853
		LDAP_BACK_PCONN_ROOTDN_SET( &lc_curr, op );
854

855
	} else {
856
857
858
859
860
861
862
863
864
865
866
867
868
		struct berval	tmpbinddn,
				tmpbindcred,
				save_o_dn,
				save_o_ndn;
		int		isproxyauthz;

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

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

891
		} else {
892
			if ( isproxyauthz && !( sendok & LDAP_BACK_BINDING ) ) {
893
				lc_curr.lc_local_ndn = *binddn;
894
				LDAP_BACK_PCONN_ROOTDN_SET( &lc_curr, op );
895
896
				LDAP_BACK_CONN_ISIDASSERT_SET( &lc_curr );

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

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

			} else {
907
				LDAP_BACK_PCONN_ANON_SET( &lc_curr, op );
908
			}
909
		}
910
	}
911

912
	/* Explicit Bind requests always get their own conn */
913
	if ( lookupconn ) {
914
915
retry_lock:
		ldap_pvt_thread_mutex_lock( &li->li_conninfo.lai_mutex );
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
		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 );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
933
					LDAP_TAILQ_ENTRY_INIT( lc, lc_q );
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
					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 );
		}
950

951
952
		if ( lc != NULL ) {
			/* Don't reuse connections while they're still binding */
953
			if ( LDAP_BACK_CONN_BINDING( lc ) ) {
954
955
				if ( !LDAP_BACK_USE_TEMPORARIES( li ) ) {
					ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
956

957
958
959
960
					ldap_pvt_thread_yield();
					goto retry_lock;
				}
				lc = NULL;
961
			}
962

963
			if ( lc != NULL ) {
964
965
966
967
968
969
970
971
				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;
			}
972
973
		}
		ldap_pvt_thread_mutex_unlock( &li->li_conninfo.lai_mutex );
974
	}
975
976

	/* Looks like we didn't get a bind. Open a new session... */
977
	if ( lc == NULL ) {
Howard Chu's avatar
Howard Chu committed
978
979
980
981
982
		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 );
983
			return NULL;
984
		}
985

986
		if ( sendok & LDAP_BACK_BINDING ) {