mirror of
https://git.openldap.org/openldap/openldap.git
synced 2025-12-28 02:29:34 -05:00
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.
This commit is contained in:
parent
be781ab808
commit
c728ebf586
5 changed files with 111 additions and 10 deletions
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue