Added support form COM_CHANGE_USER in readwritesplit.c
Added func.auth() and func.generic() in dcb.h Some mysql routines moved into mysql_common.c New session user still not saved in the dcb->data
This commit is contained in:
@ -42,8 +42,6 @@ static int gw_error_client_event(DCB *dcb);
|
||||
static int gw_client_close(DCB *dcb);
|
||||
static int gw_client_hangup_event(DCB *dcb);
|
||||
|
||||
static 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);
|
||||
static int gw_find_mysql_user_password_sha1(char *username, uint8_t *gateway_password, void *repository);
|
||||
int mysql_send_ok(DCB *dcb, int packet_number, int in_affected_rows, const char* mysql_message);
|
||||
int mysql_send_auth_error (DCB *dcb, int packet_number, int in_affected_rows, const char* mysql_message);
|
||||
int MySQLSendHandshake(DCB* dcb);
|
||||
@ -61,7 +59,9 @@ static GWPROTOCOL MyObject = {
|
||||
gw_MySQLAccept, /* Accept */
|
||||
NULL, /* Connect */
|
||||
gw_client_close, /* Close */
|
||||
gw_MySQLListener /* Listen */
|
||||
gw_MySQLListener, /* Listen */
|
||||
NULL, /* Authentication */
|
||||
NULL /* Generic */
|
||||
};
|
||||
|
||||
/**
|
||||
@ -482,122 +482,6 @@ static int gw_mysql_do_authentication(DCB *dcb, GWBUF *queue) {
|
||||
return auth_ret;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
// get the sha1(sha1(password) from repository
|
||||
/////////////////////////////////////////////////
|
||||
static int gw_find_mysql_user_password_sha1(char *username, uint8_t *gateway_password, void *repository) {
|
||||
SERVICE *service = NULL;
|
||||
char *user_password = NULL;
|
||||
|
||||
if (strcmp(username , "root") == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
service = (SERVICE *) ((DCB *)repository)->service;
|
||||
|
||||
user_password = (char *)users_fetch(service->users, username);
|
||||
|
||||
if (!user_password) {
|
||||
fprintf(stderr, ">>> MYSQL user NOT FOUND: %s\n", username);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// convert hex data (40 bytes) to binary (20 bytes)
|
||||
// gateway_password represents the SHA1(SHA1(real_password))
|
||||
// please not real_password is unknown and SHA1(real_password)
|
||||
// is unknown as well
|
||||
|
||||
if (strlen(user_password))
|
||||
gw_hex2bin(gateway_password, user_password, SHA_DIGEST_LENGTH * 2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static 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 step2[GW_MYSQL_SCRAMBLE_SIZE +1]="";
|
||||
uint8_t check_hash[GW_MYSQL_SCRAMBLE_SIZE]="";
|
||||
char hex_double_sha1[2 * GW_MYSQL_SCRAMBLE_SIZE + 1]="";
|
||||
uint8_t password[GW_MYSQL_SCRAMBLE_SIZE]="";
|
||||
int ret_val = 1;
|
||||
|
||||
if ((username == NULL) || (scramble == NULL) || (stage1_hash == NULL)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
if (ret_val) {
|
||||
fprintf(stderr, "<<<< User [%s] was not found\n", username);
|
||||
return 1;
|
||||
}
|
||||
|
||||
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
|
||||
gw_bin2hex(hex_double_sha1, password, SHA_DIGEST_LENGTH);
|
||||
} else {
|
||||
// check if the password is not set in the user table
|
||||
if (!strlen((char *)password)) {
|
||||
fprintf(stderr, ">>> continue WITHOUT auth, no password\n");
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
// 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
|
||||
////////////
|
||||
gw_sha1_2_str(scramble, scramble_len, password, SHA_DIGEST_LENGTH, step1);
|
||||
|
||||
////////////
|
||||
// step2: STEP2 = XOR(token, STEP1)
|
||||
////////////
|
||||
// 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
|
||||
// the result STEP2 is SHA1(the_password_to_check) and is SHA_DIGEST_LENGTH long
|
||||
|
||||
gw_str_xor(step2, token, step1, token_len);
|
||||
|
||||
// copy the stage1_hash back to the caller
|
||||
// stage1_hash will be used for backend authentication
|
||||
|
||||
memcpy(stage1_hash, step2, SHA_DIGEST_LENGTH);
|
||||
|
||||
///////////
|
||||
// step 3: prepare the check_hash
|
||||
///////////
|
||||
// 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);
|
||||
|
||||
|
||||
#ifdef GW_DEBUG_CLIENT_AUTH
|
||||
{
|
||||
char inpass[128]="";
|
||||
gw_bin2hex(inpass, check_hash, SHA_DIGEST_LENGTH);
|
||||
|
||||
fprintf(stderr, "The CLIENT hex(SHA1(SHA1(password))) for \"%s\" is [%s]", username, inpass);
|
||||
}
|
||||
#endif
|
||||
|
||||
// now compare SHA1(SHA1(gateway_password)) and check_hash: return 0 is MYSQL_AUTH_OK
|
||||
return memcmp(password, check_hash, SHA_DIGEST_LENGTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write function for client DCB: writes data from Gateway to Client
|
||||
*
|
||||
|
Reference in New Issue
Block a user