From f0c4f83ea28b4fd85378b539aef5ab73b1b66bc4 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Wed, 10 May 2000 17:07:09 +0000 Subject: [PATCH] libldap/tls.c: change tls_verify_cb to no longer ignore verification errors. This means a ldaps connection may drop before any LDAP protocol exchange occurs (due to expired cert, unrecognized CAs, etc.). Change ldap_pvt_tls_connect to copy any TLS error string to ld_error upon connection failure, otherwise client just sees "can't contact LDAP server." slapd/connection.c: add flush/delay when SSL_accept fails, to allow any TLS alerts we generated to propagate back to the client. (Which will then be picked up by ldap_pvt_tls_connect on the client...) --- include/ldap_pvt.h | 7 +++-- libraries/libldap/tls.c | 58 ++++++++++++++++++++++++++++++++------ servers/slapd/connection.c | 20 ++++++++++++- 3 files changed, 73 insertions(+), 12 deletions(-) diff --git a/include/ldap_pvt.h b/include/ldap_pvt.h index 6164c05743..b4da5008b7 100644 --- a/include/ldap_pvt.h +++ b/include/ldap_pvt.h @@ -138,15 +138,18 @@ ldap_pvt_str2lower LDAP_P(( char *str )); /* tls.c */ struct ldapoptions; +struct ldap; LIBLDAP_F (int) ldap_pvt_tls_init LDAP_P(( void )); LIBLDAP_F (int) ldap_pvt_tls_config LDAP_P(( struct ldapoptions *lo, int option, const char *arg )); -LIBLDAP_F (int) ldap_pvt_tls_connect LDAP_P(( Sockbuf *sb, void *ctx_arg )); +LIBLDAP_F (int) ldap_pvt_tls_connect LDAP_P(( struct ldap *ld, Sockbuf *sb, void *ctx_arg )); LIBLDAP_F (int) ldap_pvt_tls_accept LDAP_P(( Sockbuf *sb, void *ctx_arg )); LIBLDAP_F (int) ldap_pvt_tls_get_option LDAP_P(( struct ldapoptions *lo, int option, void *arg )); LIBLDAP_F (int) ldap_pvt_tls_set_option LDAP_P(( struct ldapoptions *lo, int option, void *arg )); +LIBLDAP_F (void *) ldap_pvt_tls_sb_handle LDAP_P(( Sockbuf *sb )); +LIBLDAP_F (void *) ldap_pvt_tls_get_handle LDAP_P(( struct ldap *ld )); LIBLDAP_F (int) ldap_pvt_tls_inplace LDAP_P(( Sockbuf *sb )); -LIBLDAP_F (int) ldap_pvt_tls_start LDAP_P(( Sockbuf *sb, void *ctx_arg )); +LIBLDAP_F (int) ldap_pvt_tls_start LDAP_P(( struct ldap *ld, Sockbuf *sb, void *ctx_arg )); /* * UTF-8 (in utf-8.c) diff --git a/libraries/libldap/tls.c b/libraries/libldap/tls.c index d1d786a541..71bd5c8c77 100644 --- a/libraries/libldap/tls.c +++ b/libraries/libldap/tls.c @@ -27,6 +27,8 @@ #ifdef HAVE_OPENSSL_SSL_H #include +#include +#include #elif defined( HAVE_SSL_H ) #include #endif @@ -46,7 +48,7 @@ static int tls_remove( Sockbuf *sb ); static ber_slen_t tls_read( Sockbuf *sb, void *buf, ber_len_t len ); static ber_slen_t tls_write( Sockbuf *sb, void *buf, ber_len_t len ); static int tls_close( Sockbuf *sb ); -static int tls_report_error( void ); +static void tls_report_error( void ); static Sockbuf_IO tls_io= { @@ -60,9 +62,12 @@ static Sockbuf_IO tls_io= static void tls_info_cb( SSL *ssl, int where, int ret ); static int tls_verify_cb( int ok, X509_STORE_CTX *ctx ); static RSA * tls_tmp_rsa_cb( SSL *ssl, int is_export, int key_length ); -static DH * tls_tmp_dh_cb( SSL *ssl, int is_export, int key_length ); static STACK_OF(X509_NAME) * get_ca_list( char * bundle, char * dir ); +#if 0 /* Currently this is not used by anyone */ +static DH * tls_tmp_dh_cb( SSL *ssl, int is_export, int key_length ); +#endif + static SSL_CTX *tls_def_ctx = NULL; #ifdef LDAP_R_COMPILE @@ -302,7 +307,7 @@ update_flags( Sockbuf *sb, SSL * ssl, int rc ) */ int -ldap_pvt_tls_connect( Sockbuf *sb, void *ctx_arg ) +ldap_pvt_tls_connect( LDAP *ld, Sockbuf *sb, void *ctx_arg ) { int err; SSL *ssl; @@ -319,9 +324,16 @@ ldap_pvt_tls_connect( Sockbuf *sb, void *ctx_arg ) err = SSL_connect( ssl ); +#ifdef HAVE_WINSOCK + errno = WSAGetLastError(); +#endif if ( err <= 0 ) { if ( update_flags( sb, ssl, err )) return 1; + if ((err = ERR_peek_error())) { + char buf[256]; + ld->ld_error = ldap_strdup(ERR_error_string(err, buf)); + } Debug( LDAP_DEBUG_ANY,"TLS: can't connect.\n",0,0,0); ber_pvt_sb_clear_io( sb ); ber_pvt_sb_set_io( sb, &ber_pvt_sb_io_tcp, NULL ); @@ -352,6 +364,9 @@ ldap_pvt_tls_accept( Sockbuf *sb, void *ctx_arg ) err = SSL_accept( ssl ); +#ifdef HAVE_WINSOCK + errno = WSAGetLastError(); +#endif if ( err <= 0 ) { if ( update_flags( sb, ssl, err )) return 1; @@ -372,14 +387,31 @@ ldap_pvt_tls_inplace ( Sockbuf *sb ) return(0); } +void * +ldap_pvt_tls_sb_handle( Sockbuf *sb ) +{ + if (HAS_TLS( sb )) + return sb->sb_iodata; + else + return NULL; +} + +void * +ldap_pvt_tls_get_handle( LDAP *ld ) +{ + return ldap_pvt_tls_sb_handle(&ld->ld_sb); +} + const char * ldap_pvt_tls_get_peer( LDAP *ld ) { + return NULL; } const char * ldap_pvt_tls_get_peer_issuer( LDAP *ld ) { + return NULL; } int @@ -427,9 +459,9 @@ ldap_pvt_tls_get_option( struct ldapoptions *lo, int option, void *arg ) break; case LDAP_OPT_X_TLS_CERT: if ( lo == NULL ) - arg = (void *) tls_def_ctx; + *(void **)arg = (void *) tls_def_ctx; else - arg = lo->ldo_tls_ctx; + *(void **)arg = lo->ldo_tls_ctx; break; case LDAP_OPT_X_TLS_CACERTFILE: *(char **)arg = tls_opt_cacertfile ? @@ -520,12 +552,12 @@ ldap_pvt_tls_set_option( struct ldapoptions *lo, int option, void *arg ) } int -ldap_pvt_tls_start ( Sockbuf *sb, void *ctx_arg ) +ldap_pvt_tls_start ( LDAP *ld, Sockbuf *sb, void *ctx_arg ) { /* * Fortunately, the lib uses blocking io... */ - if ( ldap_pvt_tls_connect( sb, ctx_arg ) < 0 ) { + if ( ldap_pvt_tls_connect( ld, sb, ctx_arg ) < 0 ) { return LDAP_CONNECT_ERROR; } @@ -556,6 +588,9 @@ tls_write( Sockbuf *sb, void *buf, ber_len_t sz ) { int ret = SSL_write( (SSL *)sb->sb_iodata, buf, sz ); +#ifdef HAVE_WINSOCK + errno = WSAGetLastError(); +#endif update_flags(sb, (SSL *)sb->sb_iodata, ret ); #ifdef WIN32 if (sb->sb_trans_needs_write) @@ -569,6 +604,9 @@ tls_read( Sockbuf *sb, void *buf, ber_len_t sz ) { int ret = SSL_read( (SSL *)sb->sb_iodata, buf, sz ); +#ifdef HAVE_WINSOCK + errno = WSAGetLastError(); +#endif update_flags(sb, (SSL *)sb->sb_iodata, ret ); #ifdef WIN32 if (sb->sb_trans_needs_read) @@ -658,11 +696,11 @@ tls_verify_cb( int ok, X509_STORE_CTX *ctx ) if ( iname ) CRYPTO_free ( iname ); - return 1; + return ok; } /* Inspired by ERR_print_errors in OpenSSL */ -static int +static void tls_report_error( void ) { unsigned long l; @@ -693,11 +731,13 @@ tls_tmp_rsa_cb( SSL *ssl, int is_export, int key_length ) return tmp_rsa; } +#if 0 static DH * tls_tmp_dh_cb( SSL *ssl, int is_export, int key_length ) { return NULL; } +#endif #else static int dummy; diff --git a/servers/slapd/connection.c b/servers/slapd/connection.c index 4afec31af0..2c6847a853 100644 --- a/servers/slapd/connection.c +++ b/servers/slapd/connection.c @@ -881,6 +881,9 @@ int connection_read(ber_socket_t s) if ( c->c_is_tls && c->c_needs_tls_accept ) { rc = ldap_pvt_tls_accept( c->c_sb, NULL ); if ( rc < 0 ) { + struct timeval tv; + fd_set rfd; + Debug( LDAP_DEBUG_TRACE, "connection_read(%d): TLS accept error error=%d id=%ld, closing\n", s, rc, c->c_connid ); @@ -888,6 +891,21 @@ int connection_read(ber_socket_t s) c->c_needs_tls_accept = 0; /* connections_mutex and c_mutex are locked */ connection_closing( c ); + + /* Drain input before close, to allow SSL error codes + * to propagate to client. */ + FD_ZERO(&rfd); + FD_SET(s, &rfd); + ber_pvt_sb_set_readahead(c->c_sb, 0); + for (rc=1; rc>0;) + { + char buf[4096]; + tv.tv_sec = 1; + tv.tv_usec = 0; + rc = select(s+1, &rfd, NULL, NULL, &tv); + if (rc == 1) + rc = ber_pvt_sb_read(c->c_sb, buf, sizeof(buf)); + } connection_close( c ); } else if ( rc == 0 ) { c->c_needs_tls_accept = 0; @@ -954,7 +972,7 @@ connection_input( Debug( LDAP_DEBUG_TRACE, "ber_get_next on fd %d failed errno=%d (%s)\n", - ber_pvt_sb_get_desc( conn->c_sb ), err, STRERROR(err) ); + ber_pvt_sb_get_desc( conn->c_sb ), err, sock_errstr(err) ); Debug( LDAP_DEBUG_TRACE, "\t*** got %ld of %lu so far\n", (long) ( conn->c_currentber->ber_buf -- 2.39.5