Comments added
This commit is contained in:
@ -32,9 +32,16 @@ extern int gw_write_backend_event(DCB *dcb);
|
|||||||
extern int gw_MySQLWrite_backend(DCB *dcb, GWBUF *queue);
|
extern int gw_MySQLWrite_backend(DCB *dcb, GWBUF *queue);
|
||||||
extern int gw_error_backend_event(DCB *dcb);
|
extern int gw_error_backend_event(DCB *dcb);
|
||||||
|
|
||||||
///////////////////////////////
|
/**
|
||||||
// Initialize mysql protocol struct
|
* gw_mysql_init
|
||||||
///////////////////////////////////////
|
*
|
||||||
|
* Initialize mysql protocol struct
|
||||||
|
*
|
||||||
|
* @param data The MySQLProtocol pointer, usually NULL
|
||||||
|
* @return The new MySQLProtocol allocated
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
MySQLProtocol *gw_mysql_init(MySQLProtocol *data) {
|
MySQLProtocol *gw_mysql_init(MySQLProtocol *data) {
|
||||||
MySQLProtocol *input = NULL;
|
MySQLProtocol *input = NULL;
|
||||||
|
|
||||||
@ -55,10 +62,15 @@ MySQLProtocol *gw_mysql_init(MySQLProtocol *data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////
|
/**
|
||||||
// close a connection if opened
|
* gw_mysql_close
|
||||||
// free data scructure for MySQLProtocol
|
*
|
||||||
//////////////////////////////////////
|
* close a connection if opened
|
||||||
|
* free data scructure for MySQLProtocol
|
||||||
|
*
|
||||||
|
* @param ptr The MySQLProtocol ** to close/free
|
||||||
|
*
|
||||||
|
*/
|
||||||
void gw_mysql_close(MySQLProtocol **ptr) {
|
void gw_mysql_close(MySQLProtocol **ptr) {
|
||||||
MySQLProtocol *conn = *ptr;
|
MySQLProtocol *conn = *ptr;
|
||||||
|
|
||||||
@ -70,7 +82,7 @@ void gw_mysql_close(MySQLProtocol **ptr) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (conn->fd > 0) {
|
if (conn->fd > 0) {
|
||||||
//COM_QUIT will not be sent here, but from the caller of this routine!
|
/* COM_QUIT will not be sent here, but from the caller of this routine! */
|
||||||
#ifdef MYSQL_CONN_DEBUG
|
#ifdef MYSQL_CONN_DEBUG
|
||||||
fprintf(stderr, "mysqlgw_mysql_close() called for %i\n", conn->fd);
|
fprintf(stderr, "mysqlgw_mysql_close() called for %i\n", conn->fd);
|
||||||
#endif
|
#endif
|
||||||
@ -131,7 +143,14 @@ int gw_read_backend_handshake(MySQLProtocol *conn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* gw_decode_mysql_server_handshake
|
||||||
|
*
|
||||||
* Decode mysql server handshake
|
* Decode mysql server handshake
|
||||||
|
*
|
||||||
|
* @param conn The MySQLProtocol structure
|
||||||
|
* @param payload The bytes just read from the net
|
||||||
|
* @return 0 always
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
int gw_decode_mysql_server_handshake(MySQLProtocol *conn, uint8_t *payload) {
|
int gw_decode_mysql_server_handshake(MySQLProtocol *conn, uint8_t *payload) {
|
||||||
int server_protocol;
|
int server_protocol;
|
||||||
@ -436,8 +455,17 @@ int gw_send_authentication_to_backend(char *dbname, char *user, uint8_t *passwd,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Only backend connect syscall
|
* gw_do_connect_to_backend
|
||||||
|
*
|
||||||
|
* This routine connects to a backend server using connect() in NON_BLOCKING mode
|
||||||
|
*
|
||||||
|
* @param host The host to connect to
|
||||||
|
* @param port The host TCP/IP port
|
||||||
|
* @param conn The MySQLProtocol structure to fill
|
||||||
|
* @return 0 on success and !=0 on failure
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int gw_do_connect_to_backend(char *host, int port, MySQLProtocol *conn) {
|
int gw_do_connect_to_backend(char *host, int port, MySQLProtocol *conn) {
|
||||||
struct sockaddr_in serv_addr;
|
struct sockaddr_in serv_addr;
|
||||||
int rv;
|
int rv;
|
||||||
@ -594,7 +622,7 @@ mysql_send_custom_error (DCB *dcb, int packet_number, int in_affected_rows, cons
|
|||||||
|
|
||||||
return sizeof(mysql_packet_header) + mysql_payload_size;
|
return sizeof(mysql_packet_header) + mysql_payload_size;
|
||||||
}
|
}
|
||||||
/////
|
|
||||||
/**
|
/**
|
||||||
* Write a MySQL CHANGE_USER packet to backend server
|
* Write a MySQL CHANGE_USER packet to backend server
|
||||||
*
|
*
|
||||||
@ -780,8 +808,19 @@ int gw_send_change_user_to_backend(char *dbname, char *user, uint8_t *passwd, My
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* gw_check_mysql_scramble_data
|
||||||
|
*
|
||||||
* Check authentication token received against stage1_hash and scramble
|
* Check authentication token received against stage1_hash and scramble
|
||||||
*
|
*
|
||||||
|
* @param dcb The current dcb
|
||||||
|
* @param token The token sent by the client in the authentication request
|
||||||
|
* @param token_len The token size in bytes
|
||||||
|
* @param scramble The scramble data sent by the server during handshake
|
||||||
|
* @param scramble_len The scrable size in bytes
|
||||||
|
* @param username The current username in the authentication request
|
||||||
|
* @param stage1_hash The SHA1(candidate_password) decoded by this routine
|
||||||
|
* @return 0 on succesful check or != 0 on failure
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
int gw_check_mysql_scramble_data(DCB *dcb, uint8_t *token, unsigned int token_len, uint8_t *scramble, unsigned int scramble_len, char *username, uint8_t *stage1_hash) {
|
int gw_check_mysql_scramble_data(DCB *dcb, uint8_t *token, unsigned int token_len, uint8_t *scramble, unsigned int scramble_len, char *username, uint8_t *stage1_hash) {
|
||||||
uint8_t step1[GW_MYSQL_SCRAMBLE_SIZE]="";
|
uint8_t step1[GW_MYSQL_SCRAMBLE_SIZE]="";
|
||||||
@ -795,8 +834,11 @@ int gw_check_mysql_scramble_data(DCB *dcb, uint8_t *token, unsigned int token_le
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the user's password from repository in SHA1(SHA1(real_password));
|
/**
|
||||||
// please note 'real_password' is unknown!
|
* get the user's password from repository in SHA1(SHA1(real_password));
|
||||||
|
* please note 'real_password' is unknown!
|
||||||
|
*/
|
||||||
|
|
||||||
ret_val = gw_find_mysql_user_password_sha1(username, password, (DCB *) dcb);
|
ret_val = gw_find_mysql_user_password_sha1(username, password, (DCB *) dcb);
|
||||||
|
|
||||||
if (ret_val) {
|
if (ret_val) {
|
||||||
@ -805,52 +847,60 @@ int gw_check_mysql_scramble_data(DCB *dcb, uint8_t *token, unsigned int token_le
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (token && token_len) {
|
if (token && token_len) {
|
||||||
// convert in hex format: this is the content of mysql.user table, field password without the '*' prefix
|
/**
|
||||||
// and it is 40 bytes long
|
* convert in hex format: this is the content of mysql.user table.
|
||||||
|
* The field password is without the '*' prefix and it is 40 bytes long
|
||||||
|
*/
|
||||||
|
|
||||||
gw_bin2hex(hex_double_sha1, password, SHA_DIGEST_LENGTH);
|
gw_bin2hex(hex_double_sha1, password, SHA_DIGEST_LENGTH);
|
||||||
} else {
|
} else {
|
||||||
// check if the password is not set in the user table
|
/* check if the password is not set in the user table */
|
||||||
if (!strlen((char *)password)) {
|
if (!strlen((char *)password)) {
|
||||||
fprintf(stderr, ">>> continue WITHOUT auth, no password\n");
|
/* Username without password */
|
||||||
|
//fprintf(stderr, ">>> continue WITHOUT auth, no password\n");
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////
|
/**
|
||||||
// Auth check in 3 steps
|
* Auth check in 3 steps
|
||||||
//////////////////////////
|
*
|
||||||
|
* Note: token = XOR (SHA1(real_password), SHA1(CONCAT(scramble, SHA1(SHA1(real_password)))))
|
||||||
|
* the client sends token
|
||||||
|
*
|
||||||
|
* Now, server side:
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* step 1: compute the STEP1 = SHA1(CONCAT(scramble, gateway_password))
|
||||||
|
* the result in step1 is SHA_DIGEST_LENGTH long
|
||||||
|
*/
|
||||||
|
|
||||||
// Note: token = XOR (SHA1(real_password), SHA1(CONCAT(scramble, SHA1(SHA1(real_password)))))
|
|
||||||
// the client sends token
|
|
||||||
//
|
|
||||||
// Now, server side:
|
|
||||||
//
|
|
||||||
/////////////
|
|
||||||
// step 1: compute the STEP1 = SHA1(CONCAT(scramble, gateway_password))
|
|
||||||
// the result in step1 is SHA_DIGEST_LENGTH long
|
|
||||||
////////////
|
|
||||||
gw_sha1_2_str(scramble, scramble_len, password, SHA_DIGEST_LENGTH, step1);
|
gw_sha1_2_str(scramble, scramble_len, password, SHA_DIGEST_LENGTH, step1);
|
||||||
|
|
||||||
////////////
|
/**
|
||||||
// step2: STEP2 = XOR(token, STEP1)
|
* step2: STEP2 = XOR(token, STEP1)
|
||||||
////////////
|
*
|
||||||
// token is trasmitted form client and it's based on the handshake scramble and SHA1(real_passowrd)
|
* token is trasmitted form client and it's based on the handshake scramble and SHA1(real_passowrd)
|
||||||
// step1 has been computed in the previous step
|
* step1 has been computed in the previous step
|
||||||
// the result STEP2 is SHA1(the_password_to_check) and is SHA_DIGEST_LENGTH long
|
* the result STEP2 is SHA1(the_password_to_check) and is SHA_DIGEST_LENGTH long
|
||||||
|
*/
|
||||||
|
|
||||||
gw_str_xor(step2, token, step1, token_len);
|
gw_str_xor(step2, token, step1, token_len);
|
||||||
|
|
||||||
// copy the stage1_hash back to the caller
|
/**
|
||||||
// stage1_hash will be used for backend authentication
|
* copy the stage1_hash back to the caller
|
||||||
|
* stage1_hash will be used for backend authentication
|
||||||
|
*/
|
||||||
|
|
||||||
memcpy(stage1_hash, step2, SHA_DIGEST_LENGTH);
|
memcpy(stage1_hash, step2, SHA_DIGEST_LENGTH);
|
||||||
|
|
||||||
///////////
|
/**
|
||||||
// step 3: prepare the check_hash
|
* step 3: prepare the check_hash
|
||||||
///////////
|
*
|
||||||
// compute the SHA1(STEP2) that is SHA1(SHA1(the_password_to_check)), and is SHA_DIGEST_LENGTH long
|
* compute the SHA1(STEP2) that is SHA1(SHA1(the_password_to_check)), and is SHA_DIGEST_LENGTH long
|
||||||
|
*/
|
||||||
|
|
||||||
gw_sha1_str(step2, SHA_DIGEST_LENGTH, check_hash);
|
gw_sha1_str(step2, SHA_DIGEST_LENGTH, check_hash);
|
||||||
|
|
||||||
@ -864,13 +914,24 @@ int gw_check_mysql_scramble_data(DCB *dcb, uint8_t *token, unsigned int token_le
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// now compare SHA1(SHA1(gateway_password)) and check_hash: return 0 is MYSQL_AUTH_OK
|
/* now compare SHA1(SHA1(gateway_password)) and check_hash: return 0 is MYSQL_AUTH_OK */
|
||||||
return memcmp(password, check_hash, SHA_DIGEST_LENGTH);
|
return memcmp(password, check_hash, SHA_DIGEST_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////
|
/**
|
||||||
// get the sha1(sha1(password) from repository
|
* gw_find_mysql_user_password_sha1
|
||||||
/////////////////////////////////////////////////
|
*
|
||||||
|
* The routine fetches look for an user int he Gateway users' tableg
|
||||||
|
* If found the HEX passwotd, representing sha1(sha1(password)), is converted in binary data and
|
||||||
|
* copied into gateway_password
|
||||||
|
*
|
||||||
|
* @param username The user to look for
|
||||||
|
* @param gateway_password The related SHA1(SHA1(password)), the pointer must be preallocated
|
||||||
|
* @param repository The pointer to users' table data, passed as void *
|
||||||
|
* @return 1 if user is not found or 0 if the user exists
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
int gw_find_mysql_user_password_sha1(char *username, uint8_t *gateway_password, void *repository) {
|
int gw_find_mysql_user_password_sha1(char *username, uint8_t *gateway_password, void *repository) {
|
||||||
SERVICE *service = NULL;
|
SERVICE *service = NULL;
|
||||||
char *user_password = NULL;
|
char *user_password = NULL;
|
||||||
@ -884,14 +945,14 @@ int gw_find_mysql_user_password_sha1(char *username, uint8_t *gateway_password,
|
|||||||
user_password = (char *)users_fetch(service->users, username);
|
user_password = (char *)users_fetch(service->users, username);
|
||||||
|
|
||||||
if (!user_password) {
|
if (!user_password) {
|
||||||
//fprintf(stderr, ">>> MYSQL user NOT FOUND: %s\n", username);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert hex data (40 bytes) to binary (20 bytes)
|
/**
|
||||||
// gateway_password represents the SHA1(SHA1(real_password))
|
* Convert now the hex data (40 bytes) to binary (20 bytes).
|
||||||
// please not real_password is unknown and SHA1(real_password)
|
* The gateway_password represents the SHA1(SHA1(real_password)).
|
||||||
// is unknown as well
|
* Please not real_password is unknown and SHA1(real_password) is unknown as well
|
||||||
|
*/
|
||||||
|
|
||||||
if (strlen(user_password))
|
if (strlen(user_password))
|
||||||
gw_hex2bin(gateway_password, user_password, SHA_DIGEST_LENGTH * 2);
|
gw_hex2bin(gateway_password, user_password, SHA_DIGEST_LENGTH * 2);
|
||||||
@ -977,3 +1038,4 @@ mysql_send_auth_error (DCB *dcb, int packet_number, int in_affected_rows, const
|
|||||||
|
|
||||||
return sizeof(mysql_packet_header) + mysql_payload_size;
|
return sizeof(mysql_packet_header) + mysql_payload_size;
|
||||||
}
|
}
|
||||||
|
///
|
||||||
|
|||||||
Reference in New Issue
Block a user