Merge branch '2.1' into develop
This commit is contained in:
@ -452,6 +452,9 @@ bool gw_read_backend_handshake(DCB *dcb, GWBUF *buffer);
|
|||||||
/** Send the server handshake response packet to the backend server */
|
/** Send the server handshake response packet to the backend server */
|
||||||
mxs_auth_state_t gw_send_backend_auth(DCB *dcb);
|
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);
|
||||||
|
|
||||||
/** 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);
|
||||||
|
|
||||||
|
@ -10,6 +10,6 @@ set(CTEST_PROJECT_NAME "MaxScale")
|
|||||||
set(CTEST_NIGHTLY_START_TIME "01:00:00 UTC")
|
set(CTEST_NIGHTLY_START_TIME "01:00:00 UTC")
|
||||||
|
|
||||||
set(CTEST_DROP_METHOD "http")
|
set(CTEST_DROP_METHOD "http")
|
||||||
set(CTEST_DROP_SITE "jenkins.engskysql.com")
|
set(CTEST_DROP_SITE "maxscale-jenkins.mariadb.com")
|
||||||
set(CTEST_DROP_LOCATION "/CDash/submit.php?project=MaxScale")
|
set(CTEST_DROP_LOCATION "/CDash/submit.php?project=MaxScale")
|
||||||
set(CTEST_DROP_SITE_CDASH TRUE)
|
set(CTEST_DROP_SITE_CDASH TRUE)
|
||||||
|
@ -227,7 +227,7 @@ RSA* create_rsa(int bits)
|
|||||||
BIGNUM* bn = BN_new();
|
BIGNUM* bn = BN_new();
|
||||||
BN_set_word(bn, RSA_F4);
|
BN_set_word(bn, RSA_F4);
|
||||||
RSA* rsa = RSA_new();
|
RSA* rsa = RSA_new();
|
||||||
RSA_generate_key_ex(rsa, bits, NULL, NULL);
|
RSA_generate_key_ex(rsa, bits, bn, NULL);
|
||||||
BN_free(bn);
|
BN_free(bn);
|
||||||
return rsa;
|
return rsa;
|
||||||
#else
|
#else
|
||||||
|
@ -369,7 +369,7 @@ decrypt_password(const char *crypt)
|
|||||||
enlen = strlen(crypt) / 2;
|
enlen = strlen(crypt) / 2;
|
||||||
gw_hex2bin(encrypted, crypt, strlen(crypt));
|
gw_hex2bin(encrypted, crypt, strlen(crypt));
|
||||||
|
|
||||||
if ((plain = (unsigned char *) MXS_MALLOC(80)) == NULL)
|
if ((plain = (unsigned char *) MXS_MALLOC(enlen + 1)) == NULL)
|
||||||
{
|
{
|
||||||
MXS_FREE(keys);
|
MXS_FREE(keys);
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -378,6 +378,7 @@ decrypt_password(const char *crypt)
|
|||||||
AES_set_decrypt_key(keys->enckey, 8 * MAXSCALE_KEYLEN, &aeskey);
|
AES_set_decrypt_key(keys->enckey, 8 * MAXSCALE_KEYLEN, &aeskey);
|
||||||
|
|
||||||
AES_cbc_encrypt(encrypted, plain, enlen, &aeskey, keys->initvector, AES_DECRYPT);
|
AES_cbc_encrypt(encrypted, plain, enlen, &aeskey, keys->initvector, AES_DECRYPT);
|
||||||
|
plain[enlen] = '\0';
|
||||||
MXS_FREE(keys);
|
MXS_FREE(keys);
|
||||||
|
|
||||||
return (char *) plain;
|
return (char *) plain;
|
||||||
|
@ -814,6 +814,43 @@ gw_read_and_write(DCB *dcb)
|
|||||||
MXS_INFO("Response to COM_CHANGE_USER is OK, writing stored query");
|
MXS_INFO("Response to COM_CHANGE_USER is OK, writing stored query");
|
||||||
rval = query ? dcb->func.write(dcb, query) : 1;
|
rval = query ? dcb->func.write(dcb, query) : 1;
|
||||||
}
|
}
|
||||||
|
else if (result == MYSQL_REPLY_AUTHSWITCHREQUEST &&
|
||||||
|
gwbuf_length(reply) > MYSQL_EOF_PACKET_LEN)
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The server requested a change of authentication methods.
|
||||||
|
* If we're changing the authentication method to the same one we
|
||||||
|
* are using now, it means that the server is simply generating
|
||||||
|
* a new scramble for the re-authentication process.
|
||||||
|
*/
|
||||||
|
if (strcmp((char*)GWBUF_DATA(reply) + 5, DEFAULT_MYSQL_AUTH_PLUGIN) == 0)
|
||||||
|
{
|
||||||
|
/** 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);
|
||||||
|
|
||||||
|
/** Store the query until we know the result of the authentication
|
||||||
|
* method switch. */
|
||||||
|
proto->stored_query = query;
|
||||||
|
proto->ignore_replies++;
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/** The server requested a change to something other than
|
||||||
|
* the default auth plugin */
|
||||||
|
gwbuf_free(query);
|
||||||
|
poll_fake_hangup_event(dcb);
|
||||||
|
|
||||||
|
// TODO: Use the authenticators to handle COM_CHANGE_USER responses
|
||||||
|
MXS_ERROR("Received AuthSwitchRequest to '%s' when '%s' was expected",
|
||||||
|
(char*)GWBUF_DATA(reply) + 5, DEFAULT_MYSQL_AUTH_PLUGIN);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
@ -827,21 +864,11 @@ gw_read_and_write(DCB *dcb)
|
|||||||
* close the DCB and send an error to the client. */
|
* close the DCB and send an error to the client. */
|
||||||
log_error_response(dcb, reply);
|
log_error_response(dcb, reply);
|
||||||
}
|
}
|
||||||
else if (result == MYSQL_REPLY_AUTHSWITCHREQUEST &&
|
|
||||||
gwbuf_length(reply) > MYSQL_EOF_PACKET_LEN)
|
|
||||||
{
|
|
||||||
MXS_ERROR("Received AuthSwitchRequest to '%s' when '%s' was expected",
|
|
||||||
(char*)GWBUF_DATA(reply) + 5, DEFAULT_MYSQL_AUTH_PLUGIN);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/** This should never happen */
|
/** This should never happen */
|
||||||
MXS_ERROR("Unknown response to COM_CHANGE_USER (0x%02hhx), "
|
MXS_ERROR("Unknown response to COM_CHANGE_USER (0x%02hhx), "
|
||||||
"ignoring and waiting for correct result", result);
|
"closing connection", result);
|
||||||
gwbuf_free(reply);
|
|
||||||
proto->stored_query = query;
|
|
||||||
proto->ignore_replies++;
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gwbuf_free(query);
|
gwbuf_free(query);
|
||||||
|
@ -1164,19 +1164,19 @@ static int response_length(bool with_ssl, bool ssl_established, char *user, uint
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Helper function to load hashed password
|
* Calculates the a hash from a scramble and a password
|
||||||
* @param conn DCB Protocol object
|
*
|
||||||
* @param payload Destination where hashed password is written
|
* The algorithm used is: `SHA1(scramble + SHA1(SHA1(password))) ^ SHA1(password)`
|
||||||
* @param passwd Client's double SHA1 password
|
*
|
||||||
* @return Address of the next byte after the end of the stored password
|
* @param scramble The 20 byte scramble sent by the server
|
||||||
|
* @param passwd The SHA1(password) sent by the client
|
||||||
|
* @param output Pointer where the resulting 20 byte hash is stored
|
||||||
*/
|
*/
|
||||||
static uint8_t *
|
static void calculate_hash(uint8_t *scramble, uint8_t *passwd, uint8_t *output)
|
||||||
load_hashed_password(uint8_t *scramble, uint8_t *payload, uint8_t *passwd)
|
|
||||||
{
|
{
|
||||||
uint8_t hash1[GW_MYSQL_SCRAMBLE_SIZE] = "";
|
uint8_t hash1[GW_MYSQL_SCRAMBLE_SIZE] = "";
|
||||||
uint8_t hash2[GW_MYSQL_SCRAMBLE_SIZE] = "";
|
uint8_t hash2[GW_MYSQL_SCRAMBLE_SIZE] = "";
|
||||||
uint8_t new_sha[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)
|
// hash1 is the function input, SHA1(real_password)
|
||||||
memcpy(hash1, passwd, GW_MYSQL_SCRAMBLE_SIZE);
|
memcpy(hash1, passwd, GW_MYSQL_SCRAMBLE_SIZE);
|
||||||
@ -1188,17 +1188,24 @@ load_hashed_password(uint8_t *scramble, uint8_t *payload, uint8_t *passwd)
|
|||||||
gw_sha1_2_str(scramble, GW_MYSQL_SCRAMBLE_SIZE, hash2, GW_MYSQL_SCRAMBLE_SIZE, new_sha);
|
gw_sha1_2_str(scramble, GW_MYSQL_SCRAMBLE_SIZE, hash2, GW_MYSQL_SCRAMBLE_SIZE, new_sha);
|
||||||
|
|
||||||
// compute the xor in client_scramble
|
// compute the xor in client_scramble
|
||||||
gw_str_xor(client_scramble, new_sha, hash1, GW_MYSQL_SCRAMBLE_SIZE);
|
gw_str_xor(output, new_sha, hash1, GW_MYSQL_SCRAMBLE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
// set the auth-length
|
/**
|
||||||
*payload = GW_MYSQL_SCRAMBLE_SIZE;
|
* @brief Helper function to load hashed password
|
||||||
payload++;
|
*
|
||||||
|
* @param conn DCB Protocol object
|
||||||
//copy the 20 bytes scramble data after packet_buffer + 36 + user + NULL + 1 (byte of auth-length)
|
* @param payload Destination where hashed password is written
|
||||||
memcpy(payload, client_scramble, GW_MYSQL_SCRAMBLE_SIZE);
|
* @param passwd Client's double SHA1 password
|
||||||
|
*
|
||||||
payload += GW_MYSQL_SCRAMBLE_SIZE;
|
* @return Address of the next byte after the end of the stored password
|
||||||
return payload;
|
*/
|
||||||
|
static uint8_t *
|
||||||
|
load_hashed_password(uint8_t *scramble, uint8_t *payload, uint8_t *passwd)
|
||||||
|
{
|
||||||
|
*payload++ = GW_MYSQL_SCRAMBLE_SIZE;
|
||||||
|
calculate_hash(scramble, passwd, payload);
|
||||||
|
return payload + GW_MYSQL_SCRAMBLE_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1389,6 +1396,32 @@ mxs_auth_state_t gw_send_backend_auth(DCB *dcb)
|
|||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int send_mysql_native_password_response(DCB* dcb)
|
||||||
|
{
|
||||||
|
MySQLProtocol* proto = (MySQLProtocol*) dcb->protocol;
|
||||||
|
MYSQL_session local_session;
|
||||||
|
gw_get_shared_session_auth_info(dcb, &local_session);
|
||||||
|
|
||||||
|
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
|
||||||
|
calculate_hash(proto->scramble, curr_passwd, data + MYSQL_HEADER_LEN);
|
||||||
|
|
||||||
|
return dcb_write(dcb, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
*/
|
||||||
int gw_decode_mysql_server_handshake(MySQLProtocol *conn, uint8_t *payload)
|
int gw_decode_mysql_server_handshake(MySQLProtocol *conn, uint8_t *payload)
|
||||||
{
|
{
|
||||||
uint8_t *server_version_end = NULL;
|
uint8_t *server_version_end = NULL;
|
||||||
|
Reference in New Issue
Block a user