Commit c728ebf5 authored by Ralf Haferkamp's avatar Ralf Haferkamp
Browse files

ITS#7428 Use non-blocking IO during SSL Handshake

If a timeout is set, perform the SSL Handshake using non-blocking IO.  This way
we can timeout if SSL Handshake gets stuck for whatever reason.

This code is currently hidden behind #ifdefs (LDAP_USE_NON_BLOCKING_TLS) and
disabled by default as there seem to be some problems using NON-blocking
I/O during the TLS Handshake when linking against NSS (either a bug in NSS
itself of in tls_m.c, see discussion on -devel)

This patch adds an additional parameter to ldap_int_poll() in order to indicate
if we're waiting in order to perform a read or write operation.
parent be781ab8
......@@ -612,7 +612,7 @@ LDAP_F (int) ldap_int_timeval_dup( struct timeval **dest,
LDAP_F (int) ldap_connect_to_host( LDAP *ld, Sockbuf *sb,
int proto, LDAPURLDesc *srv, int async );
LDAP_F (int) ldap_int_poll( LDAP *ld, ber_socket_t s,
struct timeval *tvp );
struct timeval *tvp, int wr );
#if defined(HAVE_TLS) || defined(HAVE_CYRUS_SASL)
LDAP_V (char *) ldap_int_hostname;
......
......@@ -540,7 +540,7 @@ ldap_int_check_async_open( LDAP *ld, ber_socket_t sd )
struct timeval tv = { 0 };
int rc;
rc = ldap_int_poll( ld, sd, &tv );
rc = ldap_int_poll( ld, sd, &tv, 1 );
switch ( rc ) {
case 0:
/* now ready to start tls */
......
......@@ -276,7 +276,8 @@ int
ldap_int_poll(
LDAP *ld,
ber_socket_t s,
struct timeval *tvp )
struct timeval *tvp,
int wr )
{
int rc;
......@@ -288,9 +289,10 @@ ldap_int_poll(
{
struct pollfd fd;
int timeout = INFTIM;
short event = wr ? POLL_WRITE : POLL_READ;
fd.fd = s;
fd.events = POLL_WRITE;
fd.events = event;
if ( tvp != NULL ) {
timeout = TV2MILLISEC( tvp );
......@@ -310,7 +312,7 @@ ldap_int_poll(
return -2;
}
if ( fd.revents & POLL_WRITE ) {
if ( fd.revents & event ) {
if ( ldap_pvt_is_socket_ready( ld, s ) == -1 ) {
return -1;
}
......@@ -452,7 +454,7 @@ ldap_pvt_connect(LDAP *ld, ber_socket_t s,
return ( -2 );
}
rc = ldap_int_poll( ld, s, opt_tv );
rc = ldap_int_poll( ld, s, opt_tv, 1 );
osip_debug(ld, "ldap_pvt_connect: %d\n", rc, 0, 0);
......
......@@ -261,7 +261,7 @@ ldap_send_server_request(
ber_sockbuf_ctrl( lc->lconn_sb, LBER_SB_OPT_GET_FD, &sd );
/* poll ... */
switch ( ldap_int_poll( ld, sd, &tv ) ) {
switch ( ldap_int_poll( ld, sd, &tv, 1 ) ) {
case 0:
/* go on! */
lc->lconn_status = LDAP_CONNST_CONNECTED;
......
......@@ -43,6 +43,10 @@ static tls_impl *tls_imp = &ldap_int_tls_impl;
#endif /* HAVE_TLS */
#ifdef LDAP_DEVEL
#define LDAP_USE_NON_BLOCKING_TLS
#endif /* LDAP_DEVEL */
/* RFC2459 minimum required set of supported attribute types
* in a certificate DN
*/
......@@ -810,6 +814,11 @@ ldap_int_tls_start ( LDAP *ld, LDAPConn *conn, LDAPURLDesc *srv )
Sockbuf *sb;
char *host;
void *ssl;
int ret;
#ifdef LDAP_USE_NON_BLOCKING_TLS
struct timeval start_time_tv, tv, tv0;
ber_socket_t sd = AC_SOCKET_ERROR;
#endif /* LDAP_USE_NON_BLOCKING_TLS */
if ( !conn )
return LDAP_PARAM_ERROR;
......@@ -828,11 +837,101 @@ ldap_int_tls_start ( LDAP *ld, LDAPConn *conn, LDAPURLDesc *srv )
(void) tls_init( tls_imp );
#ifdef LDAP_USE_NON_BLOCKING_TLS
/*
* Fortunately, the lib uses blocking io...
* Use non-blocking io during SSL Handshake when a timeout is configured
*/
if ( ldap_int_tls_connect( ld, conn ) < 0 ) {
ld->ld_errno = LDAP_CONNECT_ERROR;
if ( ld->ld_options.ldo_tm_net.tv_sec >= 0 ) {
ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_SET_NONBLOCK, sb );
ber_sockbuf_ctrl( sb, LBER_SB_OPT_GET_FD, &sd );
tv = ld->ld_options.ldo_tm_net;
tv0 = tv;
#ifdef HAVE_GETTIMEOFDAY
gettimeofday( &start_time_tv, NULL );
#else /* ! HAVE_GETTIMEOFDAY */
time( &start_time_tv.tv_sec );
start_time_tv.tv_usec = 0;
#endif /* ! HAVE_GETTIMEOFDAY */
}
#endif /* LDAP_USE_NON_BLOCKING_TLS */
ld->ld_errno = LDAP_SUCCESS;
ret = ldap_int_tls_connect( ld, conn );
#ifdef LDAP_USE_NON_BLOCKING_TLS
while ( ret > 0 ) { /* this should only happen for non-blocking io */
int wr=0;
if ( sb->sb_trans_needs_read ) {
wr=0;
} else if ( sb->sb_trans_needs_write ) {
wr=1;
}
Debug( LDAP_DEBUG_TRACE, "ldap_int_tls_start: ldap_int_tls_connect needs %s\n",
wr ? "write": "read", 0, 0);
ret = ldap_int_poll( ld, sd, &tv, wr);
if ( ret < 0 ) {
ld->ld_errno = LDAP_TIMEOUT;
break;
} else {
/* ldap_int_poll called ldap_pvt_ndelay_off */
ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_SET_NONBLOCK, sb );
ret = ldap_int_tls_connect( ld, conn );
if ( ret > 0 ) { /* need to call tls_connect once more */
struct timeval curr_time_tv, delta_tv;
/* This is mostly copied from result.c:wait4msg(), should
* probably be moved into a separate function */
#ifdef HAVE_GETTIMEOFDAY
gettimeofday( &curr_time_tv, NULL );
#else /* ! HAVE_GETTIMEOFDAY */
time( &curr_time_tv.tv_sec );
curr_time_tv.tv_usec = 0;
#endif /* ! HAVE_GETTIMEOFDAY */
/* delta = curr - start */
delta_tv.tv_sec = curr_time_tv.tv_sec - start_time_tv.tv_sec;
delta_tv.tv_usec = curr_time_tv.tv_usec - start_time_tv.tv_usec;
if ( delta_tv.tv_usec < 0 ) {
delta_tv.tv_sec--;
delta_tv.tv_usec += 1000000;
}
/* tv0 < delta ? */
if ( ( tv0.tv_sec < delta_tv.tv_sec ) ||
( ( tv0.tv_sec == delta_tv.tv_sec ) &&
( tv0.tv_usec < delta_tv.tv_usec ) ) )
{
ret = -1;
ld->ld_errno = LDAP_TIMEOUT;
break;
} else {
/* timeout -= delta_time */
tv0.tv_sec -= delta_tv.tv_sec;
tv0.tv_usec -= delta_tv.tv_usec;
if ( tv0.tv_usec < 0 ) {
tv0.tv_sec--;
tv0.tv_usec += 1000000;
}
start_time_tv.tv_sec = curr_time_tv.tv_sec;
start_time_tv.tv_usec = curr_time_tv.tv_usec;
}
tv = tv0;
Debug( LDAP_DEBUG_TRACE, "ldap_int_tls_start: ld %p %ld s %ld us to go\n",
(void *)ld, (long) tv.tv_sec, (long) tv.tv_usec );
}
}
}
if ( ld->ld_options.ldo_tm_net.tv_sec >= 0 ) {
ber_sockbuf_ctrl( ld->ld_sb, LBER_SB_OPT_SET_NONBLOCK, NULL );
}
#endif /* LDAP_USE_NON_BLOCKING_TLS */
if ( ret < 0 ) {
if ( ld->ld_errno == LDAP_SUCCESS )
ld->ld_errno = LDAP_CONNECT_ERROR;
return (ld->ld_errno);
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment