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:
Massimiliano Pinto
2013-07-15 09:03:51 +02:00
parent fa8ea19f85
commit 45c28a033e
8 changed files with 425 additions and 144 deletions

View File

@ -35,13 +35,14 @@ struct service;
* Revision History
*
* Date Who Description
* 01/06/13 Mark Riddoch Initial implementation
* 11/06/13 Mark Riddoch Updated GWPROTOCOL structure with new
* 01/06/2013 Mark Riddoch Initial implementation
* 11/06/2013 Mark Riddoch Updated GWPROTOCOL structure with new
* entry points
* 18/06/13 Mark Riddoch Addition of the listener entry point
* 02/06/2013 Massimiliano Pinto Addition of delayqlock, delayq and authlock
* 18/06/2013 Mark Riddoch Addition of the listener entry point
* 02/07/2013 Massimiliano Pinto Addition of delayqlock, delayq and authlock
* for handling backend asynchronous protocol connection
* and a generic lock for backend authentication
* 12/07/2013 Massimiliano Pinto Added auth and generic func pointers
*
* @endverbatim
*/
@ -79,6 +80,8 @@ typedef struct gw_protocol {
int (*connect)(struct dcb *, struct server *, struct session *);
int (*close)(struct dcb *);
int (*listen)(struct dcb *, char *);
int (*auth)(struct dcb *, struct server *, struct session *, GWBUF *);
int (*generic)(struct dcb *, void *);
} GWPROTOCOL;
/**
@ -162,20 +165,20 @@ typedef struct dcb {
#define DCB_PROTOCOL(x, type) (type *)((x)->protocol)
#define DCB_ISZOMBIE(x) ((x)->state == DCB_STATE_ZOMBIE)
extern DCB *dcb_alloc(); /* Allocate a DCB */
extern void dcb_free(DCB *); /* Free a DCB */
extern DCB *dcb_connect(struct server *, struct session *, const char *);
extern int dcb_read(DCB *, GWBUF **); /* Generic read routine */
extern int dcb_write(DCB *, GWBUF *); /* Generic write routine */
extern int dcb_drain_writeq(DCB *); /* Generic write routine */
extern void dcb_close(DCB *); /* Generic close functionality */
extern void dcb_process_zombies(int); /* Process Zombies */
extern void printAllDCBs(); /* Debug to print all DCB in the system */
extern void printDCB(DCB *); /* Debug print routine */
extern void dprintAllDCBs(DCB *); /* Debug to print all DCB in the system */
extern void dprintDCB(DCB *, DCB *); /* Debug to print a DCB in the system */
extern const char *gw_dcb_state2string(int); /* DCB state to string */
extern DCB *dcb_alloc(); /* Allocate a DCB */
extern void dcb_free(DCB *); /* Free a DCB */
extern DCB *dcb_connect(struct server *, struct session *, const char *); /* prepare Backend connection */
extern int dcb_read(DCB *, GWBUF **); /* Generic read routine */
extern int dcb_write(DCB *, GWBUF *); /* Generic write routine */
extern int dcb_drain_writeq(DCB *); /* Generic write routine */
extern void dcb_close(DCB *); /* Generic close functionality */
extern void dcb_process_zombies(int); /* Process Zombies */
extern void printAllDCBs(); /* Debug to print all DCB in the system */
extern void printDCB(DCB *); /* Debug print routine */
extern void dprintAllDCBs(DCB *); /* Debug to print all DCB in the system */
extern void dprintDCB(DCB *, DCB *); /* Debug to print a DCB in the system */
extern const char *gw_dcb_state2string(int); /* DCB state to string */
extern void dcb_printf(DCB *, const char *, ...); /* DCB version of printf */
extern int dcb_isclient(DCB *);
extern int dcb_isclient(DCB *); /* the DCB is the client of the session */
#endif

View File

