MXS-2883: Handle AuthSwitchRequest packets

The backend didn't expect AuthSwitchRequest packets in response to the
handshake response packets. This is allowed by the protocol and appears to
happen with at least MySQL 8.0.
This commit is contained in:
Markus Mäkelä 2020-02-10 12:09:05 +02:00
parent ef769573e4
commit c18f9c6bd7
No known key found for this signature in database
GPG Key ID: 5CE746D557ACC499
4 changed files with 30 additions and 22 deletions

View File

@ -510,7 +510,7 @@ bool gw_read_backend_handshake(DCB* dcb, GWBUF* buffer);
mxs_auth_state_t gw_send_backend_auth(DCB* dcb);
/** Sends a response for an AuthSwitchRequest to the default auth plugin */
int send_mysql_native_password_response(DCB* dcb);
int send_mysql_native_password_response(DCB* dcb, GWBUF* buffer);
/** Sends an AuthSwitchRequest packet with the default auth plugin to the DCB */
bool send_auth_switch_request_packet(DCB* dcb);

View File

@ -92,6 +92,11 @@ static bool auth_backend_extract(DCB* dcb, GWBUF* buf)
rval = true;
mba->state = MBA_AUTH_OK;
}
else if (mxs_mysql_get_command(buf) == MYSQL_REPLY_AUTHSWITCHREQUEST
&& send_mysql_native_password_response(dcb, buf))
{
rval = true;
}
else
{
mba->state = MBA_AUTH_FAILED;
@ -124,6 +129,11 @@ static int auth_backend_authenticate(DCB* dcb)
/** Authentication completed successfully */
rval = MXS_AUTH_SUCCEEDED;
}
else if (mba->state == MBA_NEED_OK)
{
/** Sent AuthSwitchRequest response */
rval = MXS_AUTH_INCOMPLETE;
}
return rval;
}

View File

@ -784,14 +784,7 @@ static bool handle_auth_change_response(GWBUF* reply, MySQLProtocol* proto, DCB*
* a new scramble for the re-authentication process.
*/
// Load the new scramble into the protocol...
gwbuf_copy_data(reply,
5 + strlen(DEFAULT_MYSQL_AUTH_PLUGIN) + 1,
GW_MYSQL_SCRAMBLE_SIZE,
proto->scramble);
/// ... and use it to send the encrypted password to the server
rval = send_mysql_native_password_response(dcb);
rval = send_mysql_native_password_response(dcb, reply);
}
return rval;

View File

@ -1009,19 +1009,30 @@ mxs_auth_state_t gw_send_backend_auth(DCB* dcb)
return rval;
}
int send_mysql_native_password_response(DCB* dcb)
int send_mysql_native_password_response(DCB* dcb, GWBUF* reply)
{
MySQLProtocol* proto = (MySQLProtocol*) dcb->protocol;
MYSQL_session local_session;
gw_get_shared_session_auth_info(dcb, &local_session);
const char default_plugin_name[] = DEFAULT_MYSQL_AUTH_PLUGIN;
// Calculate the next sequence number
uint8_t seqno = 0;
gwbuf_copy_data(reply, 3, 1, &seqno);
++seqno;
// Copy the new scramble. Skip packet header, command byte and null-terminated plugin name.
gwbuf_copy_data(reply, MYSQL_HEADER_LEN + 1 + sizeof(default_plugin_name),
sizeof(proto->scramble), proto->scramble);
uint8_t* curr_passwd = memcmp(local_session.client_sha1, null_client_sha1, MYSQL_SCRAMBLE_LEN) ?
local_session.client_sha1 : null_client_sha1;
GWBUF* buffer = gwbuf_alloc(MYSQL_HEADER_LEN + GW_MYSQL_SCRAMBLE_SIZE);
uint8_t* data = GWBUF_DATA(buffer);
gw_mysql_set_byte3(data, GW_MYSQL_SCRAMBLE_SIZE);
data[3] = 2; // This is the third packet after the COM_CHANGE_USER
data[3] = seqno;
calculate_hash(proto->scramble, curr_passwd, data + MYSQL_HEADER_LEN);
return dcb_write(dcb, buffer);
@ -1060,7 +1071,7 @@ int gw_decode_mysql_server_handshake(MySQLProtocol* conn, uint8_t* payload)
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] = "";
int scramble_len = 0;
uint8_t scramble_len = 0;
uint8_t mxs_scramble[GW_MYSQL_SCRAMBLE_SIZE] = "";
int protocol_version = 0;
@ -1116,21 +1127,15 @@ int gw_decode_mysql_server_handshake(MySQLProtocol* conn, uint8_t* payload)
// get scramble len
if (payload[0] > 0)
{
scramble_len = payload[0] - 1;
mxb_assert(scramble_len > GW_SCRAMBLE_LENGTH_323);
mxb_assert(scramble_len <= GW_MYSQL_SCRAMBLE_SIZE);
if ((scramble_len < GW_SCRAMBLE_LENGTH_323)
|| scramble_len > GW_MYSQL_SCRAMBLE_SIZE)
{
/* log this */
return -2;
}
scramble_len = std::min(payload[0] - 1, GW_MYSQL_SCRAMBLE_SIZE);
}
else
{
scramble_len = GW_MYSQL_SCRAMBLE_SIZE;
}
mxb_assert(scramble_len > GW_SCRAMBLE_LENGTH_323);
// skip 10 zero bytes
payload += 11;