Comments added

This commit is contained in:
Massimiliano Pinto
2013-07-19 10:31:17 +02:00
parent fb68e83888
commit 075f1a2903

View File

@ -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;
} }
///