@ -27,6 +27,7 @@
* for MySQL session
* 04-07-2013 Massimiliano Pinto Added new MySQL protocol status for asynchronous connection
* Added authentication reply status
* 12-07-2013 Massimiliano Pinto Added routines for change_user
*/
#include <stdio.h>
@ -220,6 +221,9 @@ int gw_send_authentication_to_backend(char *dbname, char *user, uint8_t *passwd,
const char *gw_mysql_protocol_state2string(int state);
int gw_do_connect_to_backend(char *host, int port, MySQLProtocol *conn);
int mysql_send_custom_error (DCB *dcb, int packet_number, int in_affected_rows, const char* mysql_message);
int gw_send_change_user_to_backend(char *dbname, char *user, uint8_t *passwd, MySQLProtocol *conn);
int gw_find_mysql_user_password_sha1(char *username, uint8_t *gateway_password, void *repository);
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);
extern void gw_sha1_str(const uint8_t *in, int in_len, uint8_t *out);
extern void gw_sha1_2_str(const uint8_t *in, int in_len, const uint8_t *in2, int in2_len, uint8_t *out);

View File

@ -66,7 +66,9 @@ static GWPROTOCOL MyObject = {
httpd_accept, /**< Accept */
NULL, /**< Connect */
httpd_close, /**< Close */
httpd_listen /**< Create a listener */
httpd_listen, /**< Create a listener */
NULL, /**< Authentication */
NULL /**< Generic */
};
/**

View File

@ -36,11 +36,12 @@
* 03/07/2013 Massimiliano Pinto Added delayq for incoming data before mysql connection
* 04/07/2013 Massimiliano Pinto Added asyncrhronous MySQL protocol connection to backend
* 05/07/2013 Massimiliano Pinto Added closeSession if backend auth fails
* 12/07/2013 Massimiliano Pinto Addesd Mysql Change User via dcb->func.auth()
*/
static char *version_str = "V2.0.0";
int gw_mysql_connect(char *host, int port, char *dbname, char *user, uint8_t *passwd, MySQLProtocol *conn);
static int gw_create_backend_connection(DCB *client_dcb, SERVER *server, SESSION *in_session);
static int gw_create_backend_connection(DCB *backend, SERVER *server, SESSION *in_session);
static int gw_read_backend_event(DCB* dcb);
static int gw_write_backend_event(DCB *dcb);
static int gw_MySQLWrite_backend(DCB *dcb, GWBUF *queue);
@ -49,6 +50,7 @@ static int gw_backend_close(DCB *dcb);
static int gw_backend_hangup(DCB *dcb);
static int backend_write_delayqueue(DCB *dcb);
static void backend_set_delayqueue(DCB *dcb, GWBUF *queue);
static int gw_change_user(DCB *backend_dcb, SERVER *server, SESSION *in_session, GWBUF *queue);
extern char *gw_strend(register const char *s);
@ -61,7 +63,9 @@ static GWPROTOCOL MyObject = {
NULL, /* Accept */
gw_create_backend_connection, /* Connect */
gw_backend_close, /* Close */
NULL /* Listen */
NULL, /* Listen */
gw_change_user, /* Authentication */
NULL /* Generic */
};
/*
@ -298,8 +302,6 @@ static int gw_create_backend_connection(DCB *backend, SERVER *server, SESSION *s
MYSQL_session *s_data = NULL;
int rv = -1;
//fprintf(stderr, "HERE, the server to connect is [%s]:[%i]\n", server->name, server->port);
protocol = (MySQLProtocol *) calloc(1, sizeof(MySQLProtocol));
protocol->state = MYSQL_ALLOC;
@ -419,4 +421,73 @@ static int backend_write_delayqueue(DCB *dcb)
return dcb_write(dcb, localq);
}
static int gw_change_user(DCB *backend, SERVER *server, SESSION *in_session, GWBUF *queue) {
MYSQL_session *current_session = NULL;
MySQLProtocol *backend_protocol = NULL;
MySQLProtocol *client_protocol = NULL;
char username[MYSQL_USER_MAXLEN+1]="";
char database[MYSQL_DATABASE_MAXLEN+1]="";
uint8_t client_sha1[MYSQL_SCRAMBLE_LEN]="";
uint8_t *client_auth_packet = GWBUF_DATA(queue);
unsigned int auth_token_len = 0;
uint8_t *auth_token = NULL;
int rv = -1;
int len = 0;
int auth_ret = 1;
current_session = (MYSQL_session *)in_session->client->data;
backend_protocol = backend->protocol;
client_protocol = in_session->client->protocol;
// now get the user, after 4 bytes header and 1 byte command
client_auth_packet += 5;
strcpy(username, (char *)client_auth_packet);
fprintf(stderr, "<<< The NEW Client username is [%s]\n", client_auth_packet);
client_auth_packet += strlen(username) + 1;
// get the auth token len
memcpy(&auth_token_len, client_auth_packet, 1);
client_auth_packet++;
fprintf(stderr, "<<< Now decoding the NEW user %i...\n", auth_token_len);
// allocate memory for token only if auth_token_len > 0
if (auth_token_len) {
auth_token = (uint8_t *)malloc(auth_token_len);
memcpy(auth_token, client_auth_packet, auth_token_len);
client_auth_packet += auth_token_len;
}
fprintf(stderr, "<<< Now decoding the NEW token [%s]\n", auth_token);
// decode the token and check the password
// Note: if auth_token_len == 0 && auth_token == NULL, user is without password
auth_ret = gw_check_mysql_scramble_data(backend->session->client, auth_token, auth_token_len, client_protocol->scramble, sizeof(client_protocol->scramble), username, client_sha1);
fprintf(stderr, "<<< HERE after gw_check_mysql_scramble_data()\n");
if (auth_ret != 0) {
fprintf(stderr, "<<< CLIENT AUTH FAILED for user [%s]\n", username);
}
// let's free the auth_token now
if (auth_token)
free(auth_token);
// get db name
strcpy(database, (char *)client_auth_packet);
fprintf(stderr, "<<< The NEW Client selected db is [%s]\n", database);
fprintf(stderr, "<<<< Backend session data is [%s],[%s],[%s]\n", current_session->user, current_session->client_sha1, current_session->db);
fprintf(stderr, "<<<< NEW Backend session data will be is [%s],[%s],[%s]\n", username, client_sha1, database);
rv = gw_send_change_user_to_backend(database, username, client_sha1, backend_protocol);
len = GWBUF_LENGTH(queue);
queue = gwbuf_consume(queue, len);
return rv;
}
/////

View File

@ -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
*

View File

@ -591,3 +591,308 @@ mysql_send_custom_error (DCB *dcb, int packet_number, int in_affected_rows, cons
return sizeof(mysql_packet_header) + mysql_payload_size;
}
/////
/**
* Write a MySQL CHANGE_USER packet to backend server
*
* @param conn MySQL protocol structure
* @param dbname The selected database
* @param user The selected user
* @param passwd The SHA1(real_password): Note real_password is unknown
* @return 0 on success, 1 on failure
*/
int gw_send_change_user_to_backend(char *dbname, char *user, uint8_t *passwd, MySQLProtocol *conn) {
int compress = 0;
int rv;
uint8_t *payload = NULL;
uint8_t *payload_start = NULL;
long bytes;
uint8_t client_scramble[GW_MYSQL_SCRAMBLE_SIZE];
uint8_t client_capabilities[4];
uint32_t server_capabilities;
uint32_t final_capabilities;
char dbpass[129]="";
GWBUF *buffer;
DCB *dcb;
char *curr_db = NULL;
uint8_t *curr_passwd = NULL;
if (strlen(dbname))
curr_db = dbname;
if (strlen((char *)passwd))
curr_passwd = passwd;
dcb = conn->descriptor;
//#ifdef DEBUG_MYSQL_CONN
fprintf(stderr, ">> Sending credentials %s, %s, db %s\n", user, passwd, dbname);
//#endif
// Zero the vars
memset(&server_capabilities, '\0', sizeof(server_capabilities));
memset(&final_capabilities, '\0', sizeof(final_capabilities));
final_capabilities = gw_mysql_get_byte4((uint8_t *)&server_capabilities);
final_capabilities |= GW_MYSQL_CAPABILITIES_PROTOCOL_41;
final_capabilities |= GW_MYSQL_CAPABILITIES_CLIENT;
if (compress) {
final_capabilities |= GW_MYSQL_CAPABILITIES_COMPRESS;
#ifdef DEBUG_MYSQL_CONN
fprintf(stderr, ">>>> Backend Connection with compression\n");
#endif
}
if (curr_passwd != NULL) {
uint8_t hash1[GW_MYSQL_SCRAMBLE_SIZE]="";
uint8_t hash2[GW_MYSQL_SCRAMBLE_SIZE]="";
uint8_t new_sha[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);
// dbpass is the HEX form of SHA1(SHA1(real_password))
gw_bin2hex(dbpass, hash2, GW_MYSQL_SCRAMBLE_SIZE);
// new_sha is the SHA1(CONCAT(scramble, hash2)
gw_sha1_2_str(conn->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);
}
if (curr_db == NULL) {
// without db
final_capabilities &= ~GW_MYSQL_CAPABILITIES_CONNECT_WITH_DB;
} else {
final_capabilities |= GW_MYSQL_CAPABILITIES_CONNECT_WITH_DB;
}
final_capabilities |= GW_MYSQL_CAPABILITIES_PLUGIN_AUTH;
gw_mysql_set_byte4(client_capabilities, final_capabilities);
// Protocol MySQL COM_CHANGE_USER for CLIENT_PROTOCOL_41
// 1 byte COMMAND
bytes = 1;
// add the user
bytes += strlen(user);
// the NULL
bytes++;
// next will be + 1 (scramble_len) + 20 (fixed_scramble) + (dbname + NULL term) + 2 bytes charset
if (curr_passwd != NULL) {
bytes += GW_MYSQL_SCRAMBLE_SIZE;
bytes++;
} else {
bytes++;
}
if (curr_db != NULL) {
bytes += strlen(curr_db);
bytes++;
}
// the charset
bytes += 2;
bytes += strlen("mysql_native_password");
bytes++;
// the packet header
bytes += 4;
// allocating the GWBUF
buffer = gwbuf_alloc(bytes);
payload = GWBUF_DATA(buffer);
// clearing data
memset(payload, '\0', bytes);
// save the start pointer
payload_start = payload;
// set packet # = 1
payload[3] = 0x00;
payload += 4;
// set the command COM_CHANGE_USER \x11
payload[0] = 0x11;
payload++;
memcpy(payload, user, strlen(user));
payload += strlen(user);
payload++;
if (curr_passwd != NULL) {
// 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;
} else {
// skip the auth-length and write a NULL
payload++;
}
// if the db is not NULL append it
if (curr_db != NULL) {
memcpy(payload, curr_db, strlen(curr_db));
payload += strlen(curr_db);
payload++;
}
// set the charset, 2 bytes!!!!
*payload = '\x08';
payload++;
*payload = '\x00';
payload++;
memcpy(payload, "mysql_native_password", strlen("mysql_native_password"));
payload += strlen("mysql_native_password");
payload++;
// put here the paylod size: bytes to write - 4 bytes packet header
gw_mysql_set_byte3(payload_start, (bytes-4));
// write to backend dcb
// ToDO: handle the EAGAIN | EWOULDBLOCK
rv = write(dcb->fd, GWBUF_DATA(buffer), bytes);
gwbuf_consume(buffer, bytes);
conn->state = MYSQL_IDLE;
if (rv < 0)
return rv;
else
return 0;
}
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);
}
/////////////////////////////////////////////////
// get the sha1(sha1(password) from repository
/////////////////////////////////////////////////
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;
}

