Reformat mysql_common.c
This commit is contained in:
@ -24,12 +24,17 @@
|
||||
* 17/06/2013 Massimiliano Pinto Common MySQL protocol routines
|
||||
* 02/06/2013 Massimiliano Pinto MySQL connect asynchronous phases
|
||||
* 04/09/2013 Massimiliano Pinto Added dcb NULL assert in mysql_send_custom_error
|
||||
* 12/09/2013 Massimiliano Pinto Added checks in gw_decode_mysql_server_handshake and gw_read_backend_handshake
|
||||
* 12/09/2013 Massimiliano Pinto Added checks in gw_decode_mysql_server_handshake and
|
||||
* gw_read_backend_handshake
|
||||
* 10/02/2014 Massimiliano Pinto Added MySQL Authentication with user@host
|
||||
* 10/09/2014 Massimiliano Pinto Added MySQL Authentication option enabling localhost match with any host (wildcard %)
|
||||
* Backend server configuration may differ so default is 0, don't match and an explicit
|
||||
* localhost entry should be added for the selected user in the backends.
|
||||
* Setting to 1 allow localhost (127.0.0.1 or socket) to match the any host grant via
|
||||
* 10/09/2014 Massimiliano Pinto Added MySQL Authentication option enabling localhost
|
||||
* match with any host (wildcard %)
|
||||
* Backend server configuration may differ so default is 0,
|
||||
* don't match and an explicit
|
||||
* localhost entry should be added for the selected user
|
||||
* in the backends.
|
||||
* Setting to 1 allow localhost (127.0.0.1 or socket) to
|
||||
* match the any host grant via
|
||||
* user@%
|
||||
* 29/09/2014 Massimiliano Pinto Added Mysql user@host authentication with wildcard in IPv4 hosts:
|
||||
* x.y.z.%, x.y.%.%, x.%.%.%
|
||||
@ -56,8 +61,7 @@ extern int gw_MySQLWrite_backend(DCB *dcb, GWBUF *queue);
|
||||
extern int gw_error_backend_event(DCB *dcb);
|
||||
char* get_username_from_auth(char* ptr, uint8_t* data);
|
||||
|
||||
static server_command_t* server_command_init(server_command_t* srvcmd,
|
||||
mysql_server_cmd_t cmd);
|
||||
static server_command_t* server_command_init(server_command_t* srvcmd, mysql_server_cmd_t cmd);
|
||||
|
||||
|
||||
/**
|
||||
@ -73,16 +77,15 @@ static server_command_t* server_command_init(server_command_t* srvcmd,
|
||||
* connected yet.
|
||||
*
|
||||
*/
|
||||
MySQLProtocol* mysql_protocol_init(
|
||||
DCB* dcb,
|
||||
int fd)
|
||||
MySQLProtocol* mysql_protocol_init(DCB* dcb, int fd)
|
||||
{
|
||||
MySQLProtocol* p;
|
||||
|
||||
p = (MySQLProtocol *) calloc(1, sizeof(MySQLProtocol));
|
||||
ss_dassert(p != NULL);
|
||||
|
||||
if (p == NULL) {
|
||||
if (p == NULL)
|
||||
{
|
||||
int eno = errno;
|
||||
errno = 0;
|
||||
char errbuf[STRERROR_BUFLEN];
|
||||
@ -120,8 +123,7 @@ return_p:
|
||||
* @param dcb owner DCB
|
||||
*
|
||||
*/
|
||||
void mysql_protocol_done (
|
||||
DCB* dcb)
|
||||
void mysql_protocol_done(DCB* dcb)
|
||||
{
|
||||
MySQLProtocol* p;
|
||||
server_command_t* scmd;
|
||||
@ -156,8 +158,7 @@ retblock:
|
||||
* @param conn MySQL protocol structure
|
||||
* @return 0 on success, 1 on failure
|
||||
*/
|
||||
int gw_read_backend_handshake(
|
||||
MySQLProtocol *conn)
|
||||
int gw_read_backend_handshake(MySQLProtocol *conn)
|
||||
{
|
||||
GWBUF *head = NULL;
|
||||
DCB *dcb = conn->owner_dcb;
|
||||
@ -169,7 +170,6 @@ int gw_read_backend_handshake(
|
||||
|
||||
if ((n = dcb_read(dcb, &head, 0)) != -1)
|
||||
{
|
||||
|
||||
dcb->last_read = hkheartbeat;
|
||||
|
||||
if (head)
|
||||
@ -182,7 +182,8 @@ int gw_read_backend_handshake(
|
||||
* just return with less bytes
|
||||
*/
|
||||
|
||||
if (h_len <= 4) {
|
||||
if (h_len <= 4)
|
||||
{
|
||||
/* log error this exit point */
|
||||
conn->protocol_auth_state = MYSQL_HANDSHAKE_FAILED;
|
||||
MXS_DEBUG("%lu [gw_read_backend_handshake] after "
|
||||
@ -198,7 +199,7 @@ int gw_read_backend_handshake(
|
||||
{
|
||||
size_t len = MYSQL_GET_PACKET_LEN(payload);
|
||||
uint16_t errcode = MYSQL_GET_ERRCODE(payload);
|
||||
char* bufstr = strndup(&((char *)payload)[7], len-3);
|
||||
char* bufstr = strndup(&((char *)payload)[7], len - 3);
|
||||
|
||||
conn->protocol_auth_state = MYSQL_HANDSHAKE_FAILED;
|
||||
|
||||
@ -223,7 +224,8 @@ int gw_read_backend_handshake(
|
||||
* This will avoid filling the error log.
|
||||
*/
|
||||
|
||||
if (errcode == 1129) {
|
||||
if (errcode == 1129)
|
||||
{
|
||||
MXS_ERROR("Server %s has been put into maintenance mode due "
|
||||
"to the server blocking connections from MaxScale. "
|
||||
"Run 'mysqladmin -h %s -P %d flush-hosts' on this "
|
||||
@ -241,7 +243,8 @@ int gw_read_backend_handshake(
|
||||
//get mysql packet size, 3 bytes
|
||||
packet_len = gw_mysql_get_byte3(payload);
|
||||
|
||||
if (h_len < (packet_len + 4)) {
|
||||
if (h_len < (packet_len + 4))
|
||||
{
|
||||
/*
|
||||
* data in buffer less than expected in the
|
||||
* packet. Log error this exit point
|
||||
@ -264,7 +267,8 @@ int gw_read_backend_handshake(
|
||||
//Now decode mysql handshake
|
||||
success = gw_decode_mysql_server_handshake(conn, payload);
|
||||
|
||||
if (success < 0) {
|
||||
if (success < 0)
|
||||
{
|
||||
/* MySQL handshake has not been properly decoded
|
||||
* we cannot continue
|
||||
* log error this exit point
|
||||
@ -276,7 +280,10 @@ int gw_read_backend_handshake(
|
||||
"state = MYSQL_HANDSHAKE_FAILED.",
|
||||
pthread_self(),
|
||||
conn->owner_dcb->fd);
|
||||
while((head = gwbuf_consume(head, GWBUF_LENGTH(head))));
|
||||
while ((head = gwbuf_consume(head, GWBUF_LENGTH(head))))
|
||||
{
|
||||
;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -303,14 +310,12 @@ int gw_read_backend_handshake(
|
||||
* @return 0 on success, < 0 on failure
|
||||
*
|
||||
*/
|
||||
int gw_decode_mysql_server_handshake(
|
||||
MySQLProtocol *conn,
|
||||
uint8_t *payload)
|
||||
int gw_decode_mysql_server_handshake(MySQLProtocol *conn, uint8_t *payload)
|
||||
{
|
||||
uint8_t *server_version_end = NULL;
|
||||
uint16_t mysql_server_capabilities_one = 0;
|
||||
uint16_t mysql_server_capabilities_two = 0;
|
||||
unsigned long tid =0;
|
||||
unsigned long tid = 0;
|
||||
uint8_t scramble_data_1[GW_SCRAMBLE_LENGTH_323] = "";
|
||||
uint8_t scramble_data_2[GW_MYSQL_SCRAMBLE_SIZE - GW_SCRAMBLE_LENGTH_323] = "";
|
||||
uint8_t capab_ptr[4] = "";
|
||||
@ -336,7 +341,7 @@ int gw_decode_mysql_server_handshake(
|
||||
tid = gw_mysql_get_byte4(payload);
|
||||
memcpy(&conn->tid, &tid, 4);
|
||||
|
||||
payload +=4;
|
||||
payload += 4;
|
||||
|
||||
// scramble_part 1
|
||||
memcpy(scramble_data_1, payload, GW_SCRAMBLE_LENGTH_323);
|
||||
@ -348,7 +353,7 @@ int gw_decode_mysql_server_handshake(
|
||||
mysql_server_capabilities_one = gw_mysql_get_byte2(payload);
|
||||
|
||||
//Get capabilities_part 1 (2 bytes) + 1 language + 2 server_status
|
||||
payload +=5;
|
||||
payload += 5;
|
||||
|
||||
mysql_server_capabilities_two = gw_mysql_get_byte2(payload);
|
||||
|
||||
@ -358,7 +363,7 @@ int gw_decode_mysql_server_handshake(
|
||||
memcpy(&(capab_ptr[2]), &mysql_server_capabilities_two, 2);
|
||||
|
||||
// 2 bytes shift
|
||||
payload+=2;
|
||||
payload += 2;
|
||||
|
||||
// get scramble len
|
||||
if (payload[0] > 0)
|
||||
@ -401,8 +406,7 @@ int gw_decode_mysql_server_handshake(
|
||||
* @return -1 in case of failure, 0 if there was nothing to read, 1 if read
|
||||
* was successful.
|
||||
*/
|
||||
int gw_receive_backend_auth(
|
||||
MySQLProtocol *protocol)
|
||||
int gw_receive_backend_auth(MySQLProtocol *protocol)
|
||||
{
|
||||
int n = -1;
|
||||
GWBUF *head = NULL;
|
||||
@ -433,7 +437,7 @@ int gw_receive_backend_auth(
|
||||
{
|
||||
size_t len = MYSQL_GET_PACKET_LEN(ptr);
|
||||
char* err = strndup(&((char *)ptr)[8], 5);
|
||||
char* bufstr = strndup(&((char *)ptr)[13], len-4-5);
|
||||
char* bufstr = strndup(&((char *)ptr)[13], len - 4 - 5);
|
||||
|
||||
MXS_DEBUG("%lu [gw_receive_backend_auth] Invalid "
|
||||
"authentication message from backend dcb %p "
|
||||
@ -471,7 +475,10 @@ int gw_receive_backend_auth(
|
||||
/*<
|
||||
* Remove data from buffer.
|
||||
*/
|
||||
while ((head = gwbuf_consume(head, GWBUF_LENGTH(head))) != NULL);
|
||||
while ((head = gwbuf_consume(head, GWBUF_LENGTH(head))) != NULL)
|
||||
{
|
||||
;
|
||||
}
|
||||
}
|
||||
else if (n == 0)
|
||||
{
|
||||
@ -517,8 +524,7 @@ int gw_receive_backend_auth(
|
||||
* @param passwd The SHA1(real_password): Note real_password is unknown
|
||||
* @return 0 on success, 1 on failure
|
||||
*/
|
||||
int gw_send_authentication_to_backend(
|
||||
char *dbname,
|
||||
int gw_send_authentication_to_backend(char *dbname,
|
||||
char *user,
|
||||
uint8_t *passwd,
|
||||
MySQLProtocol *conn)
|
||||
@ -551,10 +557,14 @@ int gw_send_authentication_to_backend(
|
||||
}
|
||||
|
||||
if (strlen(dbname))
|
||||
{
|
||||
curr_db = dbname;
|
||||
}
|
||||
|
||||
if (memcmp(passwd, null_client_sha1, MYSQL_SCRAMBLE_LEN))
|
||||
{
|
||||
curr_passwd = passwd;
|
||||
}
|
||||
|
||||
dcb = conn->owner_dcb;
|
||||
final_capabilities = gw_mysql_get_byte4((uint8_t *)&server_capabilities);
|
||||
@ -565,14 +575,16 @@ int gw_send_authentication_to_backend(
|
||||
/* get charset the client sent and use it for connection auth */
|
||||
charset = conn->charset;
|
||||
|
||||
if (compress) {
|
||||
if (compress)
|
||||
{
|
||||
final_capabilities |= GW_MYSQL_CAPABILITIES_COMPRESS;
|
||||
#ifdef DEBUG_MYSQL_CONN
|
||||
fprintf(stderr, ">>>> Backend Connection with compression\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (curr_passwd != NULL) {
|
||||
if (curr_passwd != NULL)
|
||||
{
|
||||
uint8_t hash1[GW_MYSQL_SCRAMBLE_SIZE]="";
|
||||
uint8_t hash2[GW_MYSQL_SCRAMBLE_SIZE]="";
|
||||
uint8_t new_sha[GW_MYSQL_SCRAMBLE_SIZE]="";
|
||||
@ -594,10 +606,13 @@ int gw_send_authentication_to_backend(
|
||||
|
||||
}
|
||||
|
||||
if (curr_db == NULL) {
|
||||
if (curr_db == NULL)
|
||||
{
|
||||
// without db
|
||||
final_capabilities &= ~GW_MYSQL_CAPABILITIES_CONNECT_WITH_DB;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
final_capabilities |= GW_MYSQL_CAPABILITIES_CONNECT_WITH_DB;
|
||||
}
|
||||
|
||||
@ -616,19 +631,23 @@ int gw_send_authentication_to_backend(
|
||||
|
||||
// next will be + 1 (scramble_len) + 20 (fixed_scramble) + 1 (user NULL term) + 1 (db NULL term)
|
||||
|
||||
if (curr_passwd != NULL) {
|
||||
if (curr_passwd != NULL)
|
||||
{
|
||||
bytes++;
|
||||
bytes += GW_MYSQL_SCRAMBLE_SIZE;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
bytes++;
|
||||
}
|
||||
|
||||
if (curr_db != NULL) {
|
||||
if (curr_db != NULL)
|
||||
{
|
||||
bytes += strlen(curr_db);
|
||||
bytes++;
|
||||
}
|
||||
|
||||
bytes +=strlen("mysql_native_password");
|
||||
bytes += strlen("mysql_native_password");
|
||||
bytes++;
|
||||
|
||||
// the packet header
|
||||
@ -670,23 +689,27 @@ int gw_send_authentication_to_backend(
|
||||
payload += strlen(user);
|
||||
payload++;
|
||||
|
||||
if (curr_passwd != NULL) {
|
||||
if (curr_passwd != NULL)
|
||||
{
|
||||
// set the auth-length
|
||||
*payload = GW_MYSQL_SCRAMBLE_SIZE;
|
||||
payload++;
|
||||
|
||||
//copy the 20 bytes scramble data after packet_buffer+36+user+NULL+1 (byte of auth-length)
|
||||
//copy the 20 bytes scramble data after packet_buffer + 36 + user + NULL + 1 (byte of auth-length)
|
||||
memcpy(payload, client_scramble, GW_MYSQL_SCRAMBLE_SIZE);
|
||||
|
||||
payload += GW_MYSQL_SCRAMBLE_SIZE;
|
||||
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// skip the auth-length and write a NULL
|
||||
payload++;
|
||||
}
|
||||
|
||||
// if the db is not NULL append it
|
||||
if (curr_db != NULL) {
|
||||
if (curr_db != NULL)
|
||||
{
|
||||
memcpy(payload, curr_db, strlen(curr_db));
|
||||
payload += strlen(curr_db);
|
||||
payload++;
|
||||
@ -699,13 +722,16 @@ int gw_send_authentication_to_backend(
|
||||
payload++;
|
||||
|
||||
// put here the paylod size: bytes to write - 4 bytes packet header
|
||||
gw_mysql_set_byte3(payload_start, (bytes-4));
|
||||
gw_mysql_set_byte3(payload_start, (bytes - 4));
|
||||
|
||||
rv = dcb_write(dcb, buffer);
|
||||
|
||||
if (rv == 0) {
|
||||
if (rv == 0)
|
||||
{
|
||||
return 1;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -724,10 +750,7 @@ int gw_send_authentication_to_backend(
|
||||
* backend server. In failure, fd == -1 and socket is closed.
|
||||
*
|
||||
*/
|
||||
int gw_do_connect_to_backend(
|
||||
char *host,
|
||||
int port,
|
||||
int *fd)
|
||||
int gw_do_connect_to_backend(char *host, int port, int *fd)
|
||||
{
|
||||
struct sockaddr_in serv_addr;
|
||||
int rv;
|
||||
@ -738,7 +761,8 @@ int gw_do_connect_to_backend(
|
||||
serv_addr.sin_family = AF_INET;
|
||||
so = socket(AF_INET,SOCK_STREAM,0);
|
||||
|
||||
if (so < 0) {
|
||||
if (so < 0)
|
||||
{
|
||||
char errbuf[STRERROR_BUFLEN];
|
||||
MXS_ERROR("Establishing connection to backend server "
|
||||
"%s:%d failed.\n\t\t Socket creation failed "
|
||||
@ -755,7 +779,7 @@ int gw_do_connect_to_backend(
|
||||
serv_addr.sin_port = htons(port);
|
||||
bufsize = GW_BACKEND_SO_SNDBUF;
|
||||
|
||||
if(setsockopt(so, SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(bufsize)) != 0)
|
||||
if (setsockopt(so, SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(bufsize)) != 0)
|
||||
{
|
||||
char errbuf[STRERROR_BUFLEN];
|
||||
MXS_ERROR("Failed to set socket options "
|
||||
@ -771,7 +795,7 @@ int gw_do_connect_to_backend(
|
||||
}
|
||||
bufsize = GW_BACKEND_SO_RCVBUF;
|
||||
|
||||
if(setsockopt(so, SOL_SOCKET, SO_RCVBUF, &bufsize, sizeof(bufsize)) != 0)
|
||||
if (setsockopt(so, SOL_SOCKET, SO_RCVBUF, &bufsize, sizeof(bufsize)) != 0)
|
||||
{
|
||||
char errbuf[STRERROR_BUFLEN];
|
||||
MXS_ERROR("Failed to set socket options "
|
||||
@ -787,7 +811,7 @@ int gw_do_connect_to_backend(
|
||||
}
|
||||
|
||||
int one = 1;
|
||||
if(setsockopt(so, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)) != 0)
|
||||
if (setsockopt(so, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)) != 0)
|
||||
{
|
||||
char errbuf[STRERROR_BUFLEN];
|
||||
MXS_ERROR("Failed to set socket options "
|
||||
@ -856,9 +880,10 @@ close_so:
|
||||
* @return String representation of the state
|
||||
*
|
||||
*/
|
||||
const char *
|
||||
gw_mysql_protocol_state2string (int state) {
|
||||
switch(state) {
|
||||
const char* gw_mysql_protocol_state2string (int state)
|
||||
{
|
||||
switch(state)
|
||||
{
|
||||
case MYSQL_ALLOC:
|
||||
return "MySQL Protocl struct allocated";
|
||||
case MYSQL_PENDING_CONNECT:
|
||||
@ -873,17 +898,20 @@ gw_mysql_protocol_state2string (int state) {
|
||||
return "MySQL Authentication failed";
|
||||
case MYSQL_IDLE:
|
||||
return "MySQL authentication is succesfully done.";
|
||||
case MYSQL_AUTH_SSL_REQ: return "MYSQL_AUTH_SSL_REQ";
|
||||
case MYSQL_AUTH_SSL_HANDSHAKE_DONE: return "MYSQL_AUTH_SSL_HANDSHAKE_DONE";
|
||||
case MYSQL_AUTH_SSL_HANDSHAKE_FAILED: return "MYSQL_AUTH_SSL_HANDSHAKE_FAILED";
|
||||
case MYSQL_AUTH_SSL_HANDSHAKE_ONGOING: return "MYSQL_AUTH_SSL_HANDSHAKE_ONGOING";
|
||||
case MYSQL_AUTH_SSL_REQ:
|
||||
return "MYSQL_AUTH_SSL_REQ";
|
||||
case MYSQL_AUTH_SSL_HANDSHAKE_DONE:
|
||||
return "MYSQL_AUTH_SSL_HANDSHAKE_DONE";
|
||||
case MYSQL_AUTH_SSL_HANDSHAKE_FAILED:
|
||||
return "MYSQL_AUTH_SSL_HANDSHAKE_FAILED";
|
||||
case MYSQL_AUTH_SSL_HANDSHAKE_ONGOING:
|
||||
return "MYSQL_AUTH_SSL_HANDSHAKE_ONGOING";
|
||||
default:
|
||||
return "MySQL (unknown protocol state)";
|
||||
}
|
||||
}
|
||||
|
||||
GWBUF* mysql_create_com_quit(
|
||||
GWBUF* bufparam,
|
||||
GWBUF* mysql_create_com_quit(GWBUF* bufparam,
|
||||
int packet_number)
|
||||
{
|
||||
uint8_t* data;
|
||||
@ -915,8 +943,7 @@ GWBUF* mysql_create_com_quit(
|
||||
return buf;
|
||||
}
|
||||
|
||||
int mysql_send_com_quit(
|
||||
DCB* dcb,
|
||||
int mysql_send_com_quit(DCB* dcb,
|
||||
int packet_number,
|
||||
GWBUF* bufparam)
|
||||
{
|
||||
@ -949,8 +976,7 @@ int mysql_send_com_quit(
|
||||
}
|
||||
|
||||
|
||||
GWBUF* mysql_create_custom_error(
|
||||
int packet_number,
|
||||
GWBUF* mysql_create_custom_error(int packet_number,
|
||||
int affected_rows,
|
||||
const char* msg)
|
||||
{
|
||||
@ -974,13 +1000,15 @@ GWBUF* mysql_create_custom_error(
|
||||
field_count = 0xff;
|
||||
gw_mysql_set_byte2(mysql_err, mysql_errno);
|
||||
mysql_statemsg[0]='#';
|
||||
memcpy(mysql_statemsg+1, mysql_state, 5);
|
||||
memcpy(mysql_statemsg + 1, mysql_state, 5);
|
||||
|
||||
if (msg != NULL) {
|
||||
if (msg != NULL)
|
||||
{
|
||||
mysql_error_msg = msg;
|
||||
}
|
||||
|
||||
mysql_payload_size = sizeof(field_count) +
|
||||
mysql_payload_size =
|
||||
sizeof(field_count) +
|
||||
sizeof(mysql_err) +
|
||||
sizeof(mysql_statemsg) +
|
||||
strlen(mysql_error_msg);
|
||||
@ -1034,8 +1062,7 @@ GWBUF* mysql_create_custom_error(
|
||||
* @return 1 Non-zero if data was sent
|
||||
*
|
||||
*/
|
||||
int mysql_send_custom_error (
|
||||
DCB *dcb,
|
||||
int mysql_send_custom_error(DCB *dcb,
|
||||
int packet_number,
|
||||
int in_affected_rows,
|
||||
const char *mysql_message)
|
||||
@ -1057,8 +1084,7 @@ int mysql_send_custom_error (
|
||||
*
|
||||
* @note the function doesn't fail
|
||||
*/
|
||||
GWBUF* gw_create_change_user_packet(
|
||||
MYSQL_session* mses,
|
||||
GWBUF* gw_create_change_user_packet(MYSQL_session* mses,
|
||||
MySQLProtocol* protocol)
|
||||
{
|
||||
char* db;
|
||||
@ -1184,8 +1210,7 @@ GWBUF* gw_create_change_user_packet(
|
||||
* Set correct type to GWBUF so that it will be handled like session
|
||||
* commands
|
||||
*/
|
||||
buffer->gwbuf_type =
|
||||
GWBUF_TYPE_MYSQL|GWBUF_TYPE_SINGLE_STMT|GWBUF_TYPE_SESCMD;
|
||||
buffer->gwbuf_type = GWBUF_TYPE_MYSQL|GWBUF_TYPE_SINGLE_STMT|GWBUF_TYPE_SESCMD;
|
||||
payload = GWBUF_DATA(buffer);
|
||||
memset(payload, '\0', bytes);
|
||||
payload_start = payload;
|
||||
@ -1208,7 +1233,7 @@ GWBUF* gw_create_change_user_packet(
|
||||
payload++;
|
||||
/**
|
||||
* copy the 20 bytes scramble data after
|
||||
* packet_buffer+36+user+NULL+1 (byte of auth-length)
|
||||
* packet_buffer + 36 + user + NULL + 1 (byte of auth-length)
|
||||
*/
|
||||
memcpy(payload, client_scramble, GW_MYSQL_SCRAMBLE_SIZE);
|
||||
payload += GW_MYSQL_SCRAMBLE_SIZE;
|
||||
@ -1248,8 +1273,7 @@ GWBUF* gw_create_change_user_packet(
|
||||
* @param passwd The SHA1(real_password)
|
||||
* @return 1 on success, 0 on failure
|
||||
*/
|
||||
int gw_send_change_user_to_backend(
|
||||
char *dbname,
|
||||
int gw_send_change_user_to_backend(char *dbname,
|
||||
char *user,
|
||||
uint8_t *passwd,
|
||||
MySQLProtocol *conn)
|
||||
@ -1284,7 +1308,14 @@ int gw_send_change_user_to_backend(
|
||||
* @return 0 on succesful check or 1 on failure
|
||||
*
|
||||
*/
|
||||
int gw_check_mysql_scramble_data(DCB *dcb, uint8_t *token, unsigned int token_len, uint8_t *scramble, unsigned int scramble_len, char *username, uint8_t *stage1_hash) {
|
||||
int gw_check_mysql_scramble_data(DCB *dcb,
|
||||
uint8_t *token,
|
||||
unsigned int token_len,
|
||||
uint8_t *scramble,
|
||||
unsigned int scramble_len,
|
||||
char *username,
|
||||
uint8_t *stage1_hash)
|
||||
{
|
||||
uint8_t step1[GW_MYSQL_SCRAMBLE_SIZE]="";
|
||||
uint8_t step2[GW_MYSQL_SCRAMBLE_SIZE +1]="";
|
||||
uint8_t check_hash[GW_MYSQL_SCRAMBLE_SIZE]="";
|
||||
@ -1292,7 +1323,8 @@ int gw_check_mysql_scramble_data(DCB *dcb, uint8_t *token, unsigned int token_le
|
||||
uint8_t password[GW_MYSQL_SCRAMBLE_SIZE]="";
|
||||
int ret_val = 1;
|
||||
|
||||
if ((username == NULL) || (scramble == NULL) || (stage1_hash == NULL)) {
|
||||
if ((username == NULL) || (scramble == NULL) || (stage1_hash == NULL))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1303,7 +1335,8 @@ int gw_check_mysql_scramble_data(DCB *dcb, uint8_t *token, unsigned int token_le
|
||||
|
||||
ret_val = gw_find_mysql_user_password_sha1(username, password, dcb);
|
||||
|
||||
if (ret_val) {
|
||||
if (ret_val)
|
||||
{
|
||||
/* if password was sent, fill stage1_hash with at least 1 byte in order
|
||||
* to create right error message: (using password: YES|NO)
|
||||
*/
|
||||
@ -1313,14 +1346,17 @@ int gw_check_mysql_scramble_data(DCB *dcb, uint8_t *token, unsigned int token_le
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (token && token_len) {
|
||||
if (token && token_len)
|
||||
{
|
||||
/*<
|
||||
* convert in hex format: this is the content of mysql.user table.
|
||||
* The field password is without the '*' prefix and it is 40 bytes long
|
||||
*/
|
||||
|
||||
gw_bin2hex(hex_double_sha1, password, SHA_DIGEST_LENGTH);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/* check if the password is not set in the user table */
|
||||
return memcmp(password, null_client_sha1, MYSQL_SCRAMBLE_LEN) ? 1 : 0;
|
||||
}
|
||||
@ -1401,7 +1437,8 @@ int gw_check_mysql_scramble_data(DCB *dcb, uint8_t *token, unsigned int token_le
|
||||
*
|
||||
*/
|
||||
|
||||
int gw_find_mysql_user_password_sha1(char *username, uint8_t *gateway_password, DCB *dcb) {
|
||||
int gw_find_mysql_user_password_sha1(char *username, uint8_t *gateway_password, DCB *dcb)
|
||||
{
|
||||
SERVICE *service = NULL;
|
||||
struct sockaddr_in *client;
|
||||
char *user_password = NULL;
|
||||
@ -1416,7 +1453,7 @@ int gw_find_mysql_user_password_sha1(char *username, uint8_t *gateway_password,
|
||||
memcpy(&key.ipv4, client, sizeof(struct sockaddr_in));
|
||||
key.netmask = 32;
|
||||
key.resource = client_data->db;
|
||||
if(strlen(dcb->remote) < MYSQL_HOST_MAXLEN)
|
||||
if (strlen(dcb->remote) < MYSQL_HOST_MAXLEN)
|
||||
{
|
||||
strcpy(key.hostname, dcb->remote);
|
||||
}
|
||||
@ -1431,10 +1468,12 @@ int gw_find_mysql_user_password_sha1(char *username, uint8_t *gateway_password,
|
||||
/* look for user@current_ipv4 now */
|
||||
user_password = mysql_users_fetch(service->users, &key);
|
||||
|
||||
if (!user_password) {
|
||||
if (!user_password)
|
||||
{
|
||||
/* The user is not authenticated @ current IPv4 */
|
||||
|
||||
while (1) {
|
||||
while (1)
|
||||
{
|
||||
/*
|
||||
* (1) Check for localhost first: 127.0.0.1 (IPv4 only)
|
||||
*/
|
||||
@ -1456,7 +1495,8 @@ int gw_find_mysql_user_password_sha1(char *username, uint8_t *gateway_password,
|
||||
|
||||
user_password = mysql_users_fetch(service->users, &key);
|
||||
|
||||
if (user_password) {
|
||||
if (user_password)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1466,7 +1506,8 @@ int gw_find_mysql_user_password_sha1(char *username, uint8_t *gateway_password,
|
||||
|
||||
user_password = mysql_users_fetch(service->users, &key);
|
||||
|
||||
if (user_password) {
|
||||
if (user_password)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1476,7 +1517,8 @@ int gw_find_mysql_user_password_sha1(char *username, uint8_t *gateway_password,
|
||||
|
||||
user_password = mysql_users_fetch(service->users, &key);
|
||||
|
||||
if (user_password) {
|
||||
if (user_password)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1500,7 +1542,8 @@ int gw_find_mysql_user_password_sha1(char *username, uint8_t *gateway_password,
|
||||
break;
|
||||
}
|
||||
|
||||
if (!user_password) {
|
||||
if (!user_password)
|
||||
{
|
||||
/*
|
||||
* user@% not found.
|
||||
*/
|
||||
@ -1520,14 +1563,16 @@ int gw_find_mysql_user_password_sha1(char *username, uint8_t *gateway_password,
|
||||
}
|
||||
|
||||
/* If user@host has been found we get the the password in binary format*/
|
||||
if (user_password) {
|
||||
if (user_password)
|
||||
{
|
||||
/*
|
||||
* Convert the hex data (40 bytes) to binary (20 bytes).
|
||||
* The gateway_password represents the SHA1(SHA1(real_password)).
|
||||
* Please note: the real_password is unknown and SHA1(real_password) is unknown as well
|
||||
*/
|
||||
int passwd_len=strlen(user_password);
|
||||
if (passwd_len) {
|
||||
if (passwd_len)
|
||||
{
|
||||
passwd_len = (passwd_len <= (SHA_DIGEST_LENGTH * 2)) ? passwd_len : (SHA_DIGEST_LENGTH * 2);
|
||||
gw_hex2bin(gateway_password, user_password, passwd_len);
|
||||
}
|
||||
@ -1550,9 +1595,7 @@ int gw_find_mysql_user_password_sha1(char *username, uint8_t *gateway_password,
|
||||
* @return packet length
|
||||
*
|
||||
*/
|
||||
int
|
||||
mysql_send_auth_error (
|
||||
DCB *dcb,
|
||||
int mysql_send_auth_error(DCB *dcb,
|
||||
int packet_number,
|
||||
int in_affected_rows,
|
||||
const char *mysql_message)
|
||||
@ -1586,13 +1629,15 @@ mysql_send_auth_error (
|
||||
field_count = 0xff;
|
||||
gw_mysql_set_byte2(mysql_err, mysql_errno);
|
||||
mysql_statemsg[0]='#';
|
||||
memcpy(mysql_statemsg+1, mysql_state, 5);
|
||||
memcpy(mysql_statemsg + 1, mysql_state, 5);
|
||||
|
||||
if (mysql_message != NULL) {
|
||||
if (mysql_message != NULL)
|
||||
{
|
||||
mysql_error_msg = mysql_message;
|
||||
}
|
||||
|
||||
mysql_payload_size = sizeof(field_count) + sizeof(mysql_err) + sizeof(mysql_statemsg) + strlen(mysql_error_msg);
|
||||
mysql_payload_size =
|
||||
sizeof(field_count) + sizeof(mysql_err) + sizeof(mysql_statemsg) + strlen(mysql_error_msg);
|
||||
|
||||
// allocate memory for packet header + payload
|
||||
if ((buf = gwbuf_alloc(sizeof(mysql_packet_header) + mysql_payload_size)) == NULL)
|
||||
@ -1641,8 +1686,7 @@ mysql_send_auth_error (
|
||||
* @return pointer to gwbuf containing a complete packet or
|
||||
* NULL if no complete packet was found.
|
||||
*/
|
||||
GWBUF* gw_MySQL_get_next_packet(
|
||||
GWBUF** p_readbuf)
|
||||
GWBUF* gw_MySQL_get_next_packet(GWBUF** p_readbuf)
|
||||
{
|
||||
GWBUF* packetbuf;
|
||||
GWBUF* readbuf;
|
||||
@ -1669,7 +1713,7 @@ GWBUF* gw_MySQL_get_next_packet(
|
||||
}
|
||||
totalbuflen = gwbuf_length(readbuf);
|
||||
data = (uint8_t *)GWBUF_DATA((readbuf));
|
||||
packetlen = MYSQL_GET_PACKET_LEN(data)+4;
|
||||
packetlen = MYSQL_GET_PACKET_LEN(data) + 4;
|
||||
|
||||
/** packet is incomplete */
|
||||
if (packetlen > totalbuflen)
|
||||
@ -1691,9 +1735,9 @@ GWBUF* gw_MySQL_get_next_packet(
|
||||
size_t bytestocopy;
|
||||
|
||||
buflen = GWBUF_LENGTH((*p_readbuf));
|
||||
bytestocopy = MIN(buflen,packetlen-nbytes_copied);
|
||||
bytestocopy = MIN(buflen, packetlen - nbytes_copied);
|
||||
|
||||
memcpy(target+nbytes_copied, src, bytestocopy);
|
||||
memcpy(target + nbytes_copied, src, bytestocopy);
|
||||
*p_readbuf = gwbuf_consume((*p_readbuf), bytestocopy);
|
||||
totalbuflen = gwbuf_length((*p_readbuf));
|
||||
nbytes_copied += bytestocopy;
|
||||
@ -1707,8 +1751,7 @@ return_packetbuf:
|
||||
/**
|
||||
* Move <npackets> from buffer pointed to by <*p_readbuf>.
|
||||
*/
|
||||
GWBUF* gw_MySQL_get_packets(
|
||||
GWBUF** p_srcbuf,
|
||||
GWBUF* gw_MySQL_get_packets(GWBUF** p_srcbuf,
|
||||
int* npackets)
|
||||
{
|
||||
GWBUF* packetbuf;
|
||||
@ -1726,8 +1769,7 @@ GWBUF* gw_MySQL_get_packets(
|
||||
}
|
||||
|
||||
|
||||
static server_command_t* server_command_init(
|
||||
server_command_t* srvcmd,
|
||||
static server_command_t* server_command_init(server_command_t* srvcmd,
|
||||
mysql_server_cmd_t cmd)
|
||||
{
|
||||
server_command_t* c;
|
||||
@ -1748,11 +1790,9 @@ static server_command_t* server_command_init(
|
||||
return c;
|
||||
}
|
||||
|
||||
static server_command_t* server_command_copy(
|
||||
server_command_t* srvcmd)
|
||||
static server_command_t* server_command_copy(server_command_t* srvcmd)
|
||||
{
|
||||
server_command_t* c =
|
||||
(server_command_t *)malloc(sizeof(server_command_t));
|
||||
server_command_t* c = (server_command_t *)malloc(sizeof(server_command_t));
|
||||
*c = *srvcmd;
|
||||
|
||||
return c;
|
||||
@ -1760,8 +1800,7 @@ static server_command_t* server_command_copy(
|
||||
|
||||
#define MAX_CMD_HISTORY 10
|
||||
|
||||
void protocol_archive_srv_command(
|
||||
MySQLProtocol* p)
|
||||
void protocol_archive_srv_command(MySQLProtocol* p)
|
||||
{
|
||||
server_command_t* s1;
|
||||
server_command_t* h1;
|
||||
@ -1828,8 +1867,7 @@ retblock:
|
||||
* If router expects to get separate, complete statements, add MySQL command
|
||||
* to MySQLProtocol structure. It is removed when response has arrived.
|
||||
*/
|
||||
void protocol_add_srv_command(
|
||||
MySQLProtocol* p,
|
||||
void protocol_add_srv_command(MySQLProtocol* p,
|
||||
mysql_server_cmd_t cmd)
|
||||
{
|
||||
#if defined(EXTRA_SS_DEBUG)
|
||||
@ -1879,8 +1917,7 @@ retblock:
|
||||
*
|
||||
* Remove current (=oldest) command.
|
||||
*/
|
||||
void protocol_remove_srv_command(
|
||||
MySQLProtocol* p)
|
||||
void protocol_remove_srv_command(MySQLProtocol* p)
|
||||
{
|
||||
server_command_t* s;
|
||||
spinlock_acquire(&p->protocol_lock);
|
||||
@ -1903,8 +1940,7 @@ void protocol_remove_srv_command(
|
||||
spinlock_release(&p->protocol_lock);
|
||||
}
|
||||
|
||||
mysql_server_cmd_t protocol_get_srv_command(
|
||||
MySQLProtocol* p,
|
||||
mysql_server_cmd_t protocol_get_srv_command(MySQLProtocol* p,
|
||||
bool removep)
|
||||
{
|
||||
mysql_server_cmd_t cmd;
|
||||
@ -1930,8 +1966,7 @@ mysql_server_cmd_t protocol_get_srv_command(
|
||||
* Fails if read buffer doesn't include enough data to read the
|
||||
* packet length.
|
||||
*/
|
||||
void init_response_status (
|
||||
GWBUF* buf,
|
||||
void init_response_status(GWBUF* buf,
|
||||
mysql_server_cmd_t cmd,
|
||||
int* npackets,
|
||||
ssize_t* nbytes_left)
|
||||
@ -1951,7 +1986,8 @@ void init_response_status (
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (cmd) {
|
||||
switch (cmd)
|
||||
{
|
||||
case MYSQL_COM_STMT_PREPARE:
|
||||
packet = (uint8_t *)GWBUF_DATA(buf);
|
||||
/** ok + nparam + eof + nattr + eof */
|
||||
@ -1992,8 +2028,7 @@ void init_response_status (
|
||||
* Read how many packets are left from current response and how many bytes there
|
||||
* is still to be read from the current packet.
|
||||
*/
|
||||
bool protocol_get_response_status (
|
||||
MySQLProtocol* p,
|
||||
bool protocol_get_response_status(MySQLProtocol* p,
|
||||
int* npackets,
|
||||
ssize_t* nbytes)
|
||||
{
|
||||
@ -2018,12 +2053,10 @@ bool protocol_get_response_status (
|
||||
return succp;
|
||||
}
|
||||
|
||||
void protocol_set_response_status (
|
||||
MySQLProtocol* p,
|
||||
void protocol_set_response_status(MySQLProtocol* p,
|
||||
int npackets_left,
|
||||
ssize_t nbytes)
|
||||
{
|
||||
|
||||
CHK_PROTOCOL(p);
|
||||
|
||||
spinlock_acquire(&p->protocol_lock);
|
||||
@ -2036,8 +2069,7 @@ void protocol_set_response_status (
|
||||
spinlock_release(&p->protocol_lock);
|
||||
}
|
||||
|
||||
char* create_auth_failed_msg(
|
||||
GWBUF* readbuf,
|
||||
char* create_auth_failed_msg(GWBUF*readbuf,
|
||||
char* hostaddr,
|
||||
uint8_t* sha1)
|
||||
{
|
||||
@ -2046,7 +2078,7 @@ char* create_auth_failed_msg(
|
||||
const char* ferrstr = "Access denied for user '%s'@'%s' (using password: %s)";
|
||||
|
||||
/** -4 comes from 2X'%s' minus terminating char */
|
||||
errstr = (char *)malloc(strlen(uname)+strlen(ferrstr)+strlen(hostaddr)+strlen("YES")-6 + 1);
|
||||
errstr = (char *)malloc(strlen(uname) + strlen(ferrstr) + strlen(hostaddr) + strlen("YES") - 6 + 1);
|
||||
|
||||
if (errstr != NULL)
|
||||
{
|
||||
@ -2068,8 +2100,7 @@ char* create_auth_failed_msg(
|
||||
* @return Pointer to a copy of the username. NULL if memory allocation
|
||||
* failed or if username was empty.
|
||||
*/
|
||||
char* get_username_from_auth(
|
||||
char* ptr,
|
||||
char* get_username_from_auth(char* ptr,
|
||||
uint8_t* data)
|
||||
{
|
||||
char* first_letter;
|
||||
@ -2085,7 +2116,7 @@ char* get_username_from_auth(
|
||||
|
||||
if (ptr == NULL)
|
||||
{
|
||||
if ((rval = (char *)malloc(MYSQL_USER_MAXLEN+1)) == NULL)
|
||||
if ((rval = (char *)malloc(MYSQL_USER_MAXLEN + 1)) == NULL)
|
||||
{
|
||||
goto retblock;
|
||||
}
|
||||
@ -2094,35 +2125,45 @@ char* get_username_from_auth(
|
||||
{
|
||||
rval = ptr;
|
||||
}
|
||||
snprintf(rval, MYSQL_USER_MAXLEN+1, "%s", first_letter);
|
||||
snprintf(rval, MYSQL_USER_MAXLEN + 1, "%s", first_letter);
|
||||
|
||||
retblock:
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
int check_db_name_after_auth(DCB *dcb, char *database, int auth_ret) {
|
||||
int check_db_name_after_auth(DCB *dcb, char *database, int auth_ret)
|
||||
{
|
||||
int db_exists = -1;
|
||||
|
||||
/* check for dabase name and possible match in resource hashtable */
|
||||
if (database && strlen(database)) {
|
||||
if (database && strlen(database))
|
||||
{
|
||||
/* if database names are loaded we can check if db name exists */
|
||||
if (dcb->service->resources != NULL) {
|
||||
if (hashtable_fetch(dcb->service->resources, database)) {
|
||||
if (dcb->service->resources != NULL)
|
||||
{
|
||||
if (hashtable_fetch(dcb->service->resources, database))
|
||||
{
|
||||
db_exists = 1;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
db_exists = 0;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
/* if database names are not loaded we don't allow connection with db name*/
|
||||
db_exists = -1;
|
||||
}
|
||||
|
||||
if (db_exists == 0 && auth_ret == 0) {
|
||||
if (db_exists == 0 && auth_ret == 0)
|
||||
{
|
||||
auth_ret = 2;
|
||||
}
|
||||
|
||||
if (db_exists < 0 && auth_ret == 0) {
|
||||
if (db_exists < 0 && auth_ret == 0)
|
||||
{
|
||||
auth_ret = 1;
|
||||
}
|
||||
}
|
||||
@ -2140,8 +2181,7 @@ int check_db_name_after_auth(DCB *dcb, char *database, int auth_ret) {
|
||||
*
|
||||
* @return Pointer to the allocated string or NULL on failure
|
||||
*/
|
||||
char *create_auth_fail_str(
|
||||
char *username,
|
||||
char *create_auth_fail_str(char *username,
|
||||
char *hostaddr,
|
||||
char *sha1,
|
||||
char *db,
|
||||
@ -2152,15 +2192,19 @@ char *create_auth_fail_str(
|
||||
int db_len;
|
||||
|
||||
if (db != NULL)
|
||||
{
|
||||
db_len = strlen(db);
|
||||
}
|
||||
else
|
||||
{
|
||||
db_len = 0;
|
||||
}
|
||||
|
||||
if (db_len > 0)
|
||||
{
|
||||
ferrstr = "Access denied for user '%s'@'%s' (using password: %s) to database '%s'";
|
||||
}
|
||||
else if(errcode == MYSQL_FAILED_AUTH_SSL)
|
||||
else if (errcode == MYSQL_FAILED_AUTH_SSL)
|
||||
{
|
||||
ferrstr = "Access without SSL denied";
|
||||
}
|
||||
@ -2168,7 +2212,9 @@ char *create_auth_fail_str(
|
||||
{
|
||||
ferrstr = "Access denied for user '%s'@'%s' (using password: %s)";
|
||||
}
|
||||
errstr = (char *)malloc(strlen(username)+strlen(ferrstr)+strlen(hostaddr)+strlen("YES")-6 + db_len + ((db_len > 0) ? (strlen(" to database ") +2) : 0) + 1);
|
||||
errstr = (char *)malloc(strlen(username) + strlen(ferrstr) +
|
||||
strlen(hostaddr) + strlen("YES") - 6 +
|
||||
db_len + ((db_len > 0) ? (strlen(" to database ") +2) : 0) + 1);
|
||||
|
||||
if (errstr == NULL)
|
||||
{
|
||||
@ -2182,7 +2228,7 @@ char *create_auth_fail_str(
|
||||
{
|
||||
sprintf(errstr, ferrstr, username, hostaddr, (*sha1 == '\0' ? "NO" : "YES"), db);
|
||||
}
|
||||
else if(errcode == MYSQL_FAILED_AUTH_SSL)
|
||||
else if (errcode == MYSQL_FAILED_AUTH_SSL)
|
||||
{
|
||||
sprintf(errstr, "%s", ferrstr);
|
||||
}
|
||||
|
Reference in New Issue
Block a user