diff --git a/include/maxscale/protocol/mysql.hh b/include/maxscale/protocol/mysql.hh index 4780da406..547feb029 100644 --- a/include/maxscale/protocol/mysql.hh +++ b/include/maxscale/protocol/mysql.hh @@ -508,7 +508,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); diff --git a/server/modules/authenticator/MariaDBBackendAuth/mysql_backend_auth.cc b/server/modules/authenticator/MariaDBBackendAuth/mysql_backend_auth.cc index 0f54d98e6..c756bdfdf 100644 --- a/server/modules/authenticator/MariaDBBackendAuth/mysql_backend_auth.cc +++ b/server/modules/authenticator/MariaDBBackendAuth/mysql_backend_auth.cc @@ -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; } diff --git a/server/modules/protocol/MySQL/mariadbbackend/mysql_backend.cc b/server/modules/protocol/MySQL/mariadbbackend/mysql_backend.cc index 7e8fbe09d..62adf12b0 100644 --- a/server/modules/protocol/MySQL/mariadbbackend/mysql_backend.cc +++ b/server/modules/protocol/MySQL/mariadbbackend/mysql_backend.cc @@ -782,14 +782,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; diff --git a/server/modules/protocol/MySQL/mysql_common.cc b/server/modules/protocol/MySQL/mysql_common.cc index cbadce85a..691218d84 100644 --- a/server/modules/protocol/MySQL/mysql_common.cc +++ b/server/modules/protocol/MySQL/mysql_common.cc @@ -987,19 +987,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); @@ -1038,7 +1049,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; @@ -1094,21 +1105,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;