View File

@ -76,7 +76,9 @@ static GWPROTOCOL MyObject = {
telnetd_accept, /**< Accept */
NULL, /**< Connect */
telnetd_close, /**< Close */
telnetd_listen /**< Create a listener */
telnetd_listen, /**< Create a listener */
NULL, /**< Authentication */
NULL /**< Generic */
};
static void

View File

@ -377,6 +377,8 @@ static int routeQuery(
len += 255*packet[1];
len += 255*255*packet[2];
fprintf(stderr, "\n\n\n>>> Packet type is [%x]\n\n\n", packet_type);
switch(packet_type) {
case COM_INIT_DB: /**< 2 DDL must go to the master */
case COM_REFRESH: /**< 7 - I guess this is session but not sure */
@ -446,10 +448,18 @@ static int routeQuery(
* TODO! Connection to all servers must be established, and
* the command must be executed in them.
*/
if (packet_type != COM_CHANGE_USER)
{
GWBUF *cq = gwbuf_clone(queue);
GWBUF *cq = gwbuf_clone(queue);
fprintf(stderr, "\n\n>>>> SESSION WRITE type [%x]\n\n", packet_type);
ret = session->masterconn->func.write(session->masterconn, queue);
session->slaveconn->func.write(session->slaveconn, cq);
} else {
GWBUF *cq = gwbuf_clone(queue);
fprintf(stderr, "\n\n>>>> COM_CHANGE_USER here\n\n");
session->masterconn->func.auth(session->masterconn, NULL, session->masterconn->session, queue);
session->slaveconn->func.auth(session->slaveconn, NULL, session->masterconn->session, cq);
}
atomic_add(&inst->stats.n_all, 1);
goto return_ret;