MXS-862: Create common MySQL library
The MySQLCommon library contains functions used by both the protocol and authenticator modules. The contents of the modutil.c file could also be moved to this file if the functions in that file are only used by modules and not the core.
This commit is contained in:
parent
d87f15b7f6
commit
cb7c112764
@ -30,7 +30,7 @@ target_link_libraries(test_log maxscale-common)
|
||||
target_link_libraries(test_logorder maxscale-common)
|
||||
target_link_libraries(test_logthrottling maxscale-common)
|
||||
target_link_libraries(test_modutil maxscale-common)
|
||||
target_link_libraries(test_mysql_users MySQLClient maxscale-common)
|
||||
target_link_libraries(test_mysql_users MySQLAuth MySQLCommon maxscale-common)
|
||||
target_link_libraries(test_poll maxscale-common)
|
||||
target_link_libraries(test_queuemanager maxscale-common)
|
||||
target_link_libraries(test_server maxscale-common)
|
||||
|
@ -1,21 +1,20 @@
|
||||
add_library(MySQLAuth SHARED mysql_auth.c)
|
||||
target_link_libraries(MySQLAuth maxscale-common)
|
||||
target_link_libraries(MySQLAuth maxscale-common MySQLCommon)
|
||||
set_target_properties(MySQLAuth PROPERTIES VERSION "1.0.0")
|
||||
install_module(MySQLAuth core)
|
||||
|
||||
add_library(MySQLBackendAuth SHARED mysql_backend_auth.c)
|
||||
target_link_libraries(MySQLBackendAuth maxscale-common MySQLBackend)
|
||||
target_link_libraries(MySQLBackendAuth maxscale-common MySQLCommon)
|
||||
set_target_properties(MySQLBackendAuth PROPERTIES VERSION "1.0.0")
|
||||
install_module(MySQLBackendAuth core)
|
||||
|
||||
add_library(GSSAPIAuth SHARED gssapi_auth.c gssapi_auth_common.c)
|
||||
target_link_libraries(GSSAPIAuth maxscale-common gssapi_krb5)
|
||||
target_link_libraries(GSSAPIAuth maxscale-common gssapi_krb5 MySQLCommon)
|
||||
set_target_properties(GSSAPIAuth PROPERTIES VERSION "1.0.0")
|
||||
install_module(GSSAPIAuth core)
|
||||
|
||||
add_library(GSSAPIBackendAuth SHARED gssapi_backend_auth.c gssapi_auth_common.c)
|
||||
target_link_libraries(GSSAPIBackendAuth maxscale-common gssapi_krb5
|
||||
MySQLBackend) # Needed for gw_send_backend_auth
|
||||
target_link_libraries(GSSAPIBackendAuth maxscale-common gssapi_krb5 MySQLCommon)
|
||||
set_target_properties(GSSAPIBackendAuth PROPERTIES VERSION "1.0.0")
|
||||
install_module(GSSAPIBackendAuth core)
|
||||
|
||||
|
@ -281,26 +281,10 @@ int gssapi_auth_authenticate(DCB *dcb)
|
||||
|
||||
MYSQL_session *ses = (MYSQL_session*)dcb->data;
|
||||
|
||||
if (validate_gssapi_token(ses->auth_token, ses->auth_token_len))
|
||||
if (validate_gssapi_token(ses->auth_token, ses->auth_token_len) &&
|
||||
mxs_mysql_send_ok(dcb, 4, 0, NULL))
|
||||
{
|
||||
/** Auth token is valid, send the OK packet
|
||||
* @see https://dev.mysql.com/doc/internals/en/packet-OK_Packet.html */
|
||||
uint8_t ok_packet[] =
|
||||
{
|
||||
0x07, 0x00, 0x00, 0x04, // Header
|
||||
0x00, // OK byte
|
||||
0x00, // Affected rows
|
||||
0x00, // Last insert id
|
||||
0x02, 0x00, // Status flags
|
||||
0x00, 0x00 // Warnings
|
||||
};
|
||||
|
||||
GWBUF *buffer = gwbuf_alloc_and_load(sizeof(ok_packet), ok_packet);
|
||||
|
||||
if (buffer && dcb->func.write(dcb, buffer))
|
||||
{
|
||||
rval = MXS_AUTH_SUCCEEDED;
|
||||
}
|
||||
rval = MXS_AUTH_SUCCEEDED;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -192,6 +192,8 @@ mysql_auth_authenticate(DCB *dcb)
|
||||
if (MXS_AUTH_SUCCEEDED == auth_ret)
|
||||
{
|
||||
dcb->user = MXS_STRDUP_A(client_data->user);
|
||||
/** Send an OK packet to the client */
|
||||
mxs_mysql_send_ok(dcb, ssl_required_by_dcb(dcb) ? 3 : 2, 0, NULL);
|
||||
}
|
||||
else if (dcb->service->log_auth_warnings)
|
||||
{
|
||||
|
@ -380,4 +380,7 @@ bool gw_read_backend_handshake(DCB *dcb, GWBUF *buffer);
|
||||
/** Send the server handshake response packet to the backend server */
|
||||
mxs_auth_state_t gw_send_backend_auth(DCB *dcb);
|
||||
|
||||
/** Write an OK packet to a DCB */
|
||||
int mxs_mysql_send_ok(DCB *dcb, int sequence, int affected_rows, const char* message);
|
||||
|
||||
#endif /** _MYSQL_PROTOCOL_H */
|
||||
|
@ -5,8 +5,7 @@ endif()
|
||||
|
||||
add_subdirectory(HTTPD)
|
||||
add_subdirectory(maxscaled)
|
||||
add_subdirectory(MySQLBackend)
|
||||
add_subdirectory(MySQLClient)
|
||||
add_subdirectory(MySQL)
|
||||
add_subdirectory(telnetd)
|
||||
|
||||
if(BUILD_TESTS)
|
||||
|
7
server/modules/protocol/MySQL/CMakeLists.txt
Normal file
7
server/modules/protocol/MySQL/CMakeLists.txt
Normal file
@ -0,0 +1,7 @@
|
||||
add_library(MySQLCommon SHARED mysql_common.c)
|
||||
target_link_libraries(MySQLCommon maxscale-common)
|
||||
set_target_properties(MySQLCommon PROPERTIES VERSION "2.0.0")
|
||||
install_module(MySQLCommon core)
|
||||
|
||||
add_subdirectory(MySQLBackend)
|
||||
add_subdirectory(MySQLClient)
|
@ -0,0 +1,7 @@
|
||||
add_library(MySQLBackend SHARED mysql_backend.c)
|
||||
# TODO: Refactor MySQLBackend so that COM_CHANGE_USER processing is
|
||||
# transparent to the protocol module. After this change, we don't need to
|
||||
# link against MySQLAuth.
|
||||
target_link_libraries(MySQLBackend maxscale-common MySQLCommon MySQLAuth)
|
||||
set_target_properties(MySQLBackend PROPERTIES VERSION "2.0.0")
|
||||
install_module(MySQLBackend core)
|
@ -661,290 +661,6 @@ gw_reply_on_error(DCB *dcb, mxs_auth_state_t state)
|
||||
gwbuf_free(errbuf);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Computes the size of the response to the DB initial handshake
|
||||
*
|
||||
* When the connection is to be SSL, but an SSL connection has not yet been
|
||||
* established, only a basic 36 byte response is sent, including the SSL
|
||||
* capability flag.
|
||||
*
|
||||
* Otherwise, the packet size is computed, based on the minimum size and
|
||||
* increased by the optional or variable elements.
|
||||
*
|
||||
* @param conn The MySQLProtocol structure for the connection
|
||||
* @param user Name of the user seeking to connect
|
||||
* @param passwd Password for the user seeking to connect
|
||||
* @param dbname Name of the database to be made default, if any
|
||||
* @return The length of the response packet
|
||||
*/
|
||||
static int
|
||||
response_length(MySQLProtocol *conn, char *user, uint8_t *passwd, char *dbname, const char *auth_module)
|
||||
{
|
||||
long bytes;
|
||||
|
||||
if (conn->owner_dcb->server->server_ssl && conn->owner_dcb->ssl_state != SSL_ESTABLISHED)
|
||||
{
|
||||
return 36;
|
||||
}
|
||||
|
||||
// Protocol MySQL HandshakeResponse for CLIENT_PROTOCOL_41
|
||||
// 4 bytes capabilities + 4 bytes max packet size + 1 byte charset + 23 '\0' bytes
|
||||
// 4 + 4 + 1 + 23 = 32
|
||||
bytes = 32;
|
||||
|
||||
if (user)
|
||||
{
|
||||
bytes += strlen(user);
|
||||
}
|
||||
// the NULL
|
||||
bytes++;
|
||||
|
||||
// next will be + 1 (scramble_len) + 20 (fixed_scramble) + 1 (user NULL term) + 1 (db NULL term)
|
||||
|
||||
if (passwd)
|
||||
{
|
||||
bytes += GW_MYSQL_SCRAMBLE_SIZE;
|
||||
}
|
||||
bytes++;
|
||||
|
||||
if (dbname && strlen(dbname))
|
||||
{
|
||||
bytes += strlen(dbname);
|
||||
bytes++;
|
||||
}
|
||||
|
||||
bytes += strlen(auth_module);
|
||||
bytes++;
|
||||
|
||||
// the packet header
|
||||
bytes += 4;
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Helper function to load hashed password
|
||||
* @param conn DCB Protocol object
|
||||
* @param payload Destination where hashed password is written
|
||||
* @param passwd Client's double SHA1 password
|
||||
* @return Address of the next byte after the end of the stored password
|
||||
*/
|
||||
static uint8_t *
|
||||
load_hashed_password(uint8_t *scramble, uint8_t *payload, uint8_t *passwd)
|
||||
{
|
||||
uint8_t hash1[GW_MYSQL_SCRAMBLE_SIZE] = "";
|
||||
uint8_t hash2[GW_MYSQL_SCRAMBLE_SIZE] = "";
|
||||
uint8_t new_sha[GW_MYSQL_SCRAMBLE_SIZE] = "";
|
||||
uint8_t client_scramble[GW_MYSQL_SCRAMBLE_SIZE];
|
||||
|
||||
// hash1 is the function input, SHA1(real_password)
|
||||
memcpy(hash1, passwd, GW_MYSQL_SCRAMBLE_SIZE);
|
||||
|
||||
// hash2 is the SHA1(input data), where input_data = SHA1(real_password)
|
||||
gw_sha1_str(hash1, GW_MYSQL_SCRAMBLE_SIZE, hash2);
|
||||
|
||||
// new_sha is the SHA1(CONCAT(scramble, hash2)
|
||||
gw_sha1_2_str(scramble, GW_MYSQL_SCRAMBLE_SIZE, hash2, GW_MYSQL_SCRAMBLE_SIZE, new_sha);
|
||||
|
||||
// compute the xor in client_scramble
|
||||
gw_str_xor(client_scramble, new_sha, hash1, GW_MYSQL_SCRAMBLE_SIZE);
|
||||
|
||||
// set the auth-length
|
||||
*payload = GW_MYSQL_SCRAMBLE_SIZE;
|
||||
payload++;
|
||||
|
||||
//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);
|
||||
|
||||
payload += GW_MYSQL_SCRAMBLE_SIZE;
|
||||
return payload;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Computes the capabilities bit mask for connecting to backend DB
|
||||
*
|
||||
* We start by taking the default bitmask and removing any bits not set in
|
||||
* the bitmask contained in the connection structure. Then add SSL flag if
|
||||
* the connection requires SSL (set from the MaxScale configuration). The
|
||||
* compression flag may be set, although compression is NOT SUPPORTED. If a
|
||||
* database name has been specified in the function call, the relevant flag
|
||||
* is set.
|
||||
*
|
||||
* @param conn The MySQLProtocol structure for the connection
|
||||
* @param db_specified Whether the connection request specified a database
|
||||
* @param compress Whether compression is requested - NOT SUPPORTED
|
||||
* @return Bit mask (32 bits)
|
||||
* @note Capability bits are defined in mysql_client_server_protocol.h
|
||||
*/
|
||||
static uint32_t
|
||||
create_capabilities(MySQLProtocol *conn, bool db_specified, bool compress)
|
||||
{
|
||||
uint32_t final_capabilities;
|
||||
|
||||
/** Copy client's flags to backend but with the known capabilities mask */
|
||||
final_capabilities = (conn->client_capabilities & (uint32_t)GW_MYSQL_CAPABILITIES_CLIENT);
|
||||
|
||||
if (conn->owner_dcb->server->server_ssl)
|
||||
{
|
||||
final_capabilities |= (uint32_t)GW_MYSQL_CAPABILITIES_SSL;
|
||||
/* Unclear whether we should include this */
|
||||
/* Maybe it should depend on whether CA certificate is provided */
|
||||
/* final_capabilities |= (uint32_t)GW_MYSQL_CAPABILITIES_SSL_VERIFY_SERVER_CERT; */
|
||||
}
|
||||
|
||||
/* Compression is not currently supported */
|
||||
if (compress)
|
||||
{
|
||||
final_capabilities |= (uint32_t)GW_MYSQL_CAPABILITIES_COMPRESS;
|
||||
#ifdef DEBUG_MYSQL_CONN
|
||||
fprintf(stderr, ">>>> Backend Connection with compression\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (db_specified)
|
||||
{
|
||||
/* With database specified */
|
||||
final_capabilities |= (int)GW_MYSQL_CAPABILITIES_CONNECT_WITH_DB;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Without database specified */
|
||||
final_capabilities &= ~(int)GW_MYSQL_CAPABILITIES_CONNECT_WITH_DB;
|
||||
}
|
||||
|
||||
final_capabilities |= (int)GW_MYSQL_CAPABILITIES_PLUGIN_AUTH;
|
||||
|
||||
return final_capabilities;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write MySQL authentication packet to backend server
|
||||
*
|
||||
* @param dcb Backend DCB
|
||||
* @return True on success, false on failure
|
||||
*/
|
||||
mxs_auth_state_t gw_send_backend_auth(DCB *dcb)
|
||||
{
|
||||
MYSQL_session local_session;
|
||||
gw_get_shared_session_auth_info(dcb, &local_session);
|
||||
|
||||
uint8_t client_capabilities[4] = {0, 0, 0, 0};
|
||||
uint8_t *curr_passwd = memcmp(local_session.client_sha1, null_client_sha1, MYSQL_SCRAMBLE_LEN) ?
|
||||
local_session.client_sha1 : NULL;
|
||||
|
||||
/**
|
||||
* If session is stopping or has failed return with error.
|
||||
*/
|
||||
if (dcb->session == NULL ||
|
||||
(dcb->session->state != SESSION_STATE_READY &&
|
||||
dcb->session->state != SESSION_STATE_ROUTER_READY) ||
|
||||
(dcb->server->server_ssl &&
|
||||
dcb->ssl_state != SSL_HANDSHAKE_FAILED))
|
||||
{
|
||||
return MXS_AUTH_STATE_FAILED;
|
||||
}
|
||||
|
||||
MySQLProtocol *conn = (MySQLProtocol*)dcb->protocol;
|
||||
uint32_t capabilities = create_capabilities(conn, (local_session.db && strlen(local_session.db)), false);
|
||||
gw_mysql_set_byte4(client_capabilities, capabilities);
|
||||
|
||||
/**
|
||||
* Use the default authentication plugin name. If the server is using a
|
||||
* different authentication mechanism, it will send an AuthSwitchRequest
|
||||
* packet.
|
||||
*/
|
||||
const char* auth_plugin_name = DEFAULT_MYSQL_AUTH_PLUGIN;
|
||||
|
||||
long bytes = response_length(conn, local_session.user, local_session.client_sha1,
|
||||
local_session.db, auth_plugin_name);
|
||||
|
||||
// allocating the GWBUF
|
||||
GWBUF *buffer = gwbuf_alloc(bytes);
|
||||
uint8_t *payload = GWBUF_DATA(buffer);
|
||||
|
||||
// clearing data
|
||||
memset(payload, '\0', bytes);
|
||||
|
||||
// put here the paylod size: bytes to write - 4 bytes packet header
|
||||
gw_mysql_set_byte3(payload, (bytes - 4));
|
||||
|
||||
// set packet # = 1
|
||||
payload[3] = (SSL_ESTABLISHED == dcb->ssl_state) ? '\x02' : '\x01';
|
||||
payload += 4;
|
||||
|
||||
// set client capabilities
|
||||
memcpy(payload, client_capabilities, 4);
|
||||
|
||||
// set now the max-packet size
|
||||
payload += 4;
|
||||
gw_mysql_set_byte4(payload, 16777216);
|
||||
|
||||
// set the charset
|
||||
payload += 4;
|
||||
*payload = conn->charset;
|
||||
|
||||
payload++;
|
||||
|
||||
// 23 bytes of 0
|
||||
payload += 23;
|
||||
|
||||
if (dcb->server->server_ssl && dcb->ssl_state != SSL_ESTABLISHED)
|
||||
{
|
||||
if (dcb_write(dcb, buffer) && dcb_connect_SSL(dcb) >= 0)
|
||||
{
|
||||
return MXS_AUTH_STATE_CONNECTED;
|
||||
}
|
||||
|
||||
return MXS_AUTH_STATE_FAILED;
|
||||
}
|
||||
|
||||
// 4 + 4 + 4 + 1 + 23 = 36, this includes the 4 bytes packet header
|
||||
memcpy(payload, local_session.user, strlen(local_session.user));
|
||||
payload += strlen(local_session.user);
|
||||
payload++;
|
||||
|
||||
if (curr_passwd != NULL)
|
||||
{
|
||||
payload = load_hashed_password(conn->scramble, payload, curr_passwd);
|
||||
}
|
||||
else
|
||||
{
|
||||
payload++;
|
||||
}
|
||||
|
||||
// if the db is not NULL append it
|
||||
if (local_session.db[0])
|
||||
{
|
||||
memcpy(payload, local_session.db, strlen(local_session.db));
|
||||
payload += strlen(local_session.db);
|
||||
payload++;
|
||||
}
|
||||
|
||||
memcpy(payload, auth_plugin_name, strlen(auth_plugin_name));
|
||||
|
||||
return dcb_write(dcb, buffer) ? MXS_AUTH_STATE_RESPONSE_SENT : MXS_AUTH_STATE_FAILED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the backend server MySQL handshake
|
||||
*
|
||||
* @param dcb Backend DCB
|
||||
* @return true on success, false on failure
|
||||
*/
|
||||
bool gw_read_backend_handshake(DCB *dcb, GWBUF *buffer)
|
||||
{
|
||||
MySQLProtocol *proto = (MySQLProtocol *)dcb->protocol;
|
||||
bool rval = false;
|
||||
uint8_t *payload = GWBUF_DATA(buffer) + 4;
|
||||
|
||||
if (gw_decode_mysql_server_handshake(proto, payload) >= 0)
|
||||
{
|
||||
rval = true;
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief With authentication completed, read new data and write to backend
|
||||
*
|
||||
@ -1649,6 +1365,8 @@ static int backend_write_delayqueue(DCB *dcb, GWBUF *buffer)
|
||||
/**
|
||||
* This routine handles the COM_CHANGE_USER command
|
||||
*
|
||||
* TODO: Move this into the authenticators
|
||||
*
|
||||
* @param dcb The current backend DCB
|
||||
* @param server The backend server pointer
|
||||
* @param in_session The current session data (MYSQL_session)
|
||||
@ -2028,105 +1746,6 @@ static bool sescmd_response_complete(DCB* dcb)
|
||||
return succp;
|
||||
}
|
||||
|
||||
/**
|
||||
* gw_decode_mysql_server_handshake
|
||||
*
|
||||
* Decode mysql server handshake
|
||||
*
|
||||
* @param conn The MySQLProtocol structure
|
||||
* @param payload The bytes just read from the net
|
||||
* @return 0 on success, < 0 on failure
|
||||
*
|
||||
*/
|
||||
static int
|
||||
gw_decode_mysql_server_handshake(MySQLProtocol *conn, uint8_t *payload)
|
||||
{
|
||||
uint8_t *server_version_end = NULL;
|
||||
uint16_t mysql_server_capabilities_one = 0;
|
||||
uint16_t mysql_server_capabilities_two = 0;
|
||||
unsigned long tid = 0;
|
||||
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 mxs_scramble[GW_MYSQL_SCRAMBLE_SIZE] = "";
|
||||
int protocol_version = 0;
|
||||
|
||||
protocol_version = payload[0];
|
||||
|
||||
if (protocol_version != GW_MYSQL_PROTOCOL_VERSION)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
payload++;
|
||||
|
||||
// Get server version (string)
|
||||
server_version_end = (uint8_t *) gw_strend((char*) payload);
|
||||
|
||||
payload = server_version_end + 1;
|
||||
|
||||
// get ThreadID: 4 bytes
|
||||
tid = gw_mysql_get_byte4(payload);
|
||||
memcpy(&conn->tid, &tid, 4);
|
||||
|
||||
payload += 4;
|
||||
|
||||
// scramble_part 1
|
||||
memcpy(scramble_data_1, payload, GW_SCRAMBLE_LENGTH_323);
|
||||
payload += GW_SCRAMBLE_LENGTH_323;
|
||||
|
||||
// 1 filler
|
||||
payload++;
|
||||
|
||||
mysql_server_capabilities_one = gw_mysql_get_byte2(payload);
|
||||
|
||||
//Get capabilities_part 1 (2 bytes) + 1 language + 2 server_status
|
||||
payload += 5;
|
||||
|
||||
mysql_server_capabilities_two = gw_mysql_get_byte2(payload);
|
||||
|
||||
memcpy(capab_ptr, &mysql_server_capabilities_one, 2);
|
||||
|
||||
// get capabilities part 2 (2 bytes)
|
||||
memcpy(&capab_ptr[2], &mysql_server_capabilities_two, 2);
|
||||
|
||||
// 2 bytes shift
|
||||
payload += 2;
|
||||
|
||||
// get scramble len
|
||||
if (payload[0] > 0)
|
||||
{
|
||||
scramble_len = payload[0] - 1;
|
||||
ss_dassert(scramble_len > GW_SCRAMBLE_LENGTH_323);
|
||||
ss_dassert(scramble_len <= GW_MYSQL_SCRAMBLE_SIZE);
|
||||
|
||||
if ((scramble_len < GW_SCRAMBLE_LENGTH_323) ||
|
||||
scramble_len > GW_MYSQL_SCRAMBLE_SIZE)
|
||||
{
|
||||
/* log this */
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
scramble_len = GW_MYSQL_SCRAMBLE_SIZE;
|
||||
}
|
||||
// skip 10 zero bytes
|
||||
payload += 11;
|
||||
|
||||
// copy the second part of the scramble
|
||||
memcpy(scramble_data_2, payload, scramble_len - GW_SCRAMBLE_LENGTH_323);
|
||||
|
||||
memcpy(mxs_scramble, scramble_data_1, GW_SCRAMBLE_LENGTH_323);
|
||||
memcpy(mxs_scramble + GW_SCRAMBLE_LENGTH_323, scramble_data_2, scramble_len - GW_SCRAMBLE_LENGTH_323);
|
||||
|
||||
// full 20 bytes scramble is ready
|
||||
memcpy(conn->scramble, mxs_scramble, GW_MYSQL_SCRAMBLE_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void inline
|
||||
close_socket(int sock)
|
||||
{
|
4
server/modules/protocol/MySQL/MySQLClient/CMakeLists.txt
Normal file
4
server/modules/protocol/MySQL/MySQLClient/CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
||||
add_library(MySQLClient SHARED mysql_client.c)
|
||||
target_link_libraries(MySQLClient maxscale-common MySQLCommon)
|
||||
set_target_properties(MySQLClient PROPERTIES VERSION "1.0.0")
|
||||
install_module(MySQLClient core)
|
@ -86,7 +86,6 @@ static int gw_client_close(DCB *dcb);
|
||||
static int gw_client_hangup_event(DCB *dcb);
|
||||
static char *gw_default_auth();
|
||||
static int gw_connection_limit(DCB *dcb, int limit);
|
||||
static int mysql_send_ok(DCB *dcb, int packet_number, int in_affected_rows, const char* mysql_message);
|
||||
static int MySQLSendHandshake(DCB* dcb);
|
||||
static int route_by_statement(SESSION *, GWBUF **);
|
||||
static void mysql_client_auth_error_handling(DCB *dcb, int auth_val);
|
||||
@ -162,92 +161,6 @@ static char *gw_default_auth()
|
||||
{
|
||||
return "MySQLAuth";
|
||||
}
|
||||
/**
|
||||
* mysql_send_ok
|
||||
*
|
||||
* Send a MySQL protocol OK message to the dcb (client)
|
||||
*
|
||||
* @param dcb Descriptor Control Block for the connection to which the OK is sent
|
||||
* @param packet_number
|
||||
* @param in_affected_rows
|
||||
* @param mysql_message
|
||||
* @return packet length
|
||||
*
|
||||
*/
|
||||
int mysql_send_ok(DCB *dcb, int packet_number, int in_affected_rows, const char* mysql_message)
|
||||
{
|
||||
uint8_t *outbuf = NULL;
|
||||
uint32_t mysql_payload_size = 0;
|
||||
uint8_t mysql_packet_header[4];
|
||||
uint8_t *mysql_payload = NULL;
|
||||
uint8_t field_count = 0;
|
||||
uint8_t affected_rows = 0;
|
||||
uint8_t insert_id = 0;
|
||||
uint8_t mysql_server_status[2];
|
||||
uint8_t mysql_warning_counter[2];
|
||||
GWBUF *buf;
|
||||
|
||||
affected_rows = in_affected_rows;
|
||||
|
||||
mysql_payload_size =
|
||||
sizeof(field_count) +
|
||||
sizeof(affected_rows) +
|
||||
sizeof(insert_id) +
|
||||
sizeof(mysql_server_status) +
|
||||
sizeof(mysql_warning_counter);
|
||||
|
||||
if (mysql_message != NULL)
|
||||
{
|
||||
mysql_payload_size += strlen(mysql_message);
|
||||
}
|
||||
|
||||
// allocate memory for packet header + payload
|
||||
if ((buf = gwbuf_alloc(sizeof(mysql_packet_header) + mysql_payload_size)) == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
outbuf = GWBUF_DATA(buf);
|
||||
|
||||
// write packet header with packet number
|
||||
gw_mysql_set_byte3(mysql_packet_header, mysql_payload_size);
|
||||
mysql_packet_header[3] = packet_number;
|
||||
|
||||
// write header
|
||||
memcpy(outbuf, mysql_packet_header, sizeof(mysql_packet_header));
|
||||
|
||||
mysql_payload = outbuf + sizeof(mysql_packet_header);
|
||||
|
||||
mysql_server_status[0] = 2;
|
||||
mysql_server_status[1] = 0;
|
||||
mysql_warning_counter[0] = 0;
|
||||
mysql_warning_counter[1] = 0;
|
||||
|
||||
// write data
|
||||
memcpy(mysql_payload, &field_count, sizeof(field_count));
|
||||
mysql_payload = mysql_payload + sizeof(field_count);
|
||||
|
||||
memcpy(mysql_payload, &affected_rows, sizeof(affected_rows));
|
||||
mysql_payload = mysql_payload + sizeof(affected_rows);
|
||||
|
||||
memcpy(mysql_payload, &insert_id, sizeof(insert_id));
|
||||
mysql_payload = mysql_payload + sizeof(insert_id);
|
||||
|
||||
memcpy(mysql_payload, mysql_server_status, sizeof(mysql_server_status));
|
||||
mysql_payload = mysql_payload + sizeof(mysql_server_status);
|
||||
|
||||
memcpy(mysql_payload, mysql_warning_counter, sizeof(mysql_warning_counter));
|
||||
mysql_payload = mysql_payload + sizeof(mysql_warning_counter);
|
||||
|
||||
if (mysql_message != NULL)
|
||||
{
|
||||
memcpy(mysql_payload, mysql_message, strlen(mysql_message));
|
||||
}
|
||||
|
||||
// writing data in the Client buffer queue
|
||||
dcb->func.write(dcb, buf);
|
||||
|
||||
return sizeof(mysql_packet_header) + mysql_payload_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* MySQLSendHandshake
|
||||
@ -625,18 +538,10 @@ gw_read_do_authentication(DCB *dcb, GWBUF *read_buffer, int nbytes_read)
|
||||
|
||||
if (session != NULL)
|
||||
{
|
||||
int packet_number = ssl_required_by_dcb(dcb) ? 3 : 2;
|
||||
|
||||
CHK_SESSION(session);
|
||||
ss_dassert(session->state != SESSION_STATE_ALLOC &&
|
||||
session->state != SESSION_STATE_DUMMY);
|
||||
|
||||
session->state != SESSION_STATE_DUMMY);
|
||||
protocol->protocol_auth_state = MXS_AUTH_STATE_COMPLETE;
|
||||
/**
|
||||
* Send an AUTH_OK packet to the client,
|
||||
* packet sequence is # packet_number
|
||||
*/
|
||||
mysql_send_ok(dcb, packet_number, 0, NULL);
|
||||
}
|
||||
else
|
||||
{
|
@ -1078,3 +1078,465 @@ bool gw_get_shared_session_auth_info(DCB* dcb, MYSQL_session* session)
|
||||
spinlock_release(&dcb->session->ses_lock);
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Send a MySQL protocol OK message to the dcb (client)
|
||||
*
|
||||
* @param dcb DCB where packet is written
|
||||
* @param sequence Packet sequence number
|
||||
* @param affected_rows Number of affected rows
|
||||
* * @param message SQL message
|
||||
* @return 1 on success, 0 on error
|
||||
*
|
||||
*/
|
||||
int mxs_mysql_send_ok(DCB *dcb, int sequence, int affected_rows, const char* message)
|
||||
{
|
||||
uint8_t *outbuf = NULL;
|
||||
uint32_t mysql_payload_size = 0;
|
||||
uint8_t mysql_packet_header[4];
|
||||
uint8_t *mysql_payload = NULL;
|
||||
uint8_t field_count = 0;
|
||||
uint8_t insert_id = 0;
|
||||
uint8_t mysql_server_status[2];
|
||||
uint8_t mysql_warning_counter[2];
|
||||
GWBUF *buf;
|
||||
|
||||
|
||||
mysql_payload_size =
|
||||
sizeof(field_count) +
|
||||
sizeof(affected_rows) +
|
||||
sizeof(insert_id) +
|
||||
sizeof(mysql_server_status) +
|
||||
sizeof(mysql_warning_counter);
|
||||
|
||||
if (message != NULL)
|
||||
{
|
||||
mysql_payload_size += strlen(message);
|
||||
}
|
||||
|
||||
// allocate memory for packet header + payload
|
||||
if ((buf = gwbuf_alloc(sizeof(mysql_packet_header) + mysql_payload_size)) == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
outbuf = GWBUF_DATA(buf);
|
||||
|
||||
// write packet header with packet number
|
||||
gw_mysql_set_byte3(mysql_packet_header, mysql_payload_size);
|
||||
mysql_packet_header[3] = sequence;
|
||||
|
||||
// write header
|
||||
memcpy(outbuf, mysql_packet_header, sizeof(mysql_packet_header));
|
||||
|
||||
mysql_payload = outbuf + sizeof(mysql_packet_header);
|
||||
|
||||
mysql_server_status[0] = 2;
|
||||
mysql_server_status[1] = 0;
|
||||
mysql_warning_counter[0] = 0;
|
||||
mysql_warning_counter[1] = 0;
|
||||
|
||||
// write data
|
||||
memcpy(mysql_payload, &field_count, sizeof(field_count));
|
||||
mysql_payload = mysql_payload + sizeof(field_count);
|
||||
|
||||
memcpy(mysql_payload, &affected_rows, sizeof(affected_rows));
|
||||
mysql_payload = mysql_payload + sizeof(affected_rows);
|
||||
|
||||
memcpy(mysql_payload, &insert_id, sizeof(insert_id));
|
||||
mysql_payload = mysql_payload + sizeof(insert_id);
|
||||
|
||||
memcpy(mysql_payload, mysql_server_status, sizeof(mysql_server_status));
|
||||
mysql_payload = mysql_payload + sizeof(mysql_server_status);
|
||||
|
||||
memcpy(mysql_payload, mysql_warning_counter, sizeof(mysql_warning_counter));
|
||||
mysql_payload = mysql_payload + sizeof(mysql_warning_counter);
|
||||
|
||||
if (message != NULL)
|
||||
{
|
||||
memcpy(mysql_payload, message, strlen(message));
|
||||
}
|
||||
|
||||
// writing data in the Client buffer queue
|
||||
return dcb->func.write(dcb, buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Computes the size of the response to the DB initial handshake
|
||||
*
|
||||
* When the connection is to be SSL, but an SSL connection has not yet been
|
||||
* established, only a basic 36 byte response is sent, including the SSL
|
||||
* capability flag.
|
||||
*
|
||||
* Otherwise, the packet size is computed, based on the minimum size and
|
||||
* increased by the optional or variable elements.
|
||||
*
|
||||
* @param conn The MySQLProtocol structure for the connection
|
||||
* @param user Name of the user seeking to connect
|
||||
* @param passwd Password for the user seeking to connect
|
||||
* @param dbname Name of the database to be made default, if any
|
||||
* @return The length of the response packet
|
||||
*/
|
||||
static int
|
||||
response_length(MySQLProtocol *conn, char *user, uint8_t *passwd, char *dbname, const char *auth_module)
|
||||
{
|
||||
long bytes;
|
||||
|
||||
if (conn->owner_dcb->server->server_ssl && conn->owner_dcb->ssl_state != SSL_ESTABLISHED)
|
||||
{
|
||||
return MYSQL_AUTH_PACKET_BASE_SIZE;
|
||||
}
|
||||
|
||||
// Protocol MySQL HandshakeResponse for CLIENT_PROTOCOL_41
|
||||
// 4 bytes capabilities + 4 bytes max packet size + 1 byte charset + 23 '\0' bytes
|
||||
// 4 + 4 + 1 + 23 = 32
|
||||
bytes = 32;
|
||||
|
||||
if (user)
|
||||
{
|
||||
bytes += strlen(user);
|
||||
}
|
||||
// the NULL
|
||||
bytes++;
|
||||
|
||||
// next will be + 1 (scramble_len) + 20 (fixed_scramble) + 1 (user NULL term) + 1 (db NULL term)
|
||||
|
||||
if (passwd)
|
||||
{
|
||||
bytes += GW_MYSQL_SCRAMBLE_SIZE;
|
||||
}
|
||||
bytes++;
|
||||
|
||||
if (dbname && strlen(dbname))
|
||||
{
|
||||
bytes += strlen(dbname);
|
||||
bytes++;
|
||||
}
|
||||
|
||||
bytes += strlen(auth_module);
|
||||
bytes++;
|
||||
|
||||
// the packet header
|
||||
bytes += 4;
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Helper function to load hashed password
|
||||
* @param conn DCB Protocol object
|
||||
* @param payload Destination where hashed password is written
|
||||
* @param passwd Client's double SHA1 password
|
||||
* @return Address of the next byte after the end of the stored password
|
||||
*/
|
||||
static uint8_t *
|
||||
load_hashed_password(uint8_t *scramble, uint8_t *payload, uint8_t *passwd)
|
||||
{
|
||||
uint8_t hash1[GW_MYSQL_SCRAMBLE_SIZE] = "";
|
||||
uint8_t hash2[GW_MYSQL_SCRAMBLE_SIZE] = "";
|
||||
uint8_t new_sha[GW_MYSQL_SCRAMBLE_SIZE] = "";
|
||||
uint8_t client_scramble[GW_MYSQL_SCRAMBLE_SIZE];
|
||||
|
||||
// hash1 is the function input, SHA1(real_password)
|
||||
memcpy(hash1, passwd, GW_MYSQL_SCRAMBLE_SIZE);
|
||||
|
||||
// hash2 is the SHA1(input data), where input_data = SHA1(real_password)
|
||||
gw_sha1_str(hash1, GW_MYSQL_SCRAMBLE_SIZE, hash2);
|
||||
|
||||
// new_sha is the SHA1(CONCAT(scramble, hash2)
|
||||
gw_sha1_2_str(scramble, GW_MYSQL_SCRAMBLE_SIZE, hash2, GW_MYSQL_SCRAMBLE_SIZE, new_sha);
|
||||
|
||||
// compute the xor in client_scramble
|
||||
gw_str_xor(client_scramble, new_sha, hash1, GW_MYSQL_SCRAMBLE_SIZE);
|
||||
|
||||
// set the auth-length
|
||||
*payload = GW_MYSQL_SCRAMBLE_SIZE;
|
||||
payload++;
|
||||
|
||||
//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);
|
||||
|
||||
payload += GW_MYSQL_SCRAMBLE_SIZE;
|
||||
return payload;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Computes the capabilities bit mask for connecting to backend DB
|
||||
*
|
||||
* We start by taking the default bitmask and removing any bits not set in
|
||||
* the bitmask contained in the connection structure. Then add SSL flag if
|
||||
* the connection requires SSL (set from the MaxScale configuration). The
|
||||
* compression flag may be set, although compression is NOT SUPPORTED. If a
|
||||
* database name has been specified in the function call, the relevant flag
|
||||
* is set.
|
||||
*
|
||||
* @param conn The MySQLProtocol structure for the connection
|
||||
* @param db_specified Whether the connection request specified a database
|
||||
* @param compress Whether compression is requested - NOT SUPPORTED
|
||||
* @return Bit mask (32 bits)
|
||||
* @note Capability bits are defined in mysql_client_server_protocol.h
|
||||
*/
|
||||
static uint32_t
|
||||
create_capabilities(MySQLProtocol *conn, bool db_specified, bool compress)
|
||||
{
|
||||
uint32_t final_capabilities;
|
||||
|
||||
/** Copy client's flags to backend but with the known capabilities mask */
|
||||
final_capabilities = (conn->client_capabilities & (uint32_t)GW_MYSQL_CAPABILITIES_CLIENT);
|
||||
|
||||
if (conn->owner_dcb->server->server_ssl)
|
||||
{
|
||||
final_capabilities |= (uint32_t)GW_MYSQL_CAPABILITIES_SSL;
|
||||
/* Unclear whether we should include this */
|
||||
/* Maybe it should depend on whether CA certificate is provided */
|
||||
/* final_capabilities |= (uint32_t)GW_MYSQL_CAPABILITIES_SSL_VERIFY_SERVER_CERT; */
|
||||
}
|
||||
|
||||
/* Compression is not currently supported */
|
||||
if (compress)
|
||||
{
|
||||
final_capabilities |= (uint32_t)GW_MYSQL_CAPABILITIES_COMPRESS;
|
||||
#ifdef DEBUG_MYSQL_CONN
|
||||
fprintf(stderr, ">>>> Backend Connection with compression\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (db_specified)
|
||||
{
|
||||
/* With database specified */
|
||||
final_capabilities |= (int)GW_MYSQL_CAPABILITIES_CONNECT_WITH_DB;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Without database specified */
|
||||
final_capabilities &= ~(int)GW_MYSQL_CAPABILITIES_CONNECT_WITH_DB;
|
||||
}
|
||||
|
||||
final_capabilities |= (int)GW_MYSQL_CAPABILITIES_PLUGIN_AUTH;
|
||||
|
||||
return final_capabilities;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write MySQL authentication packet to backend server
|
||||
*
|
||||
* @param dcb Backend DCB
|
||||
* @return True on success, false on failure
|
||||
*/
|
||||
mxs_auth_state_t gw_send_backend_auth(DCB *dcb)
|
||||
{
|
||||
MYSQL_session local_session;
|
||||
gw_get_shared_session_auth_info(dcb, &local_session);
|
||||
|
||||
uint8_t client_capabilities[4] = {0, 0, 0, 0};
|
||||
uint8_t *curr_passwd = memcmp(local_session.client_sha1, null_client_sha1, MYSQL_SCRAMBLE_LEN) ?
|
||||
local_session.client_sha1 : NULL;
|
||||
|
||||
/**
|
||||
* If session is stopping or has failed return with error.
|
||||
*/
|
||||
if (dcb->session == NULL ||
|
||||
(dcb->session->state != SESSION_STATE_READY &&
|
||||
dcb->session->state != SESSION_STATE_ROUTER_READY) ||
|
||||
(dcb->server->server_ssl &&
|
||||
dcb->ssl_state != SSL_HANDSHAKE_FAILED))
|
||||
{
|
||||
return MXS_AUTH_STATE_FAILED;
|
||||
}
|
||||
|
||||
MySQLProtocol *conn = (MySQLProtocol*)dcb->protocol;
|
||||
uint32_t capabilities = create_capabilities(conn, (local_session.db && strlen(local_session.db)), false);
|
||||
gw_mysql_set_byte4(client_capabilities, capabilities);
|
||||
|
||||
/**
|
||||
* Use the default authentication plugin name. If the server is using a
|
||||
* different authentication mechanism, it will send an AuthSwitchRequest
|
||||
* packet.
|
||||
*/
|
||||
const char* auth_plugin_name = DEFAULT_MYSQL_AUTH_PLUGIN;
|
||||
|
||||
long bytes = response_length(conn, local_session.user, local_session.client_sha1,
|
||||
local_session.db, auth_plugin_name);
|
||||
|
||||
// allocating the GWBUF
|
||||
GWBUF *buffer = gwbuf_alloc(bytes);
|
||||
uint8_t *payload = GWBUF_DATA(buffer);
|
||||
|
||||
// clearing data
|
||||
memset(payload, '\0', bytes);
|
||||
|
||||
// put here the paylod size: bytes to write - 4 bytes packet header
|
||||
gw_mysql_set_byte3(payload, (bytes - 4));
|
||||
|
||||
// set packet # = 1
|
||||
payload[3] = (SSL_ESTABLISHED == dcb->ssl_state) ? '\x02' : '\x01';
|
||||
payload += 4;
|
||||
|
||||
// set client capabilities
|
||||
memcpy(payload, client_capabilities, 4);
|
||||
|
||||
// set now the max-packet size
|
||||
payload += 4;
|
||||
gw_mysql_set_byte4(payload, 16777216);
|
||||
|
||||
// set the charset
|
||||
payload += 4;
|
||||
*payload = conn->charset;
|
||||
|
||||
payload++;
|
||||
|
||||
// 23 bytes of 0
|
||||
payload += 23;
|
||||
|
||||
if (dcb->server->server_ssl && dcb->ssl_state != SSL_ESTABLISHED)
|
||||
{
|
||||
if (dcb_write(dcb, buffer) && dcb_connect_SSL(dcb) >= 0)
|
||||
{
|
||||
return MXS_AUTH_STATE_CONNECTED;
|
||||
}
|
||||
|
||||
return MXS_AUTH_STATE_FAILED;
|
||||
}
|
||||
|
||||
// 4 + 4 + 4 + 1 + 23 = 36, this includes the 4 bytes packet header
|
||||
memcpy(payload, local_session.user, strlen(local_session.user));
|
||||
payload += strlen(local_session.user);
|
||||
payload++;
|
||||
|
||||
if (curr_passwd != NULL)
|
||||
{
|
||||
payload = load_hashed_password(conn->scramble, payload, curr_passwd);
|
||||
}
|
||||
else
|
||||
{
|
||||
payload++;
|
||||
}
|
||||
|
||||
// if the db is not NULL append it
|
||||
if (local_session.db[0])
|
||||
{
|
||||
memcpy(payload, local_session.db, strlen(local_session.db));
|
||||
payload += strlen(local_session.db);
|
||||
payload++;
|
||||
}
|
||||
|
||||
memcpy(payload, auth_plugin_name, strlen(auth_plugin_name));
|
||||
|
||||
return dcb_write(dcb, buffer) ? MXS_AUTH_STATE_RESPONSE_SENT : MXS_AUTH_STATE_FAILED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode mysql server handshake
|
||||
*
|
||||
* @param conn The MySQLProtocol structure
|
||||
* @param payload The bytes just read from the net
|
||||
* @return 0 on success, < 0 on failure
|
||||
*
|
||||
*/
|
||||
static int
|
||||
gw_decode_mysql_server_handshake(MySQLProtocol *conn, uint8_t *payload)
|
||||
{
|
||||
uint8_t *server_version_end = NULL;
|
||||
uint16_t mysql_server_capabilities_one = 0;
|
||||
uint16_t mysql_server_capabilities_two = 0;
|
||||
unsigned long tid = 0;
|
||||
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 mxs_scramble[GW_MYSQL_SCRAMBLE_SIZE] = "";
|
||||
int protocol_version = 0;
|
||||
|
||||
protocol_version = payload[0];
|
||||
|
||||
if (protocol_version != GW_MYSQL_PROTOCOL_VERSION)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
payload++;
|
||||
|
||||
// Get server version (string)
|
||||
server_version_end = (uint8_t *) gw_strend((char*) payload);
|
||||
|
||||
payload = server_version_end + 1;
|
||||
|
||||
// get ThreadID: 4 bytes
|
||||
tid = gw_mysql_get_byte4(payload);
|
||||
memcpy(&conn->tid, &tid, 4);
|
||||
|
||||
payload += 4;
|
||||
|
||||
// scramble_part 1
|
||||
memcpy(scramble_data_1, payload, GW_SCRAMBLE_LENGTH_323);
|
||||
payload += GW_SCRAMBLE_LENGTH_323;
|
||||
|
||||
// 1 filler
|
||||
payload++;
|
||||
|
||||
mysql_server_capabilities_one = gw_mysql_get_byte2(payload);
|
||||
|
||||
//Get capabilities_part 1 (2 bytes) + 1 language + 2 server_status
|
||||
payload += 5;
|
||||
|
||||
mysql_server_capabilities_two = gw_mysql_get_byte2(payload);
|
||||
|
||||
memcpy(capab_ptr, &mysql_server_capabilities_one, 2);
|
||||
|
||||
// get capabilities part 2 (2 bytes)
|
||||
memcpy(&capab_ptr[2], &mysql_server_capabilities_two, 2);
|
||||
|
||||
// 2 bytes shift
|
||||
payload += 2;
|
||||
|
||||
// get scramble len
|
||||
if (payload[0] > 0)
|
||||
{
|
||||
scramble_len = payload[0] - 1;
|
||||
ss_dassert(scramble_len > GW_SCRAMBLE_LENGTH_323);
|
||||
ss_dassert(scramble_len <= GW_MYSQL_SCRAMBLE_SIZE);
|
||||
|
||||
if ((scramble_len < GW_SCRAMBLE_LENGTH_323) ||
|
||||
scramble_len > GW_MYSQL_SCRAMBLE_SIZE)
|
||||
{
|
||||
/* log this */
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
scramble_len = GW_MYSQL_SCRAMBLE_SIZE;
|
||||
}
|
||||
// skip 10 zero bytes
|
||||
payload += 11;
|
||||
|
||||
// copy the second part of the scramble
|
||||
memcpy(scramble_data_2, payload, scramble_len - GW_SCRAMBLE_LENGTH_323);
|
||||
|
||||
memcpy(mxs_scramble, scramble_data_1, GW_SCRAMBLE_LENGTH_323);
|
||||
memcpy(mxs_scramble + GW_SCRAMBLE_LENGTH_323, scramble_data_2, scramble_len - GW_SCRAMBLE_LENGTH_323);
|
||||
|
||||
// full 20 bytes scramble is ready
|
||||
memcpy(conn->scramble, mxs_scramble, GW_MYSQL_SCRAMBLE_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the backend server MySQL handshake
|
||||
*
|
||||
* @param dcb Backend DCB
|
||||
* @return true on success, false on failure
|
||||
*/
|
||||
bool gw_read_backend_handshake(DCB *dcb, GWBUF *buffer)
|
||||
{
|
||||
MySQLProtocol *proto = (MySQLProtocol *)dcb->protocol;
|
||||
bool rval = false;
|
||||
uint8_t *payload = GWBUF_DATA(buffer) + 4;
|
||||
|
||||
if (gw_decode_mysql_server_handshake(proto, payload) >= 0)
|
||||
{
|
||||
rval = true;
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
add_library(MySQLBackend SHARED mysql_backend.c ../mysql_common.c)
|
||||
target_link_libraries(MySQLBackend maxscale-common MySQLAuth)
|
||||
set_target_properties(MySQLBackend PROPERTIES VERSION "2.0.0")
|
||||
install_module(MySQLBackend core)
|
@ -1,4 +0,0 @@
|
||||
add_library(MySQLClient SHARED mysql_client.c ../mysql_common.c)
|
||||
target_link_libraries(MySQLClient maxscale-common MySQLAuth)
|
||||
set_target_properties(MySQLClient PROPERTIES VERSION "1.0.0")
|
||||
install_module(MySQLClient core)
|
Loading…
x
Reference in New Issue
Block a user