Redesign logic of SSL connections to work with status in client DCB instead of in the protocol. This eases the way to moving SSL logic out of a specific protocol (currently MySQL) so as to be available across any protocol. Also, some simplification.
This commit is contained in:
@ -223,6 +223,9 @@ dcb_alloc(dcb_role_t role)
|
|||||||
newdcb->callbacks = NULL;
|
newdcb->callbacks = NULL;
|
||||||
newdcb->data = NULL;
|
newdcb->data = NULL;
|
||||||
|
|
||||||
|
newdcb->listen_ssl = NULL;
|
||||||
|
newdcb->ssl_state = SSL_HANDSHAKE_UNKNOWN;
|
||||||
|
|
||||||
newdcb->remote = NULL;
|
newdcb->remote = NULL;
|
||||||
newdcb->user = NULL;
|
newdcb->user = NULL;
|
||||||
newdcb->flags = 0;
|
newdcb->flags = 0;
|
||||||
@ -280,6 +283,7 @@ dcb_clone(DCB *orig)
|
|||||||
clonedcb->state = orig->state;
|
clonedcb->state = orig->state;
|
||||||
clonedcb->data = orig->data;
|
clonedcb->data = orig->data;
|
||||||
clonedcb->listen_ssl = orig->listen_ssl;
|
clonedcb->listen_ssl = orig->listen_ssl;
|
||||||
|
clonedcb->ssl_state = orig->ssl_state;
|
||||||
if (orig->remote)
|
if (orig->remote)
|
||||||
{
|
{
|
||||||
clonedcb->remote = strdup(orig->remote);
|
clonedcb->remote = strdup(orig->remote);
|
||||||
@ -2863,42 +2867,56 @@ int dcb_create_SSL(DCB* dcb)
|
|||||||
int dcb_accept_SSL(DCB* dcb)
|
int dcb_accept_SSL(DCB* dcb)
|
||||||
{
|
{
|
||||||
int ssl_rval;
|
int ssl_rval;
|
||||||
|
char *remote;
|
||||||
|
char *user;
|
||||||
|
|
||||||
|
if (dcb->ssl == NULL && dcb_create_SSL(dcb) != 0)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
remote = dcb->remote ? dcb->remote : "";
|
||||||
|
user = dcb->user ? dcb->user : "";
|
||||||
|
|
||||||
ssl_rval = SSL_accept(dcb->ssl);
|
ssl_rval = SSL_accept(dcb->ssl);
|
||||||
|
|
||||||
switch (SSL_get_error(dcb->ssl, ssl_rval))
|
switch (SSL_get_error(dcb->ssl, ssl_rval))
|
||||||
{
|
{
|
||||||
case SSL_ERROR_NONE:
|
case SSL_ERROR_NONE:
|
||||||
MXS_DEBUG("SSL_accept done for %s", dcb->remote);
|
MXS_DEBUG("SSL_accept done for %s@%s", user, remote);
|
||||||
|
dcb->ssl_state = SSL_HANDSHAKE_DONE;
|
||||||
return 1;
|
return 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SSL_ERROR_WANT_READ:
|
case SSL_ERROR_WANT_READ:
|
||||||
MXS_DEBUG("SSL_accept ongoing want read for %s", dcb->remote);
|
MXS_DEBUG("SSL_accept ongoing want read for %s@%s", user, remote);
|
||||||
return 0;
|
return 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SSL_ERROR_WANT_WRITE:
|
case SSL_ERROR_WANT_WRITE:
|
||||||
MXS_DEBUG("SSL_accept ongoing want write for %s", dcb->remote);
|
MXS_DEBUG("SSL_accept ongoing want write for %s@%s", user, remote);
|
||||||
return 0;
|
return 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SSL_ERROR_ZERO_RETURN:
|
case SSL_ERROR_ZERO_RETURN:
|
||||||
MXS_DEBUG("SSL error, shut down cleanly during SSL accept %s", dcb->remote);
|
MXS_DEBUG("SSL error, shut down cleanly during SSL accept %s@%s", user, remote);
|
||||||
dcb_log_errors_SSL(dcb, __func__, 0);
|
dcb_log_errors_SSL(dcb, __func__, 0);
|
||||||
poll_fake_hangup_event(dcb);
|
poll_fake_hangup_event(dcb);
|
||||||
return 0;
|
return 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SSL_ERROR_SYSCALL:
|
case SSL_ERROR_SYSCALL:
|
||||||
MXS_DEBUG("SSL connection SSL_ERROR_SYSCALL error during accept %s", dcb->remote);
|
MXS_DEBUG("SSL connection SSL_ERROR_SYSCALL error during accept %s@%s", user, remote);
|
||||||
dcb_log_errors_SSL(dcb, __func__, ssl_rval);
|
dcb_log_errors_SSL(dcb, __func__, ssl_rval);
|
||||||
|
dcb->ssl_state = SSL_HANDSHAKE_FAILED;
|
||||||
poll_fake_hangup_event(dcb);
|
poll_fake_hangup_event(dcb);
|
||||||
return -1;
|
return -1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
MXS_DEBUG("SSL connection shut down with error during SSL accept %s", dcb->remote);
|
MXS_DEBUG("SSL connection shut down with error during SSL accept %s@%s", user, remote);
|
||||||
dcb_log_errors_SSL(dcb, __func__, 0);
|
dcb_log_errors_SSL(dcb, __func__, 0);
|
||||||
|
dcb->ssl_state = SSL_HANDSHAKE_FAILED;
|
||||||
poll_fake_hangup_event(dcb);
|
poll_fake_hangup_event(dcb);
|
||||||
return -1;
|
return -1;
|
||||||
break;
|
break;
|
||||||
|
@ -59,6 +59,7 @@ struct service;
|
|||||||
* 23/09/2014 Mark Riddoch New poll processing queue
|
* 23/09/2014 Mark Riddoch New poll processing queue
|
||||||
* 19/06/2015 Martin Brampton Provision of persistent connections
|
* 19/06/2015 Martin Brampton Provision of persistent connections
|
||||||
* 20/01/2016 Martin Brampton Moved GWPROTOCOL to gw_protocol.h
|
* 20/01/2016 Martin Brampton Moved GWPROTOCOL to gw_protocol.h
|
||||||
|
* 01/02/2016 Martin Brampton Added fields for SSL and authentication
|
||||||
*
|
*
|
||||||
* @endverbatim
|
* @endverbatim
|
||||||
*/
|
*/
|
||||||
@ -173,6 +174,17 @@ typedef struct dcb_callback
|
|||||||
struct dcb_callback *next; /*< Next callback for this DCB */
|
struct dcb_callback *next; /*< Next callback for this DCB */
|
||||||
} DCB_CALLBACK;
|
} DCB_CALLBACK;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* State of SSL connection
|
||||||
|
*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
SSL_HANDSHAKE_UNKNOWN, /*< The DCB has unknown SSL status */
|
||||||
|
SSL_HANDSHAKE_REQUIRED, /*< SSL handshake is needed */
|
||||||
|
SSL_HANDSHAKE_DONE, /*< The SSL handshake completed OK */
|
||||||
|
SSL_ESTABLISHED, /*< The SSL connection is in use */
|
||||||
|
SSL_HANDSHAKE_FAILED /*< The SSL handshake failed */
|
||||||
|
} SSL_STATE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Descriptor Control Block
|
* Descriptor Control Block
|
||||||
@ -195,6 +207,7 @@ typedef struct dcb
|
|||||||
DCBEVENTQ evq; /**< The event queue for this DCB */
|
DCBEVENTQ evq; /**< The event queue for this DCB */
|
||||||
int fd; /**< The descriptor */
|
int fd; /**< The descriptor */
|
||||||
dcb_state_t state; /**< Current descriptor state */
|
dcb_state_t state; /**< Current descriptor state */
|
||||||
|
SSL_STATE ssl_state; /**< Current state of SSL if in use */
|
||||||
int flags; /**< DCB flags */
|
int flags; /**< DCB flags */
|
||||||
char *remote; /**< Address of remote end */
|
char *remote; /**< Address of remote end */
|
||||||
char *user; /**< User name for connection */
|
char *user; /**< User name for connection */
|
||||||
|
@ -96,13 +96,19 @@ struct dcb;
|
|||||||
#define MYSQL_FAILED_AUTH_SSL 3
|
#define MYSQL_FAILED_AUTH_SSL 3
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
MYSQL_ALLOC,
|
MYSQL_ALLOC, /* Initial state of protocol auth state */
|
||||||
|
/* The following are used only for backend connections */
|
||||||
MYSQL_PENDING_CONNECT,
|
MYSQL_PENDING_CONNECT,
|
||||||
MYSQL_CONNECTED,
|
MYSQL_CONNECTED,
|
||||||
|
/* The following can be used for either client or backend */
|
||||||
|
/* The comments have only been checked for client use at present */
|
||||||
MYSQL_AUTH_SENT,
|
MYSQL_AUTH_SENT,
|
||||||
MYSQL_AUTH_RECV,
|
MYSQL_AUTH_RECV, /* This is only ever a transient value */
|
||||||
MYSQL_AUTH_FAILED,
|
MYSQL_AUTH_FAILED, /* Once this is set, the connection */
|
||||||
|
/* will be ended, so this is transient */
|
||||||
|
/* The following is used only for backend connections */
|
||||||
MYSQL_HANDSHAKE_FAILED,
|
MYSQL_HANDSHAKE_FAILED,
|
||||||
|
/* The following are obsolete and will be removed */
|
||||||
MYSQL_AUTH_SSL_REQ, /*< client requested SSL but SSL_accept hasn't beed called */
|
MYSQL_AUTH_SSL_REQ, /*< client requested SSL but SSL_accept hasn't beed called */
|
||||||
MYSQL_AUTH_SSL_HANDSHAKE_DONE, /*< SSL handshake has been fully completed */
|
MYSQL_AUTH_SSL_HANDSHAKE_DONE, /*< SSL handshake has been fully completed */
|
||||||
MYSQL_AUTH_SSL_HANDSHAKE_FAILED, /*< SSL handshake failed for any reason */
|
MYSQL_AUTH_SSL_HANDSHAKE_FAILED, /*< SSL handshake failed for any reason */
|
||||||
@ -232,38 +238,38 @@ typedef enum mysql_server_cmd {
|
|||||||
MYSQL_COM_INIT_DB,
|
MYSQL_COM_INIT_DB,
|
||||||
MYSQL_COM_QUERY,
|
MYSQL_COM_QUERY,
|
||||||
MYSQL_COM_FIELD_LIST,
|
MYSQL_COM_FIELD_LIST,
|
||||||
MYSQL_COM_CREATE_DB,
|
MYSQL_COM_CREATE_DB,
|
||||||
MYSQL_COM_DROP_DB,
|
MYSQL_COM_DROP_DB,
|
||||||
MYSQL_COM_REFRESH,
|
MYSQL_COM_REFRESH,
|
||||||
MYSQL_COM_SHUTDOWN,
|
MYSQL_COM_SHUTDOWN,
|
||||||
MYSQL_COM_STATISTICS,
|
MYSQL_COM_STATISTICS,
|
||||||
MYSQL_COM_PROCESS_INFO,
|
MYSQL_COM_PROCESS_INFO,
|
||||||
MYSQL_COM_CONNECT,
|
MYSQL_COM_CONNECT,
|
||||||
MYSQL_COM_PROCESS_KILL,
|
MYSQL_COM_PROCESS_KILL,
|
||||||
MYSQL_COM_DEBUG,
|
MYSQL_COM_DEBUG,
|
||||||
MYSQL_COM_PING,
|
MYSQL_COM_PING,
|
||||||
MYSQL_COM_TIME,
|
MYSQL_COM_TIME,
|
||||||
MYSQL_COM_DELAYED_INSERT,
|
MYSQL_COM_DELAYED_INSERT,
|
||||||
MYSQL_COM_CHANGE_USER,
|
MYSQL_COM_CHANGE_USER,
|
||||||
MYSQL_COM_BINLOG_DUMP,
|
MYSQL_COM_BINLOG_DUMP,
|
||||||
MYSQL_COM_TABLE_DUMP,
|
MYSQL_COM_TABLE_DUMP,
|
||||||
MYSQL_COM_CONNECT_OUT,
|
MYSQL_COM_CONNECT_OUT,
|
||||||
MYSQL_COM_REGISTER_SLAVE,
|
MYSQL_COM_REGISTER_SLAVE,
|
||||||
MYSQL_COM_STMT_PREPARE,
|
MYSQL_COM_STMT_PREPARE,
|
||||||
MYSQL_COM_STMT_EXECUTE,
|
MYSQL_COM_STMT_EXECUTE,
|
||||||
MYSQL_COM_STMT_SEND_LONG_DATA,
|
MYSQL_COM_STMT_SEND_LONG_DATA,
|
||||||
MYSQL_COM_STMT_CLOSE,
|
MYSQL_COM_STMT_CLOSE,
|
||||||
MYSQL_COM_STMT_RESET,
|
MYSQL_COM_STMT_RESET,
|
||||||
MYSQL_COM_SET_OPTION,
|
MYSQL_COM_SET_OPTION,
|
||||||
MYSQL_COM_STMT_FETCH,
|
MYSQL_COM_STMT_FETCH,
|
||||||
MYSQL_COM_DAEMON,
|
MYSQL_COM_DAEMON,
|
||||||
MYSQL_COM_END /*< Must be the last */
|
MYSQL_COM_END /*< Must be the last */
|
||||||
} mysql_server_cmd_t;
|
} mysql_server_cmd_t;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of server commands, and number of response packets are stored here.
|
* List of server commands, and number of response packets are stored here.
|
||||||
* server_command_t is used in MySQLProtocol structure, so for each DCB there is
|
* server_command_t is used in MySQLProtocol structure, so for each DCB there is
|
||||||
* one MySQLProtocol and one server command list.
|
* one MySQLProtocol and one server command list.
|
||||||
*/
|
*/
|
||||||
typedef struct server_command_st {
|
typedef struct server_command_st {
|
||||||
@ -275,8 +281,8 @@ typedef struct server_command_st {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* MySQL Protocol specific state data.
|
* MySQL Protocol specific state data.
|
||||||
*
|
*
|
||||||
* Protocol carries information from client side to backend side, such as
|
* Protocol carries information from client side to backend side, such as
|
||||||
* MySQL session command information and history of earlier session commands.
|
* MySQL session command information and history of earlier session commands.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -286,7 +292,7 @@ typedef struct {
|
|||||||
int fd; /*< The socket descriptor */
|
int fd; /*< The socket descriptor */
|
||||||
struct dcb *owner_dcb; /*< The DCB of the socket
|
struct dcb *owner_dcb; /*< The DCB of the socket
|
||||||
* we are running on */
|
* we are running on */
|
||||||
SPINLOCK protocol_lock;
|
SPINLOCK protocol_lock;
|
||||||
server_command_t protocol_command; /*< session command list */
|
server_command_t protocol_command; /*< session command list */
|
||||||
server_command_t* protocol_cmd_history; /*< session command history */
|
server_command_t* protocol_cmd_history; /*< session command history */
|
||||||
mysql_auth_state_t protocol_auth_state; /*< Authentication status */
|
mysql_auth_state_t protocol_auth_state; /*< Authentication status */
|
||||||
@ -346,7 +352,7 @@ int mysql_send_custom_error (
|
|||||||
const char* mysql_message);
|
const char* mysql_message);
|
||||||
|
|
||||||
GWBUF* mysql_create_custom_error(
|
GWBUF* mysql_create_custom_error(
|
||||||
int packet_number,
|
int packet_number,
|
||||||
int affected_rows,
|
int affected_rows,
|
||||||
const char* msg);
|
const char* msg);
|
||||||
|
|
||||||
@ -411,9 +417,9 @@ void protocol_archive_srv_command(MySQLProtocol* p);
|
|||||||
|
|
||||||
|
|
||||||
void init_response_status (
|
void init_response_status (
|
||||||
GWBUF* buf,
|
GWBUF* buf,
|
||||||
mysql_server_cmd_t cmd,
|
mysql_server_cmd_t cmd,
|
||||||
int* npackets,
|
int* npackets,
|
||||||
ssize_t* nbytes);
|
ssize_t* nbytes);
|
||||||
|
|
||||||
#endif /** _MYSQL_PROTOCOL_H */
|
#endif /** _MYSQL_PROTOCOL_H */
|
||||||
|
@ -77,14 +77,12 @@ static int gw_client_close(DCB *dcb);
|
|||||||
static int gw_client_hangup_event(DCB *dcb);
|
static int gw_client_hangup_event(DCB *dcb);
|
||||||
static int mysql_send_ok(DCB *dcb, int packet_number, int in_affected_rows, const char* mysql_message);
|
static int mysql_send_ok(DCB *dcb, int packet_number, int in_affected_rows, const char* mysql_message);
|
||||||
static int MySQLSendHandshake(DCB* dcb);
|
static int MySQLSendHandshake(DCB* dcb);
|
||||||
static int gw_mysql_do_authentication(DCB *dcb, GWBUF **queue);
|
static int gw_mysql_do_authentication(DCB *dcb, GWBUF **buf);
|
||||||
static int route_by_statement(SESSION *, GWBUF **);
|
static int route_by_statement(SESSION *, GWBUF **);
|
||||||
extern char* get_username_from_auth(char* ptr, uint8_t* data);
|
extern char* get_username_from_auth(char* ptr, uint8_t* data);
|
||||||
extern int check_db_name_after_auth(DCB *, char *, int);
|
extern int check_db_name_after_auth(DCB *, char *, int);
|
||||||
extern char* create_auth_fail_str(char *username, char *hostaddr, char *sha1, char *db,int);
|
extern char* create_auth_fail_str(char *username, char *hostaddr, char *sha1, char *db,int);
|
||||||
|
|
||||||
static int do_ssl_accept(MySQLProtocol* protocol);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The "module object" for the mysqld client protocol module.
|
* The "module object" for the mysqld client protocol module.
|
||||||
*/
|
*/
|
||||||
@ -485,7 +483,7 @@ static int gw_mysql_do_authentication(DCB *dcb, GWBUF **buf)
|
|||||||
|
|
||||||
/** Skip this if the SSL handshake is already done.
|
/** Skip this if the SSL handshake is already done.
|
||||||
* If not, start the SSL handshake. */
|
* If not, start the SSL handshake. */
|
||||||
if (protocol->protocol_auth_state != MYSQL_AUTH_SSL_HANDSHAKE_DONE)
|
if (protocol->owner_dcb->ssl_state != SSL_HANDSHAKE_DONE && protocol->owner_dcb->ssl_state != SSL_ESTABLISHED)
|
||||||
{
|
{
|
||||||
ssl = protocol->client_capabilities & GW_MYSQL_CAPABILITIES_SSL;
|
ssl = protocol->client_capabilities & GW_MYSQL_CAPABILITIES_SSL;
|
||||||
|
|
||||||
@ -510,11 +508,13 @@ static int gw_mysql_do_authentication(DCB *dcb, GWBUF **buf)
|
|||||||
|
|
||||||
/** Do the SSL Handshake */
|
/** Do the SSL Handshake */
|
||||||
/* if (ssl && protocol->owner_dcb->service->ssl_mode != SSL_DISABLED) */
|
/* if (ssl && protocol->owner_dcb->service->ssl_mode != SSL_DISABLED) */
|
||||||
if (ssl && NULL != protocol->owner_dcb->listen_ssl)
|
if (NULL != protocol->owner_dcb->listen_ssl)
|
||||||
{
|
{
|
||||||
protocol->protocol_auth_state = MYSQL_AUTH_SSL_REQ;
|
if (SSL_HANDSHAKE_UNKNOWN == protocol->owner_dcb->ssl_state)
|
||||||
|
{
|
||||||
if (do_ssl_accept(protocol) < 0)
|
protocol->owner_dcb->ssl_state = SSL_HANDSHAKE_REQUIRED;
|
||||||
|
}
|
||||||
|
if (dcb_accept_SSL(protocol->owner_dcb) < 0)
|
||||||
{
|
{
|
||||||
return MYSQL_FAILED_AUTH;
|
return MYSQL_FAILED_AUTH;
|
||||||
}
|
}
|
||||||
@ -611,7 +611,7 @@ static int gw_mysql_do_authentication(DCB *dcb, GWBUF **buf)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* on succesful auth set user into dcb field */
|
/* on successful auth set user into dcb field */
|
||||||
if (auth_ret == 0)
|
if (auth_ret == 0)
|
||||||
{
|
{
|
||||||
dcb->user = strdup(client_data->user);
|
dcb->user = strdup(client_data->user);
|
||||||
@ -679,13 +679,11 @@ int gw_read_client_event(DCB* dcb)
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** SSL authentication is still going on, we need to call do_ssl_accept
|
/** SSL authentication is still going on, we need to call dcb_accept_SSL
|
||||||
* until it return 1 for success or -1 for error */
|
* until it return 1 for success or -1 for error */
|
||||||
if (protocol->protocol_auth_state == MYSQL_AUTH_SSL_HANDSHAKE_ONGOING ||
|
if (protocol->owner_dcb->ssl_state == SSL_HANDSHAKE_REQUIRED)
|
||||||
protocol->protocol_auth_state == MYSQL_AUTH_SSL_REQ)
|
|
||||||
{
|
{
|
||||||
|
switch(dcb_accept_SSL(protocol->owner_dcb))
|
||||||
switch(do_ssl_accept(protocol))
|
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
return 0;
|
return 0;
|
||||||
@ -711,7 +709,7 @@ int gw_read_client_event(DCB* dcb)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (protocol->use_ssl)
|
if (SSL_HANDSHAKE_DONE == protocol->owner_dcb->ssl_state || SSL_ESTABLISHED == protocol->owner_dcb->ssl_state)
|
||||||
{
|
{
|
||||||
/** SSL handshake is done, communication is now encrypted with SSL */
|
/** SSL handshake is done, communication is now encrypted with SSL */
|
||||||
rc = dcb_read_SSL(dcb, &read_buffer);
|
rc = dcb_read_SSL(dcb, &read_buffer);
|
||||||
@ -837,21 +835,28 @@ int gw_read_client_event(DCB* dcb)
|
|||||||
{
|
{
|
||||||
case MYSQL_AUTH_SENT:
|
case MYSQL_AUTH_SENT:
|
||||||
{
|
{
|
||||||
int auth_val;
|
int auth_val, packet_number;
|
||||||
|
|
||||||
|
packet_number = protocol->owner_dcb->listen_ssl ? 3 : 2;
|
||||||
auth_val = gw_mysql_do_authentication(dcb, &read_buffer);
|
auth_val = gw_mysql_do_authentication(dcb, &read_buffer);
|
||||||
|
|
||||||
if (protocol->protocol_auth_state == MYSQL_AUTH_SSL_REQ ||
|
if (protocol->owner_dcb->ssl_state == SSL_HANDSHAKE_REQUIRED ||
|
||||||
protocol->protocol_auth_state == MYSQL_AUTH_SSL_HANDSHAKE_ONGOING ||
|
protocol->owner_dcb->ssl_state == SSL_HANDSHAKE_DONE ||
|
||||||
protocol->protocol_auth_state == MYSQL_AUTH_SSL_HANDSHAKE_DONE ||
|
protocol->owner_dcb->ssl_state == SSL_HANDSHAKE_FAILED)
|
||||||
protocol->protocol_auth_state == MYSQL_AUTH_SSL_HANDSHAKE_FAILED)
|
|
||||||
{
|
{
|
||||||
/** SSL was requested and the handshake is either done or
|
/** SSL was requested and the handshake is either done or
|
||||||
* still ongoing. After the handshake is done, the client
|
* still ongoing. After the handshake is done, the client
|
||||||
* will send another auth packet. */
|
* will send another auth packet. */
|
||||||
gwbuf_free(read_buffer);
|
if (protocol->owner_dcb->ssl_state == SSL_HANDSHAKE_DONE)
|
||||||
read_buffer = NULL;
|
{
|
||||||
break;
|
protocol->owner_dcb->ssl_state = SSL_ESTABLISHED;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gwbuf_free(read_buffer);
|
||||||
|
read_buffer = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auth_val == 0)
|
if (auth_val == 0)
|
||||||
@ -875,9 +880,9 @@ int gw_read_client_event(DCB* dcb)
|
|||||||
protocol->protocol_auth_state = MYSQL_IDLE;
|
protocol->protocol_auth_state = MYSQL_IDLE;
|
||||||
/**
|
/**
|
||||||
* Send an AUTH_OK packet to the client,
|
* Send an AUTH_OK packet to the client,
|
||||||
* packet sequence is # 2
|
* packet sequence is # packet_number
|
||||||
*/
|
*/
|
||||||
mysql_send_ok(dcb, 2, 0, NULL);
|
mysql_send_ok(dcb, packet_number, 0, NULL);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -890,7 +895,7 @@ int gw_read_client_event(DCB* dcb)
|
|||||||
|
|
||||||
/** Send ERR 1045 to client */
|
/** Send ERR 1045 to client */
|
||||||
mysql_send_auth_error(dcb,
|
mysql_send_auth_error(dcb,
|
||||||
2,
|
packet_number,
|
||||||
0,
|
0,
|
||||||
"failed to create new session");
|
"failed to create new session");
|
||||||
|
|
||||||
@ -912,7 +917,7 @@ int gw_read_client_event(DCB* dcb)
|
|||||||
snprintf(fail_str, message_len, "Unknown database '%s'",
|
snprintf(fail_str, message_len, "Unknown database '%s'",
|
||||||
(char*)((MYSQL_session *)dcb->data)->db);
|
(char*)((MYSQL_session *)dcb->data)->db);
|
||||||
|
|
||||||
modutil_send_mysql_err_packet(dcb, 2, 0, 1049, "42000", fail_str);
|
modutil_send_mysql_err_packet(dcb, packet_number, 0, 1049, "42000", fail_str);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -921,108 +926,7 @@ int gw_read_client_event(DCB* dcb)
|
|||||||
dcb->remote,
|
dcb->remote,
|
||||||
(char*)((MYSQL_session *)dcb->data)->client_sha1,
|
(char*)((MYSQL_session *)dcb->data)->client_sha1,
|
||||||
(char*)((MYSQL_session *)dcb->data)->db,auth_val);
|
(char*)((MYSQL_session *)dcb->data)->db,auth_val);
|
||||||
modutil_send_mysql_err_packet(dcb, 2, 0, 1045, "28000", fail_str);
|
modutil_send_mysql_err_packet(dcb, packet_number, 0, 1045, "28000", fail_str);
|
||||||
}
|
|
||||||
if (fail_str)
|
|
||||||
{
|
|
||||||
free(fail_str);
|
|
||||||
}
|
|
||||||
|
|
||||||
MXS_DEBUG("%lu [gw_read_client_event] after "
|
|
||||||
"gw_mysql_do_authentication, fd %d, "
|
|
||||||
"state = MYSQL_AUTH_FAILED.",
|
|
||||||
pthread_self(),
|
|
||||||
protocol->owner_dcb->fd);
|
|
||||||
/**
|
|
||||||
* Release MYSQL_session since it is not used anymore.
|
|
||||||
*/
|
|
||||||
if (!DCB_IS_CLONE(dcb))
|
|
||||||
{
|
|
||||||
free(dcb->data);
|
|
||||||
}
|
|
||||||
dcb->data = NULL;
|
|
||||||
|
|
||||||
dcb_close(dcb);
|
|
||||||
}
|
|
||||||
gwbuf_free(read_buffer);
|
|
||||||
read_buffer = NULL;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MYSQL_AUTH_SSL_HANDSHAKE_DONE:
|
|
||||||
{
|
|
||||||
int auth_val;
|
|
||||||
|
|
||||||
auth_val = gw_mysql_do_authentication(dcb, &read_buffer);
|
|
||||||
|
|
||||||
if (auth_val == 0)
|
|
||||||
{
|
|
||||||
SESSION *session;
|
|
||||||
|
|
||||||
protocol->protocol_auth_state = MYSQL_AUTH_RECV;
|
|
||||||
/**
|
|
||||||
* Create session, and a router session for it.
|
|
||||||
* If successful, there will be backend connection(s)
|
|
||||||
* after this point.
|
|
||||||
*/
|
|
||||||
session = session_alloc(dcb->service, dcb);
|
|
||||||
|
|
||||||
if (session != NULL)
|
|
||||||
{
|
|
||||||
CHK_SESSION(session);
|
|
||||||
ss_dassert(session->state != SESSION_STATE_ALLOC &&
|
|
||||||
session->state != SESSION_STATE_DUMMY);
|
|
||||||
|
|
||||||
protocol->protocol_auth_state = MYSQL_IDLE;
|
|
||||||
/**
|
|
||||||
* Send an AUTH_OK packet to the client,
|
|
||||||
* packet sequence is # 2
|
|
||||||
*/
|
|
||||||
mysql_send_ok(dcb, 3, 0, NULL);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
protocol->protocol_auth_state = MYSQL_AUTH_FAILED;
|
|
||||||
MXS_DEBUG("%lu [gw_read_client_event] session "
|
|
||||||
"creation failed. fd %d, "
|
|
||||||
"state = MYSQL_AUTH_FAILED.",
|
|
||||||
pthread_self(),
|
|
||||||
protocol->owner_dcb->fd);
|
|
||||||
|
|
||||||
/** Send ERR 1045 to client */
|
|
||||||
mysql_send_auth_error(dcb,
|
|
||||||
3,
|
|
||||||
0,
|
|
||||||
"failed to create new session");
|
|
||||||
|
|
||||||
dcb_close(dcb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
char* fail_str = NULL;
|
|
||||||
|
|
||||||
protocol->protocol_auth_state = MYSQL_AUTH_FAILED;
|
|
||||||
|
|
||||||
if (auth_val == 2)
|
|
||||||
{
|
|
||||||
/** Send error 1049 to client */
|
|
||||||
int message_len = 25 + MYSQL_DATABASE_MAXLEN;
|
|
||||||
|
|
||||||
fail_str = calloc(1, message_len+1);
|
|
||||||
snprintf(fail_str, message_len, "Unknown database '%s'",
|
|
||||||
(char*)((MYSQL_session *)dcb->data)->db);
|
|
||||||
|
|
||||||
modutil_send_mysql_err_packet(dcb, 3, 0, 1049, "42000", fail_str);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/** Send error 1045 to client */
|
|
||||||
fail_str = create_auth_fail_str((char *)((MYSQL_session *)dcb->data)->user,
|
|
||||||
dcb->remote,
|
|
||||||
(char*)((MYSQL_session *)dcb->data)->client_sha1,
|
|
||||||
(char*)((MYSQL_session *)dcb->data)->db,auth_val);
|
|
||||||
modutil_send_mysql_err_packet(dcb, 3, 0, 1045, "28000", fail_str);
|
|
||||||
}
|
}
|
||||||
if (fail_str)
|
if (fail_str)
|
||||||
{
|
{
|
||||||
@ -1875,71 +1779,3 @@ static int route_by_statement(SESSION* session, GWBUF** p_readbuf)
|
|||||||
return_rc:
|
return_rc:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Do the SSL authentication handshake.
|
|
||||||
* This creates the DCB SSL structure if one has not been created and starts the
|
|
||||||
* SSL handshake handling.
|
|
||||||
* @param protocol Protocol to connect with SSL
|
|
||||||
* @return 1 on success, 0 when the handshake is ongoing or -1 on error
|
|
||||||
*/
|
|
||||||
int do_ssl_accept(MySQLProtocol* protocol)
|
|
||||||
{
|
|
||||||
int rval,errnum;
|
|
||||||
char errbuf[2014];
|
|
||||||
DCB* dcb = protocol->owner_dcb;
|
|
||||||
if (dcb->ssl == NULL)
|
|
||||||
{
|
|
||||||
if (dcb_create_SSL(dcb) != 0)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rval = dcb_accept_SSL(dcb);
|
|
||||||
|
|
||||||
switch(rval)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
/** Not all of the data has been read. Go back to the poll
|
|
||||||
queue and wait for more.*/
|
|
||||||
|
|
||||||
rval = 0;
|
|
||||||
MXS_INFO("SSL_accept ongoing for %s@%s",
|
|
||||||
protocol->owner_dcb->user,
|
|
||||||
protocol->owner_dcb->remote);
|
|
||||||
return 0;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
spinlock_acquire(&protocol->protocol_lock);
|
|
||||||
protocol->protocol_auth_state = MYSQL_AUTH_SSL_HANDSHAKE_DONE;
|
|
||||||
protocol->use_ssl = true;
|
|
||||||
spinlock_release(&protocol->protocol_lock);
|
|
||||||
|
|
||||||
rval = 1;
|
|
||||||
|
|
||||||
MXS_INFO("SSL_accept done for %s@%s",
|
|
||||||
protocol->owner_dcb->user,
|
|
||||||
protocol->owner_dcb->remote);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case -1:
|
|
||||||
spinlock_acquire(&protocol->protocol_lock);
|
|
||||||
protocol->protocol_auth_state = MYSQL_AUTH_SSL_HANDSHAKE_FAILED;
|
|
||||||
spinlock_release(&protocol->protocol_lock);
|
|
||||||
rval = -1;
|
|
||||||
MXS_ERROR("Fatal error in SSL_accept for %s",
|
|
||||||
protocol->owner_dcb->remote);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
MXS_ERROR("Fatal error in SSL_accept, returned value was %d.", rval);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#ifdef SS_DEBUG
|
|
||||||
MXS_DEBUG("[do_ssl_accept] Protocol state: %s",
|
|
||||||
gw_mysql_protocol_state2string(protocol->protocol_auth_state));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return rval;
|
|
||||||
}
|
|
||||||
|
Reference in New Issue
Block a user