/* ** Virtual I/O library for SSL wrapper ** Written by Andrei Errapart <andreie@no.spam.ee> */ /* * This file has some huge DBUG_ statements. Boy, this is silly... */ #include "vio-global.h" #ifdef VIO_HAVE_OPENSSL #include <assert.h> #include <netinet/in.h> #include <openssl/x509.h> #include <openssl/ssl.h> #include <openssl/err.h> #include <openssl/pem.h> #ifdef __GNUC__ #pragma implementation // gcc: Class implementation #endif VIO_NS_BEGIN #define this_ssl_con my_static_cast(SSL*)(this->ssl_con_) #define this_bio my_static_cast(BIO*)(this->bio_) typedef char* dataptr_t; static void report_errors() { unsigned long l; const char* file; const char* data; int line,flags; DBUG_ENTER("VioSSLConnectorFd::report_errors"); while ((l=ERR_get_error_line_data(&file,&line,&data,&flags)) != 0) { char buf[200]; DBUG_PRINT("error", ("OpenSSL: %s:%s:%d:%s\n", ERR_error_string(l,buf), file,line,(flags&ERR_TXT_STRING)?data:"")) ; } DBUG_VOID_RETURN; } //FIXME: duplicate code! VioSSL::VioSSL(int fd, vio_ptr ssl_context, int state) : bio_(0), ssl_con_(0), open_(FALSE), sd_(new VioSocket(fd)) { DBUG_ENTER("VioSSL::VioSSL"); DBUG_PRINT("enter", ("this=%p, fd=%d, ssl_context=%p, state=%d", this, fd, ssl_context, state)); assert(fd!=0); assert(ssl_context!=0); assert(state==state_connect || state==state_accept); if (!init_bio_(fd, ssl_context, state, BIO_NOCLOSE)) open_ = true; DBUG_VOID_RETURN; } VioSSL::VioSSL(VioSocket* sd, vio_ptr ssl_context, int state) :bio_(0), ssl_con_(0), open_(FALSE), sd_(sd) { DBUG_ENTER("VioSSL::VioSSL"); DBUG_PRINT("enter", ("this=%p, sd=%s, ssl_context=%p, state=%d", this, sd ? sd->description() : "0", ssl_context, state)); assert(sd != 0); assert(ssl_context != 0); assert(state == state_connect || state==state_accept); if (!init_bio_(sd->sd_, ssl_context, state, BIO_NOCLOSE)) open_ = true; DBUG_VOID_RETURN; } VioSSL::~VioSSL() { DBUG_ENTER("VioSSL::~VioSSL"); DBUG_PRINT("enter", ("this=%p", this)); if (ssl_con_!=0) { SSL_shutdown(this_ssl_con); SSL_free(this_ssl_con); } if (sd_!=0) delete sd_; /* FIXME: no need to close bio? */ /* if (bio_!=0) BIO_free(this_bio); */ DBUG_VOID_RETURN; } bool VioSSL::is_open() const { return open_; } int VioSSL::read(vio_ptr buf, int size) { int r; DBUG_ENTER("VioSSL::read"); DBUG_PRINT("enter", ("this=%p, buf=%p, size=%d", this, buf, size)); assert(this_ssl_con != 0); r = SSL_read(this_ssl_con, my_static_cast(dataptr_t)(buf), size); if ( r< 0) report_errors(); DBUG_PRINT("exit", ("r=%d", r)); DBUG_RETURN(r); } int VioSSL::write(const vio_ptr buf, int size) { int r; DBUG_ENTER("VioSSL::write"); DBUG_PRINT("enter", ("this=%p, buf=%p, size=%d", this, buf, size)); assert(this_ssl_con!=0); r = SSL_write(this_ssl_con, my_static_cast(dataptr_t)(buf), size); if (r<0) report_errors(); DBUG_PRINT("exit", ("r=%d", r)); DBUG_RETURN(r); } int VioSSL::blocking(bool onoff) { int r; DBUG_ENTER("VioSSL::blocking"); DBUG_PRINT("enter", ("this=%p, onoff=%s", this, onoff?"true":"false")); r = sd_->blocking(onoff); DBUG_PRINT("exit", ("r=%d", (int)r )); DBUG_RETURN(r); } bool VioSSL::blocking() const { bool r; DBUG_ENTER("VioSSL::blocking"); DBUG_PRINT("enter", ("this=%p", this)); r = sd_->blocking(); DBUG_PRINT("exit", ("r=%d", (int)r )); DBUG_RETURN(r); } int VioSSL::fastsend(bool onoff) { int r; DBUG_ENTER("VioSSL::fastsend"); DBUG_PRINT("enter", ("this=%p, onoff=%d", this, (int) onoff)); r = sd_->fastsend(onoff); DBUG_PRINT("exit", ("r=%d", (int)r )); DBUG_RETURN(r); } int VioSSL::keepalive(bool onoff) { int r; DBUG_ENTER("VioSSL::keepalive"); DBUG_PRINT("enter", ("this=%p, onoff=%d", this, (int) onoff)); r = sd_->keepalive(onoff); DBUG_PRINT("exit", ("r=%d", int(r) )); DBUG_RETURN(r); } bool VioSSL::fcntl() const { bool r; DBUG_ENTER("VioSSL::fcntl"); DBUG_PRINT("enter", ("this=%p", this)); r = sd_->fcntl(); DBUG_PRINT("exit", ("r=%d", (int)r )); DBUG_RETURN(r); } bool VioSSL::should_retry() const { bool r; DBUG_ENTER("VioSSL::should_retry"); DBUG_PRINT("enter", ("this=%p", this)); r = sd_->should_retry(); DBUG_PRINT("exit", ("r=%d", (int)r )); DBUG_RETURN(r); } int VioSSL::close() { int r= -2; DBUG_ENTER("VioSSL::close"); DBUG_PRINT("enter", ("this=%p", this)); if (ssl_con) { r = SSL_shutdown(this_ssl_con); SSL_free(this_ssl_con); ssl_con_ = 0; BIO_free(this_bio); bio_ = 0; } DBUG_PRINT("exit", ("r=%d", r)); DBUG_RETURN(r); } const char* VioSSL::description() const { return desc_; } const char* VioSSL::peer_addr() const { if (sd_!=0) return sd != 0 ? sd_->peer_addr() : ""; } const char* VioSSL::peer_name() const { return sd != 0 ? sd_->peer_name() : ""; } const char* VioSSL::cipher_description() const { return SSL_get_cipher_name(this_ssl_con); } int VioSSL::init_bio_(int fd, vio_ptr ssl_context, int state, int bio_flags) { DBUG_ENTER("VioSSL::init_bio_"); DBUG_PRINT("enter", ("this=%p, fd=%p, ssl_context=%p, state=%d, bio_flags=%d", this, fd, ssl_context, state, bio_flags)); if (!(ssl_con_ = SSL_new(my_static_cast(SSL_CTX*)(ssl_context)))) { DBUG_PRINT("error", ("SSL_new failure")); report_errors(); DBUG_RETURN(-1); } if (!(bio_ = BIO_new_socket(fd, bio_flags))) { DBUG_PRINT("error", ("BIO_new_socket failure")); report_errors(); SSL_free(ssl_con_); ssl_con_ =0; DBUG_RETURN(-1); } SSL_set_bio(this_ssl_con, this_bio, this_bio); switch(state) { case state_connect: SSL_set_connect_state(this_ssl_con); break; case state_accept: SSL_set_accept_state(this_ssl_con); break; default: assert(0); } sprintf(desc_, "VioSSL(%d)", fd); ssl_cip_ = new SSL_CIPHER ; DBUG_RETURN(0); } VIO_NS_END #endif /* VIO_HAVE_OPENSSL */