mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 03:52:35 +01:00
292 lines
5.9 KiB
C++
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 */
|
|
|