]> git.ipfire.org Git - thirdparty/openldap.git/commitdiff
ITS#8650 loop on incomplete TLS handshake
authorHoward Chu <hyc@openldap.org>
Sun, 12 Apr 2020 21:18:51 +0000 (22:18 +0100)
committerQuanah Gibson-Mount <quanah@openldap.org>
Mon, 13 Apr 2020 16:32:35 +0000 (16:32 +0000)
Always retry ldap_int_tls_connect() if it didn't complete,
regardless of blocking or non-blocking socket. Code from
ITS#7428 was wrong to only retry for async.

libraries/libldap/tls2.c

index dfccff044aad113e024eae39cfabd811c895ebe1..c1f15cbc1870d1fa7ca80b62060c223ded32291d 100644 (file)
@@ -892,78 +892,71 @@ ldap_int_tls_start ( LDAP *ld, LDAPConn *conn, LDAPURLDesc *srv )
        ld->ld_errno = LDAP_SUCCESS;
        ret = ldap_int_tls_connect( ld, conn, host );
 
+        /* this mainly only happens for non-blocking io
+         * but can also happen when the handshake is too
+         * big for a single network message.
+         */
+       while ( ret > 0 ) {
 #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 if not async */
-                       if ( !async ) {
-                               ber_sockbuf_ctrl( sb, LBER_SB_OPT_SET_NONBLOCK, (void*)1 );
+               if ( async ) {
+                       struct timeval curr_time_tv, delta_tv;
+                       int wr=0;
+
+                       if ( sb->sb_trans_needs_read ) {
+                               wr=0;
+                       } else if ( sb->sb_trans_needs_write ) {
+                               wr=1;
                        }
-                       ret = ldap_int_tls_connect( ld, conn, host );
-                       if ( ret > 0 ) { /* need to call tls_connect once more */
-                               struct timeval curr_time_tv, delta_tv;
+                       Debug1( LDAP_DEBUG_TRACE, "ldap_int_tls_start: ldap_int_tls_connect needs %s\n",
+                                       wr ? "write": "read" );
 
-                               /* This is mostly copied from result.c:wait4msg(), should
-                                * probably be moved into a separate function */
+                       /* This is mostly copied from result.c:wait4msg(), should
+                        * probably be moved into a separate function */
 #ifdef HAVE_GETTIMEOFDAY
-                               gettimeofday( &curr_time_tv, NULL );
+                       gettimeofday( &curr_time_tv, NULL );
 #else /* ! HAVE_GETTIMEOFDAY */
-                               time( &curr_time_tv.tv_sec );
-                               curr_time_tv.tv_usec = 0;
+                       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;
-                               }
+                       /* 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 );
+                       /* 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;
+                       }
+                       /* 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;
+                       Debug3( 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 );
+                       ret = ldap_int_poll( ld, sd, &tv, wr);
+                       if ( ret < 0 ) {
+                               ld->ld_errno = LDAP_TIMEOUT;
+                               break;
                        }
                }
-       }
-       /* Leave it nonblocking if async */
-       if ( !async && ld->ld_options.ldo_tm_net.tv_sec >= 0 ) {
-               ber_sockbuf_ctrl( sb, LBER_SB_OPT_SET_NONBLOCK, NULL );
-       }
 #endif /* LDAP_USE_NON_BLOCKING_TLS */
+               ret = ldap_int_tls_connect( ld, conn, host );
+       }
 
        if ( ret < 0 ) {
                if ( ld->ld_errno == LDAP_SUCCESS )