Reformat mysql_common.c

This commit is contained in:
Johan Wikman
2016-01-12 15:36:15 +02:00
parent da29ee0f4a
commit fd9698e705

View File

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