Reply messages for failed db authentication
Reply messages for failed db authentication
This commit is contained in:
parent
a834b4eeb0
commit
35996a40cb
@ -226,3 +226,109 @@ modutil_get_query(GWBUF *buf)
|
||||
retblock:
|
||||
return query_str;
|
||||
}
|
||||
|
||||
|
||||
/* create mysql response packet */
|
||||
|
||||
GWBUF* modutil_create_mysql_packet(
|
||||
int packet_number,
|
||||
int affected_rows,
|
||||
int merrno,
|
||||
char *statemsg,
|
||||
const char * msg)
|
||||
{
|
||||
uint8_t *outbuf = NULL;
|
||||
uint8_t mysql_payload_size = 0;
|
||||
uint8_t mysql_packet_header[4];
|
||||
uint8_t *mysql_payload = NULL;
|
||||
uint8_t field_count = 0;
|
||||
uint8_t mysql_err[2];
|
||||
uint8_t mysql_statemsg[6];
|
||||
unsigned int mysql_errno = 0;
|
||||
const char* mysql_error_msg = NULL;
|
||||
const char* mysql_state = NULL;
|
||||
|
||||
GWBUF* errbuf = NULL;
|
||||
|
||||
mysql_errno = (unsigned int)merrno;
|
||||
mysql_error_msg = msg;
|
||||
mysql_state = statemsg;
|
||||
|
||||
field_count = 0xff;
|
||||
|
||||
gw_mysql_set_byte2(mysql_err, mysql_errno);
|
||||
|
||||
mysql_statemsg[0]='#';
|
||||
memcpy(mysql_statemsg+1, mysql_state, 5);
|
||||
|
||||
if (msg != NULL) {
|
||||
mysql_error_msg = msg;
|
||||
}
|
||||
mysql_payload_size = sizeof(field_count) +
|
||||
sizeof(mysql_err) +
|
||||
sizeof(mysql_statemsg) +
|
||||
strlen(mysql_error_msg);
|
||||
|
||||
/** allocate memory for packet header + payload */
|
||||
errbuf = gwbuf_alloc(sizeof(mysql_packet_header) + mysql_payload_size);
|
||||
ss_dassert(errbuf != NULL);
|
||||
|
||||
if (errbuf == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
outbuf = GWBUF_DATA(errbuf);
|
||||
|
||||
/** write packet header and packet number */
|
||||
gw_mysql_set_byte3(mysql_packet_header, mysql_payload_size);
|
||||
mysql_packet_header[3] = packet_number;
|
||||
|
||||
/** write header */
|
||||
memcpy(outbuf, mysql_packet_header, sizeof(mysql_packet_header));
|
||||
|
||||
mysql_payload = outbuf + sizeof(mysql_packet_header);
|
||||
|
||||
/** write field */
|
||||
memcpy(mysql_payload, &field_count, sizeof(field_count));
|
||||
mysql_payload = mysql_payload + sizeof(field_count);
|
||||
|
||||
/** write errno */
|
||||
memcpy(mysql_payload, mysql_err, sizeof(mysql_err));
|
||||
mysql_payload = mysql_payload + sizeof(mysql_err);
|
||||
|
||||
/** write sqlstate */
|
||||
memcpy(mysql_payload, mysql_statemsg, sizeof(mysql_statemsg));
|
||||
mysql_payload = mysql_payload + sizeof(mysql_statemsg);
|
||||
|
||||
/** write error message */
|
||||
memcpy(mysql_payload, mysql_error_msg, strlen(mysql_error_msg));
|
||||
|
||||
return errbuf;
|
||||
}
|
||||
|
||||
/**
|
||||
* mysql_send_custom_error
|
||||
*
|
||||
* Send a MySQL protocol Generic ERR message, to the dcb
|
||||
* Note the errno and state are still fixed now
|
||||
*
|
||||
* @param dcb Owner_Dcb Control Block for the connection to which the OK is sent
|
||||
* @param packet_number
|
||||
* @param in_affected_rows
|
||||
* @param mysql_message
|
||||
* @return packet length
|
||||
*
|
||||
*/
|
||||
int modutil_send_mysql_packet (
|
||||
DCB *dcb,
|
||||
int packet_number,
|
||||
int in_affected_rows,
|
||||
const char *mysql_message)
|
||||
{
|
||||
GWBUF* buf;
|
||||
|
||||
buf = modutil_create_mysql_packet(packet_number, in_affected_rows, 1049, "42000", mysql_message);
|
||||
|
||||
return dcb->func.write(dcb, buf);
|
||||
}
|
||||
|
||||
|
@ -1192,7 +1192,6 @@ static int gw_change_user(
|
||||
uint8_t *auth_token = NULL;
|
||||
int rv = -1;
|
||||
int auth_ret = 1;
|
||||
int db_exists = 0;
|
||||
|
||||
current_session = (MYSQL_session *)in_session->client->data;
|
||||
backend_protocol = backend->protocol;
|
||||
@ -1220,13 +1219,14 @@ static int gw_change_user(
|
||||
client_auth_packet += auth_token_len;
|
||||
}
|
||||
|
||||
/* get new database name */
|
||||
strcpy(database, (char *)client_auth_packet);
|
||||
|
||||
/* save current_database name */
|
||||
strcpy(current_database, current_session->db);
|
||||
|
||||
/* get new database name */
|
||||
strcpy(database, (char *)client_auth_packet);
|
||||
/* set it to current dtabase */
|
||||
strcpy(current_session->db, database);
|
||||
/* empty database name in dcb */
|
||||
strcpy(current_session->db, "");
|
||||
|
||||
// decode the token and check the password
|
||||
// Note: if auth_token_len == 0 && auth_token == NULL, user is without password
|
||||
@ -1240,45 +1240,30 @@ static int gw_change_user(
|
||||
}
|
||||
}
|
||||
|
||||
/* copy back current datbase to client session */
|
||||
strcpy(current_session->db, current_database);
|
||||
|
||||
// let's free the auth_token now
|
||||
if (auth_token)
|
||||
free(auth_token);
|
||||
|
||||
if (strlen(database)) {
|
||||
int i = 0;
|
||||
if (backend->session->client->service->resources) {
|
||||
if (hashtable_fetch(backend->session->client->service->resources, database)) {
|
||||
db_exists = 1;
|
||||
}
|
||||
}
|
||||
/*
|
||||
while(backend->session->client->service->resources[i]) {
|
||||
if (strncmp(database, backend->session->client->service->resources[i], MYSQL_DATABASE_MAXLEN) == 0) {
|
||||
db_exists = 1;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
*/
|
||||
if (!db_exists && auth_ret == 0) {
|
||||
auth_ret = 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (auth_ret != 0) {
|
||||
char *message;
|
||||
|
||||
message = calloc(1,100);
|
||||
strcpy(message, "change user authentication failed");
|
||||
|
||||
char *message = create_auth_failed_msg(queue, "ipaddr", client_sha1, auth_ret);
|
||||
/* send the error packet */
|
||||
//modutil_send_mysql_packet(backend->session->client, 1, 0, message);
|
||||
mysql_send_auth_error(backend->session->client, 1, 0, message);
|
||||
fprintf(stderr, "ERROR change user for [%s] to [%s]\n", username, database);
|
||||
|
||||
free(message);
|
||||
|
||||
/* copy back current datbase to client session */
|
||||
strcpy(current_session->db, current_database);
|
||||
|
||||
rv = 1;
|
||||
} else {
|
||||
fprintf(stderr, "going to backend change_user for db [%s]\n", database);
|
||||
|
||||
rv = gw_send_change_user_to_backend(database, username, client_sha1, backend_protocol);
|
||||
|
||||
/*<
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include <gw.h>
|
||||
#include <modinfo.h>
|
||||
#include <sys/stat.h>
|
||||
#include <modutil.h>
|
||||
|
||||
MODULE_INFO info = {
|
||||
MODULE_API_PROTOCOL,
|
||||
@ -69,8 +70,9 @@ int mysql_send_ok(DCB *dcb, int packet_number, int in_affected_rows, const char*
|
||||
int MySQLSendHandshake(DCB* dcb);
|
||||
static int gw_mysql_do_authentication(DCB *dcb, GWBUF *queue);
|
||||
static int route_by_statement(SESSION *, GWBUF **);
|
||||
static char* create_auth_fail_str(GWBUF* readbuf, char* hostaddr, char* sha1);
|
||||
static char* create_auth_fail_str(GWBUF* readbuf, char* hostaddr, char* sha1i, char *db);
|
||||
extern char* get_username_from_auth(char* ptr, uint8_t* data);
|
||||
extern int modutil_send_mysql_packet(DCB *, int, int, const char *);
|
||||
|
||||
/*
|
||||
* The "module object" for the mysqld client protocol module.
|
||||
@ -466,7 +468,8 @@ static int gw_mysql_do_authentication(DCB *dcb, GWBUF *queue) {
|
||||
auth_token_len);
|
||||
}
|
||||
|
||||
/* decode the token and check the password
|
||||
/*
|
||||
* Decode the token and check the password
|
||||
* Note: if auth_token_len == 0 && auth_token == NULL, user is without password
|
||||
*/
|
||||
|
||||
@ -477,29 +480,8 @@ static int gw_mysql_do_authentication(DCB *dcb, GWBUF *queue) {
|
||||
username,
|
||||
stage1_hash);
|
||||
|
||||
|
||||
/* check for dabase name and possible match in resource hashtable */
|
||||
if (database && strlen(database)) {
|
||||
/* if database names are loaded we can check if db name exists */
|
||||
if (dcb->service->resources != NULL) {
|
||||
if (hashtable_fetch(dcb->service->resources, database)) {
|
||||
db_exists = 1;
|
||||
} else {
|
||||
db_exists = 0;
|
||||
}
|
||||
} else {
|
||||
/* if database names are not loaded we don't allow connection with db name*/
|
||||
db_exists = -1;
|
||||
}
|
||||
|
||||
if (db_exists == 0 && auth_ret == 0) {
|
||||
auth_ret = 2;
|
||||
}
|
||||
|
||||
if (db_exists < 0 && auth_ret == 0) {
|
||||
auth_ret = 1;
|
||||
}
|
||||
}
|
||||
/* check for database name match in resource hashtable */
|
||||
auth_ret = check_db_name_after_auth(dcb, database, auth_ret);
|
||||
|
||||
/* On failed auth try to load users' table from backend database */
|
||||
if (auth_ret != 0) {
|
||||
@ -511,29 +493,9 @@ static int gw_mysql_do_authentication(DCB *dcb, GWBUF *queue) {
|
||||
}
|
||||
|
||||
/* Do again the database check */
|
||||
/* check for dabase name and possible match in resource hashtable */
|
||||
if (database && strlen(database)) {
|
||||
/* if database names are loaded we can check if db name exists */
|
||||
if (dcb->service->resources != NULL) {
|
||||
if (hashtable_fetch(dcb->service->resources, database)) {
|
||||
db_exists = 1;
|
||||
} else {
|
||||
db_exists = 0;
|
||||
}
|
||||
} else {
|
||||
/* if database names are not loaded we don't allow connection with db name*/
|
||||
db_exists = -1;
|
||||
}
|
||||
|
||||
if (db_exists == 0 && auth_ret == 0) {
|
||||
auth_ret = 2;
|
||||
}
|
||||
|
||||
if (db_exists < 0 && auth_ret == 0) {
|
||||
auth_ret = 1;
|
||||
}
|
||||
}
|
||||
auth_ret = check_db_name_after_auth(dcb, database, auth_ret);
|
||||
|
||||
/* on succesful auth set user into dcb field */
|
||||
if (auth_ret == 0) {
|
||||
dcb->user = strdup(client_data->user);
|
||||
}
|
||||
@ -549,11 +511,23 @@ static int gw_mysql_do_authentication(DCB *dcb, GWBUF *queue) {
|
||||
static char* create_auth_fail_str(
|
||||
GWBUF* readbuf,
|
||||
char* hostaddr,
|
||||
char* sha1)
|
||||
char* sha1,
|
||||
char* db)
|
||||
{
|
||||
char* errstr;
|
||||
char* uname;
|
||||
const char* ferrstr = "Access denied for user '%s'@'%s' (using password: %s)";
|
||||
const char* ferrstr;
|
||||
int db_len;
|
||||
|
||||
if (db != NULL)
|
||||
db_len = strlen(db);
|
||||
else
|
||||
db_len = 0;
|
||||
|
||||
if (db_len>0)
|
||||
ferrstr = "Access denied for user '%s'@'%s' (using password: %s) to database '%s'";
|
||||
else
|
||||
ferrstr = "Access denied for user '%s'@'%s' (using password: %s)";
|
||||
|
||||
if ( (uname = get_username_from_auth(NULL, (uint8_t *)GWBUF_DATA(readbuf))) == NULL)
|
||||
{
|
||||
@ -561,12 +535,14 @@ static char* create_auth_fail_str(
|
||||
goto retblock;
|
||||
}
|
||||
/** -4 comes from 2X'%s' minus terminating char */
|
||||
errstr = (char *)malloc(strlen(uname)+strlen(ferrstr)+strlen(hostaddr)+strlen("YES")-6+1);
|
||||
errstr = (char *)malloc(strlen(uname)+strlen(ferrstr)+strlen(hostaddr)+strlen("YES")-6 + db_len + 1);
|
||||
|
||||
if (errstr != NULL)
|
||||
if (errstr != NULL && db_len>0)
|
||||
{
|
||||
sprintf(errstr, ferrstr, uname, hostaddr, (*sha1 == '\0' ? "NO" : "YES"));
|
||||
sprintf(errstr, ferrstr, uname, hostaddr, (*sha1 == '\0' ? "NO" : "YES"), db);
|
||||
}
|
||||
else
|
||||
sprintf(errstr, ferrstr, uname, hostaddr, (*sha1 == '\0' ? "NO" : "YES"));
|
||||
free(uname);
|
||||
|
||||
retblock:
|
||||
@ -733,17 +709,19 @@ int gw_read_client_event(
|
||||
dberr= calloc(1, 100);
|
||||
sprintf(dberr, "Unknown database '%s'", (char*)((MYSQL_session *)dcb->data)->db);
|
||||
|
||||
mysql_send_auth_error(
|
||||
modutil_send_mysql_packet(
|
||||
//mysql_send_auth_error(
|
||||
dcb,
|
||||
2,
|
||||
0,
|
||||
dberr);
|
||||
|
||||
free(dberr);
|
||||
} else {
|
||||
/** Send error 1045 to client */
|
||||
fail_str = create_auth_fail_str(read_buffer,
|
||||
dcb->remote,
|
||||
(char*)((MYSQL_session *)dcb->data)->client_sha1);
|
||||
(char*)((MYSQL_session *)dcb->data)->client_sha1, (char*)((MYSQL_session *)dcb->data)->db);
|
||||
mysql_send_auth_error(
|
||||
dcb,
|
||||
2,
|
||||
@ -1640,4 +1618,3 @@ return_str:
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -2046,3 +2046,32 @@ retblock:
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
int check_db_name_after_auth(DCB *dcb, char *database, int auth_ret) {
|
||||
int db_exists = -1;
|
||||
|
||||
/* check for dabase name and possible match in resource hashtable */
|
||||
if (database && strlen(database)) {
|
||||
/* if database names are loaded we can check if db name exists */
|
||||
if (dcb->service->resources != NULL) {
|
||||
if (hashtable_fetch(dcb->service->resources, database)) {
|
||||
db_exists = 1;
|
||||
} else {
|
||||
db_exists = 0;
|
||||
}
|
||||
} else {
|
||||
/* if database names are not loaded we don't allow connection with db name*/
|
||||
db_exists = -1;
|
||||
}
|
||||
|
||||
if (db_exists == 0 && auth_ret == 0) {
|
||||
auth_ret = 2;
|
||||
}
|
||||
|
||||
if (db_exists < 0 && auth_ret == 0) {
|
||||
auth_ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return auth_ret;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user