mariadb/vio/VioSSL.cc
bk@work.mysql.com f4c589ff6c Import changeset
2000-07-31 21:29:14 +02:00

292 lines
5.9 KiB
C++

/*
** 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 */