MXS-862: Move client information extraction to client protocol

The client protocol module now extracts the information that is relevant
for all modules. Currently this information consists of the client
capabilities, character set, username and default database.
This commit is contained in:
Markus Makela
2016-10-15 10:53:53 +03:00
parent c0ad2936a4
commit 891ce2d0e7
3 changed files with 57 additions and 73 deletions

View File

@ -155,31 +155,8 @@ bool store_client_token(DCB *dcb, GWBUF *buffer)
*/ */
static void copy_client_information(DCB *dcb, GWBUF *buffer) static void copy_client_information(DCB *dcb, GWBUF *buffer)
{ {
size_t buflen = gwbuf_length(buffer);
MySQLProtocol *protocol = (MySQLProtocol*)dcb->protocol;
gssapi_auth_t *auth = (gssapi_auth_t*)dcb->authenticator_data; gssapi_auth_t *auth = (gssapi_auth_t*)dcb->authenticator_data;
/* Store the connection characteristics and sequence number of the current packet */
protocol->charset = 0;
gwbuf_copy_data(buffer, MYSQL_CHARSET_OFFSET, 1, (uint8_t*)&protocol->charset);
gwbuf_copy_data(buffer, MYSQL_CLIENT_CAP_OFFSET, MYSQL_CLIENT_CAP_SIZE,
(uint8_t*)&protocol->client_capabilities);
gwbuf_copy_data(buffer, MYSQL_SEQ_OFFSET, 1, &auth->sequence); gwbuf_copy_data(buffer, MYSQL_SEQ_OFFSET, 1, &auth->sequence);
if (buflen > MYSQL_AUTH_PACKET_BASE_SIZE)
{
buflen -= MYSQL_AUTH_PACKET_BASE_SIZE;
/** TODO: Implement something that can safely iterate bytes of a GWBUF
* so that we know where the terminating null character is. For the time
* being, we'll just copy everything. */
uint8_t data[buflen];
gwbuf_copy_data(buffer, MYSQL_AUTH_PACKET_BASE_SIZE, buflen, data);
MYSQL_session *ses = (MYSQL_session*)dcb->data;
/** data is null-terminated so the strcpy is safe */
strcpy(ses->user, (char*)data);
}
} }
/** /**

View File

@ -298,46 +298,30 @@ mysql_auth_set_client_data(
uint8_t client_auth_packet[client_auth_packet_size]; uint8_t client_auth_packet[client_auth_packet_size];
gwbuf_copy_data(buffer, 0, client_auth_packet_size, client_auth_packet); gwbuf_copy_data(buffer, 0, client_auth_packet_size, client_auth_packet);
/* The numbers are the fixed elements in the client handshake packet */
int auth_packet_base_size = MYSQL_AUTH_PACKET_BASE_SIZE;
int packet_length_used = 0; int packet_length_used = 0;
/* Take data from fixed locations first */
memcpy(&protocol->client_capabilities, client_auth_packet + 4, 4);
protocol->charset = 0;
memcpy(&protocol->charset, client_auth_packet + 4 + 4 + 4, 1);
/* Make username and database a null string in case none is provided */
client_data->user[0] = 0;
client_data->db[0] = 0;
/* Make authentication token length 0 and token null in case none is provided */ /* Make authentication token length 0 and token null in case none is provided */
client_data->auth_token_len = 0; client_data->auth_token_len = 0;
client_data->auth_token = NULL; client_data->auth_token = NULL;
if (client_auth_packet_size > auth_packet_base_size) if (client_auth_packet_size > MYSQL_AUTH_PACKET_BASE_SIZE)
{ {
/* Should have a username */ /* Should have a username */
char *first_letter_of_username = (char *)(client_auth_packet + auth_packet_base_size); char *first_letter_of_username = (char *)(client_auth_packet + MYSQL_AUTH_PACKET_BASE_SIZE);
int user_length = strlen(first_letter_of_username); int user_length = strlen(first_letter_of_username);
if (client_auth_packet_size > (auth_packet_base_size + user_length)
&& user_length <= MYSQL_USER_MAXLEN) ss_dassert(client_auth_packet_size > (MYSQL_AUTH_PACKET_BASE_SIZE + user_length)
{ && user_length <= MYSQL_USER_MAXLEN);
strcpy(client_data->user, first_letter_of_username);
} if (client_auth_packet_size > (MYSQL_AUTH_PACKET_BASE_SIZE + user_length + 1))
else
{
/* Packet has incomplete or too long username */
return MXS_AUTH_FAILED;
}
if (client_auth_packet_size > (auth_packet_base_size + user_length + 1))
{ {
/* Extra 1 is for the terminating null after user name */ /* Extra 1 is for the terminating null after user name */
packet_length_used = auth_packet_base_size + user_length + 1; packet_length_used = MYSQL_AUTH_PACKET_BASE_SIZE + user_length + 1;
/* We should find an authentication token next */ /* We should find an authentication token next */
/* One byte of packet is the length of authentication token */ /* One byte of packet is the length of authentication token */
memcpy(&client_data->auth_token_len, memcpy(&client_data->auth_token_len,
client_auth_packet + packet_length_used, client_auth_packet + packet_length_used, 1);
1);
if (client_auth_packet_size > if (client_auth_packet_size >
(packet_length_used + client_data->auth_token_len)) (packet_length_used + client_data->auth_token_len))
{ {
@ -346,7 +330,7 @@ mysql_auth_set_client_data(
{ {
/* The extra 1 is for the token length byte, just extracted*/ /* The extra 1 is for the token length byte, just extracted*/
memcpy(client_data->auth_token, memcpy(client_data->auth_token,
client_auth_packet + auth_packet_base_size + user_length + 1 + 1, client_auth_packet + MYSQL_AUTH_PACKET_BASE_SIZE + user_length + 1 + 1,
client_data->auth_token_len); client_data->auth_token_len);
} }
else else
@ -360,29 +344,6 @@ mysql_auth_set_client_data(
/* Packet was too small to contain authentication token */ /* Packet was too small to contain authentication token */
return MXS_AUTH_FAILED; return MXS_AUTH_FAILED;
} }
packet_length_used += 1 + client_data->auth_token_len;
/*
* Note: some clients may pass empty database, CONNECT_WITH_DB !=0 but database =""
*/
if ((uint32_t)GW_MYSQL_CAPABILITIES_CONNECT_WITH_DB &
gw_mysql_get_byte4((uint8_t *)&protocol->client_capabilities)
&& client_auth_packet_size > packet_length_used)
{
char *database = (char *)(client_auth_packet + packet_length_used);
int database_length = strlen(database);
if (client_auth_packet_size >
(packet_length_used + database_length)
&& strlen(database) <= MYSQL_DATABASE_MAXLEN)
{
strcpy(client_data->db, database);
}
else
{
/* Packet is too short to contain database string */
/* or database string in packet is too long */
return MXS_AUTH_FAILED;
}
}
} }
} }
return MXS_AUTH_SUCCEEDED; return MXS_AUTH_SUCCEEDED;

View File

@ -466,6 +466,44 @@ int gw_read_client_event(DCB* dcb)
return return_code; return return_code;
} }
/**
* @brief Store client connection information into the DCB
* @param dcb Client DCB
* @param buffer Buffer containing the handshake response packet
*/
static void store_client_information(DCB *dcb, GWBUF *buffer)
{
size_t len = gwbuf_length(buffer);
uint8_t data[len];
MySQLProtocol *proto = (MySQLProtocol*)dcb->protocol;
MYSQL_session *ses = (MYSQL_session*)dcb->data;
gwbuf_copy_data(buffer, 0, len, data);
ss_dassert(MYSQL_GET_PACKET_LEN(data) + MYSQL_HEADER_LEN == len);
proto->client_capabilities = gw_mysql_get_byte4(data + MYSQL_CLIENT_CAP_OFFSET);
proto->charset = data[MYSQL_CHARSET_OFFSET];
strcpy(ses->user, (char*)data + MYSQL_AUTH_PACKET_BASE_SIZE);
*ses->db = '\0';
if (proto->client_capabilities & GW_MYSQL_CAPABILITIES_CONNECT_WITH_DB)
{
/** Client supports default database on connect */
size_t userlen = strlen(ses->user) + 1;
/** Skip the authentication token, it is handled by the authenticators */
uint8_t authlen = data[MYSQL_AUTH_PACKET_BASE_SIZE + userlen];
size_t dboffset = MYSQL_AUTH_PACKET_BASE_SIZE + userlen + authlen + 1;
if (data[dboffset])
{
/** Client is connecting with a default database */
strcpy(ses->db, (char*)data + dboffset);
}
}
}
/** /**
* @brief Client read event, process when client not yet authenticated * @brief Client read event, process when client not yet authenticated
* *
@ -490,6 +528,14 @@ gw_read_do_authentication(DCB *dcb, GWBUF *read_buffer, int nbytes_read)
/** Read the client's packet sequence and increment that by one */ /** Read the client's packet sequence and increment that by one */
uint8_t next_sequence; uint8_t next_sequence;
gwbuf_copy_data(read_buffer, MYSQL_SEQ_OFFSET, 1, &next_sequence); gwbuf_copy_data(read_buffer, MYSQL_SEQ_OFFSET, 1, &next_sequence);
if (next_sequence == 1)
{
/** This is the first response from the client, read the connection
* information and store them in the shared structure */
store_client_information(dcb, read_buffer);
}
next_sequence++; next_sequence++;
/** /**