MXS-1826: Respond with AuthSwitchRequest to COM_CHANGE_USER
To support a wider range of client connectors, MaxScale should respond with an AuthSwitchRequest packet to all COM_CHANGE_USER commands. Only MariaDB connectors understand the OK packet as the only response to a COM_CHANGE_USER but all connectors understand the AuthSwitchRequest packet.
This commit is contained in:
@ -513,6 +513,9 @@ mxs_auth_state_t gw_send_backend_auth(DCB *dcb);
|
|||||||
/** Sends a response for an AuthSwitchRequest to the default auth plugin */
|
/** 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);
|
||||||
|
|
||||||
|
/** Sends an AuthSwitchRequest packet with the default auth plugin to the DCB */
|
||||||
|
bool send_auth_switch_request_packet(DCB* dcb);
|
||||||
|
|
||||||
/** Write an OK packet to a DCB */
|
/** Write an OK packet to a DCB */
|
||||||
int mxs_mysql_send_ok(DCB *dcb, int sequence, uint8_t affected_rows, const char* message);
|
int mxs_mysql_send_ok(DCB *dcb, int sequence, uint8_t affected_rows, const char* message);
|
||||||
|
|
||||||
|
@ -986,7 +986,14 @@ gw_read_normal_data(DCB *dcb, GWBUF *read_buffer, int nbytes_read)
|
|||||||
* the smallest version number. */
|
* the smallest version number. */
|
||||||
qc_set_server_version(service_get_version(session->service, SERVICE_VERSION_MIN));
|
qc_set_server_version(service_get_version(session->service, SERVICE_VERSION_MIN));
|
||||||
|
|
||||||
spec_com_res_t res = process_special_commands(dcb, read_buffer, nbytes_read);
|
spec_com_res_t res = RES_CONTINUE;
|
||||||
|
MySQLProtocol* proto = static_cast<MySQLProtocol*>(dcb->protocol);
|
||||||
|
|
||||||
|
if (!proto->changing_user)
|
||||||
|
{
|
||||||
|
res = process_special_commands(dcb, read_buffer, nbytes_read);
|
||||||
|
}
|
||||||
|
|
||||||
int rval = 1;
|
int rval = 1;
|
||||||
switch (res)
|
switch (res)
|
||||||
{
|
{
|
||||||
@ -1449,6 +1456,37 @@ void update_current_command(DCB* dcb, GWBUF* buffer)
|
|||||||
check_pool_candidate(dcb);
|
check_pool_candidate(dcb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform re-authentication of the client
|
||||||
|
*
|
||||||
|
* @param session Client session
|
||||||
|
* @param packetbuf Client's response to the AuthSwitchRequest
|
||||||
|
*
|
||||||
|
* @return True if the user is allowed access
|
||||||
|
*/
|
||||||
|
static bool reauthenticate_client(MXS_SESSION* session, GWBUF* packetbuf)
|
||||||
|
{
|
||||||
|
bool rval = false;
|
||||||
|
|
||||||
|
if (session->client_dcb->authfunc.reauthenticate)
|
||||||
|
{
|
||||||
|
MySQLProtocol* proto = (MySQLProtocol*)session->client_dcb->protocol;
|
||||||
|
MYSQL_session* data = (MYSQL_session*)session->client_dcb->data;
|
||||||
|
uint8_t client_sha1[MYSQL_SCRAMBLE_LEN] = {};
|
||||||
|
uint8_t payload[gwbuf_length(packetbuf) - MYSQL_HEADER_LEN];
|
||||||
|
gwbuf_copy_data(packetbuf, MYSQL_HEADER_LEN, sizeof(payload), payload);
|
||||||
|
|
||||||
|
int rc = session->client_dcb->authfunc.reauthenticate(session->client_dcb, data->user,
|
||||||
|
payload, sizeof(payload),
|
||||||
|
proto->scramble, sizeof(proto->scramble),
|
||||||
|
client_sha1, sizeof(client_sha1));
|
||||||
|
|
||||||
|
rval = rc == MXS_AUTH_SUCCEEDED;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detect if buffer includes partial mysql packet or multiple packets.
|
* Detect if buffer includes partial mysql packet or multiple packets.
|
||||||
* Store partial packet to dcb_readqueue. Send complete packets one by one
|
* Store partial packet to dcb_readqueue. Send complete packets one by one
|
||||||
@ -1480,11 +1518,15 @@ static int route_by_statement(MXS_SESSION* session, uint64_t capabilities, GWBUF
|
|||||||
if (packetbuf != NULL)
|
if (packetbuf != NULL)
|
||||||
{
|
{
|
||||||
CHK_GWBUF(packetbuf);
|
CHK_GWBUF(packetbuf);
|
||||||
|
MySQLProtocol* proto = (MySQLProtocol*)session->client_dcb->protocol;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the currently command being executed.
|
* Update the currently command being executed.
|
||||||
*/
|
*/
|
||||||
update_current_command(session->client_dcb, packetbuf);
|
if (!proto->changing_user)
|
||||||
|
{
|
||||||
|
update_current_command(session->client_dcb, packetbuf);
|
||||||
|
}
|
||||||
|
|
||||||
if (rcap_type_required(capabilities, RCAP_TYPE_CONTIGUOUS_INPUT))
|
if (rcap_type_required(capabilities, RCAP_TYPE_CONTIGUOUS_INPUT))
|
||||||
{
|
{
|
||||||
@ -1559,8 +1601,26 @@ static int route_by_statement(MXS_SESSION* session, uint64_t capabilities, GWBUF
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Route query */
|
bool changed_user = false;
|
||||||
rc = MXS_SESSION_ROUTE_QUERY(session, packetbuf);
|
|
||||||
|
if (!proto->changing_user && proto->current_command == MXS_COM_CHANGE_USER)
|
||||||
|
{
|
||||||
|
changed_user = true;
|
||||||
|
send_auth_switch_request_packet(session->client_dcb);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proto->changing_user)
|
||||||
|
{
|
||||||
|
rc = reauthenticate_client(session, packetbuf) ? 1 : 0;
|
||||||
|
gwbuf_free(packetbuf);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/** Route query */
|
||||||
|
rc = MXS_SESSION_ROUTE_QUERY(session, packetbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
proto->changing_user = changed_user;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1404,6 +1404,23 @@ int send_mysql_native_password_response(DCB* dcb)
|
|||||||
return dcb_write(dcb, buffer);
|
return dcb_write(dcb, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool send_auth_switch_request_packet(DCB* dcb)
|
||||||
|
{
|
||||||
|
MySQLProtocol* proto = (MySQLProtocol*) dcb->protocol;
|
||||||
|
const char plugin[] = DEFAULT_MYSQL_AUTH_PLUGIN;
|
||||||
|
uint32_t len = 1 + sizeof(plugin) + GW_MYSQL_SCRAMBLE_SIZE;
|
||||||
|
GWBUF* buffer = gwbuf_alloc(MYSQL_HEADER_LEN + len);
|
||||||
|
|
||||||
|
uint8_t* data = GWBUF_DATA(buffer);
|
||||||
|
gw_mysql_set_byte3(data, len);
|
||||||
|
data[3] = 1; // First response to the COM_CHANGE_USER
|
||||||
|
data[MYSQL_HEADER_LEN] = MYSQL_REPLY_AUTHSWITCHREQUEST;
|
||||||
|
memcpy(data + MYSQL_HEADER_LEN + 1, plugin, sizeof(plugin));
|
||||||
|
memcpy(data + MYSQL_HEADER_LEN + 1 + sizeof(plugin), proto->scramble, GW_MYSQL_SCRAMBLE_SIZE);
|
||||||
|
|
||||||
|
return dcb_write(dcb, buffer) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decode mysql server handshake
|
* Decode mysql server handshake
|
||||||
*
|
*
|
||||||
|
Reference in New Issue
Block a user