int ldap_int_tls_start ( LDAP *ld, LDAPConn *conn, LDAPURLDesc *srv ) { Sockbuf *sb; char *host; void *ssl; if ( !conn ) return LDAP_PARAM_ERROR; sb = conn->lconn_sb; if( srv ) { host = srv->lud_host; } else { host = conn->lconn_server->lud_host; } /* avoid NULL host */ if( host == NULL ) { host = "localhost"; } (void) tls_init( tls_imp ); /* * Fortunately, the lib uses blocking io... */ if ( ldap_int_tls_connect( ld, conn ) < 0 ) { ld->ld_errno = LDAP_CONNECT_ERROR; return (ld->ld_errno); } ssl = ldap_pvt_tls_sb_ctx( sb ); assert( ssl != NULL ); /* * compare host with name(s) in certificate */ if (ld->ld_options.ldo_tls_require_cert != LDAP_OPT_X_TLS_NEVER && ld->ld_options.ldo_tls_require_cert != LDAP_OPT_X_TLS_ALLOW) { ld->ld_errno = ldap_pvt_tls_check_hostname( ld, ssl, host ); if (ld->ld_errno != LDAP_SUCCESS) { return ld->ld_errno; } } return LDAP_SUCCESS; }
int 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; sb = conn->lconn_sb; if( srv ) { host = srv->lud_host; } else { host = conn->lconn_server->lud_host; } /* avoid NULL host */ if( host == NULL ) { host = "localhost"; } (void) tls_init( tls_imp ); #ifdef LDAP_USE_NON_BLOCKING_TLS /* * Use non-blocking io during SSL Handshake when a timeout is configured */ 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); } ssl = ldap_pvt_tls_sb_ctx( sb ); assert( ssl != NULL ); /* * compare host with name(s) in certificate */ if (ld->ld_options.ldo_tls_require_cert != LDAP_OPT_X_TLS_NEVER && ld->ld_options.ldo_tls_require_cert != LDAP_OPT_X_TLS_ALLOW) { ld->ld_errno = ldap_pvt_tls_check_hostname( ld, ssl, host ); if (ld->ld_errno != LDAP_SUCCESS) { return ld->ld_errno; } } return LDAP_SUCCESS; }
int ldap_int_tls_start ( LDAP *ld, LDAPConn *conn, LDAPURLDesc *srv ) { Sockbuf *sb; char *host; void *ssl; if ( !conn ) return LDAP_PARAM_ERROR; sb = conn->lconn_sb; if( srv ) { host = srv->lud_host; } else { host = conn->lconn_server->lud_host; } /* avoid NULL host */ if( host == NULL ) { host = "localhost"; } (void) tls_init( tls_imp ); #if defined(__APPLE__) && !defined(HAVE_SECURE_TRANSPORT) /* Get the host's certificate from the keychain if possible, and stash * it in the options for use once the SSL context is created. */ tls_get_cert_from_keychain( host ); #endif /* * Fortunately, the lib uses blocking io... */ if ( ldap_int_tls_connect( ld, conn ) < 0 ) { ld->ld_errno = LDAP_CONNECT_ERROR; return (ld->ld_errno); } ssl = ldap_pvt_tls_sb_ctx( sb ); assert( ssl != NULL ); /* * compare host with name(s) in certificate */ if (ld->ld_options.ldo_tls_require_cert != LDAP_OPT_X_TLS_NEVER && ld->ld_options.ldo_tls_require_cert != LDAP_OPT_X_TLS_ALLOW) { ld->ld_errno = ldap_pvt_tls_check_hostname( ld, ssl, host ); if (ld->ld_errno != LDAP_SUCCESS) { #ifdef __APPLE__ /* If the hostname is really an IP address, do the reverse * lookup and see if that matches the cert. */ char *hostname = ldap_host_connected_to( sb, host ); if (hostname) { Debug( LDAP_DEBUG_ANY, "TLS reverse lookup of '%s' is '%s', checking if that matches the certificate common name\n", host, hostname, 0); ld->ld_errno = ldap_pvt_tls_check_hostname( ld, ssl, hostname ); free(hostname); hostname = NULL; } #endif return ld->ld_errno; } } return LDAP_SUCCESS; }