Update for message errors in DB authentication
Update for message errors in DB authentication
This commit is contained in:
@ -731,7 +731,7 @@ getUsers(SERVICE *service, USERS *users)
|
||||
} else {
|
||||
LOGIF(LE, (skygw_log_write_flush(
|
||||
LOGFILE_ERROR,
|
||||
"%lu [mysql_users_add()] Failed adding user %s@%si for service [%s]",
|
||||
"%lu [mysql_users_add()] Failed adding user %s@%s for service [%s]",
|
||||
pthread_self(),
|
||||
row[0],
|
||||
row[1],
|
||||
|
@ -24,6 +24,7 @@
|
||||
*
|
||||
* Date Who Description
|
||||
* 04/06/14 Mark Riddoch Initial implementation
|
||||
* 24/10/14 Massimiliano Pinto Added modutil_send_mysql_err_packet, modutil_create_mysql_err_msg
|
||||
*
|
||||
* @endverbatim
|
||||
*/
|
||||
@ -229,13 +230,14 @@ retblock:
|
||||
}
|
||||
|
||||
|
||||
/* create mysql response packet */
|
||||
|
||||
/**
|
||||
* create mysql response packet */
|
||||
*/
|
||||
GWBUF* modutil_create_mysql_packet(
|
||||
int packet_number,
|
||||
int affected_rows,
|
||||
int merrno,
|
||||
char *statemsg,
|
||||
const char *statemsg,
|
||||
const char * msg)
|
||||
{
|
||||
uint8_t *outbuf = NULL;
|
||||
@ -246,10 +248,9 @@ GWBUF* modutil_create_mysql_packet(
|
||||
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;
|
||||
const char *mysql_error_msg = NULL;
|
||||
const char *mysql_state = NULL;
|
||||
GWBUF *errbuf = NULL;
|
||||
|
||||
mysql_errno = (unsigned int)merrno;
|
||||
mysql_error_msg = msg;
|
||||
@ -270,7 +271,7 @@ GWBUF* modutil_create_mysql_packet(
|
||||
sizeof(mysql_statemsg) +
|
||||
strlen(mysql_error_msg);
|
||||
|
||||
/** allocate memory for packet header + payload */
|
||||
/* allocate memory for packet header + payload */
|
||||
errbuf = gwbuf_alloc(sizeof(mysql_packet_header) + mysql_payload_size);
|
||||
ss_dassert(errbuf != NULL);
|
||||
|
||||
@ -308,27 +309,30 @@ GWBUF* modutil_create_mysql_packet(
|
||||
}
|
||||
|
||||
/**
|
||||
* mysql_send_custom_error
|
||||
* modutil_send_mysql_err_packet
|
||||
*
|
||||
* 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
|
||||
* @param dcb The DCB to send the packet
|
||||
* @param packet_number MySQL protocol sequence number in the packet
|
||||
* @param in_affected_rows MySQL affected rows
|
||||
* @param mysql_errno The MySQL errno
|
||||
* @param sqlstate_msg The MySQL State Message
|
||||
* @param mysql_message The Error Message
|
||||
* @return 0 for successful dcb write or 1 on failure
|
||||
*
|
||||
*/
|
||||
int modutil_send_mysql_packet (
|
||||
int modutil_send_mysql_err_packet (
|
||||
DCB *dcb,
|
||||
int packet_number,
|
||||
int in_affected_rows,
|
||||
int mysql_errno,
|
||||
const char *sqlstate_msg,
|
||||
const char *mysql_message)
|
||||
{
|
||||
GWBUF* buf;
|
||||
|
||||
buf = modutil_create_mysql_packet(packet_number, in_affected_rows, 1049, "42000", mysql_message);
|
||||
buf = modutil_create_mysql_err_msg(packet_number, in_affected_rows, mysql_errno, sqlstate_msg, mysql_message);
|
||||
|
||||
return dcb->func.write(dcb, buf);
|
||||
}
|
||||
|
@ -27,15 +27,18 @@
|
||||
* Date Who Description
|
||||
* 04/06/14 Mark Riddoch Initial implementation
|
||||
* 24/06/14 Mark Riddoch Add modutil_MySQL_Query to enable multipacket queries
|
||||
* 24/10/14 Massimiliano Pinto Add modutil_send_mysql_err_packet to send a mysql ERR_Packet
|
||||
*
|
||||
* @endverbatim
|
||||
*/
|
||||
#include <buffer.h>
|
||||
#include <dcb.h>
|
||||
|
||||
extern int modutil_is_SQL(GWBUF *);
|
||||
extern int modutil_extract_SQL(GWBUF *, char **, int *);
|
||||
extern int modutil_MySQL_Query(GWBUF *, char **, int *, int *);
|
||||
extern GWBUF *modutil_replace_SQL(GWBUF *, char *);
|
||||
char* modutil_get_query(GWBUF* buf);
|
||||
extern char *modutil_get_query(GWBUF* buf);
|
||||
extern int modutil_send_mysql_err_packet(DCB *, int, int, int, const char *, const char *);
|
||||
|
||||
#endif
|
||||
|
@ -20,6 +20,8 @@
|
||||
#include <skygw_types.h>
|
||||
#include <skygw_utils.h>
|
||||
#include <log_manager.h>
|
||||
#include <modutil.h>
|
||||
|
||||
/*
|
||||
* MySQL Protocol module for handling the protocol between the gateway
|
||||
* and the backend MySQL database.
|
||||
@ -41,6 +43,7 @@
|
||||
* 04/09/2013 Massimiliano Pinto Added dcb->session and dcb->session->client checks for NULL
|
||||
* 12/09/2013 Massimiliano Pinto Added checks in gw_read_backend_event() for gw_read_backend_handshake
|
||||
* 27/09/2013 Massimiliano Pinto Changed in gw_read_backend_event the check for dcb_read(), now is if rc < 0
|
||||
* 24/10/2014 Massimiliano Pinto Added Mysql user@host @db authentication support
|
||||
*
|
||||
*/
|
||||
#include <modinfo.h>
|
||||
@ -66,7 +69,8 @@ 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);
|
||||
static GWBUF* process_response_data (DCB* dcb, GWBUF* readbuf, int nbytes_to_process);
|
||||
extern char* create_auth_failed_msg( GWBUF* readbuf, char* hostaddr, uint8_t* sha1, int dbmatch);
|
||||
extern char* create_auth_failed_msg( GWBUF* readbuf, char* hostaddr, uint8_t* sha1);
|
||||
extern char* create_auth_fail_str(char *username, char *hostaddr, char *sha1, char *db);
|
||||
|
||||
|
||||
#if defined(NOT_USED)
|
||||
@ -1172,8 +1176,15 @@ static int backend_write_delayqueue(DCB *dcb)
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This routine handles the COM_CHANGE_USER command
|
||||
*
|
||||
* @param dcb The current backend DCB
|
||||
* @param server The backend server pointer
|
||||
* @param in_session The current session data (MYSQL_session)
|
||||
* @param queue The GWBUF containing the COM_CHANGE_USER receveid
|
||||
* @return 0 on success and 1 on failure
|
||||
*/
|
||||
static int gw_change_user(
|
||||
DCB *backend,
|
||||
SERVER *server,
|
||||
@ -1197,18 +1208,18 @@ static int gw_change_user(
|
||||
backend_protocol = backend->protocol;
|
||||
client_protocol = in_session->client->protocol;
|
||||
|
||||
// now get the user, after 4 bytes header and 1 byte command
|
||||
/* now get the user, after 4 bytes header and 1 byte command */
|
||||
client_auth_packet += 5;
|
||||
strcpy(username, (char *)client_auth_packet);
|
||||
client_auth_packet += strlen(username) + 1;
|
||||
|
||||
// get the auth token len
|
||||
/* get the auth token len */
|
||||
memcpy(&auth_token_len, client_auth_packet, 1);
|
||||
ss_dassert(auth_token_len >= 0);
|
||||
|
||||
client_auth_packet++;
|
||||
|
||||
// allocate memory for token only if auth_token_len > 0
|
||||
/* allocate memory for token only if auth_token_len > 0 */
|
||||
if (auth_token_len > 0) {
|
||||
auth_token = (uint8_t *)malloc(auth_token_len);
|
||||
ss_dassert(auth_token != NULL);
|
||||
@ -1225,11 +1236,16 @@ static int gw_change_user(
|
||||
/* save current_database name */
|
||||
strcpy(current_database, current_session->db);
|
||||
|
||||
/* empty database name in dcb */
|
||||
/*
|
||||
* Now clear database name in dcb as we don't do local authentication on db name for change user.
|
||||
* Local authentication only for user@host and if successful the database name change is sent to backend.
|
||||
*/
|
||||
strcpy(current_session->db, "");
|
||||
|
||||
// decode the token and check the password
|
||||
// Note: if auth_token_len == 0 && auth_token == NULL, user is without password
|
||||
/*
|
||||
* 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);
|
||||
|
||||
if (auth_ret != 0) {
|
||||
@ -1243,30 +1259,34 @@ 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
|
||||
/* let's free the auth_token now */
|
||||
if (auth_token)
|
||||
free(auth_token);
|
||||
|
||||
if (auth_ret != 0) {
|
||||
char *message;
|
||||
char *password_set = NULL;
|
||||
char *message = NULL;
|
||||
|
||||
message = calloc(1,100);
|
||||
strcpy(message, "change user authentication failed");
|
||||
if (auth_token_len > 0)
|
||||
password_set = (char *)client_sha1;
|
||||
else
|
||||
password_set = "";
|
||||
|
||||
message=create_auth_fail_str(username,
|
||||
backend->session->client->remote,
|
||||
password_set,
|
||||
"");
|
||||
/* 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);
|
||||
modutil_send_mysql_err_packet(backend->session->client, 1, 0, 1045, "28000", message);
|
||||
|
||||
free(message);
|
||||
|
||||
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);
|
||||
|
||||
/*<
|
||||
/*
|
||||
* Now copy new data into user session
|
||||
*/
|
||||
strcpy(current_session->user, username);
|
||||
@ -1275,8 +1295,6 @@ static int gw_change_user(
|
||||
}
|
||||
gwbuf_free(queue);
|
||||
|
||||
fprintf(stderr, "--- After change_user curren client dcb DB is [%s]\n", current_session->db);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -70,9 +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* 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 *);
|
||||
extern int check_db_name_after_auth(DCB *, char *, int);
|
||||
extern char* create_auth_fail_str(char *username, char *hostaddr, char *sha1, char *db);
|
||||
|
||||
/*
|
||||
* The "module object" for the mysqld client protocol module.
|
||||
@ -396,7 +396,6 @@ static int gw_mysql_do_authentication(DCB *dcb, GWBUF *queue) {
|
||||
uint8_t *stage1_hash = NULL;
|
||||
int auth_ret = -1;
|
||||
MYSQL_session *client_data = NULL;
|
||||
int db_exists = 0;
|
||||
|
||||
CHK_DCB(dcb);
|
||||
|
||||
@ -508,47 +507,6 @@ static int gw_mysql_do_authentication(DCB *dcb, GWBUF *queue) {
|
||||
return auth_ret;
|
||||
}
|
||||
|
||||
static char* create_auth_fail_str(
|
||||
GWBUF* readbuf,
|
||||
char* hostaddr,
|
||||
char* sha1,
|
||||
char* db)
|
||||
{
|
||||
char* errstr;
|
||||
char* uname;
|
||||
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)
|
||||
{
|
||||
errstr = NULL;
|
||||
goto retblock;
|
||||
}
|
||||
/** -4 comes from 2X'%s' minus terminating char */
|
||||
errstr = (char *)malloc(strlen(uname)+strlen(ferrstr)+strlen(hostaddr)+strlen("YES")-6 + db_len + 1);
|
||||
|
||||
if (errstr != NULL && db_len>0)
|
||||
{
|
||||
sprintf(errstr, ferrstr, uname, hostaddr, (*sha1 == '\0' ? "NO" : "YES"), db);
|
||||
}
|
||||
else
|
||||
sprintf(errstr, ferrstr, uname, hostaddr, (*sha1 == '\0' ? "NO" : "YES"));
|
||||
free(uname);
|
||||
|
||||
retblock:
|
||||
return errstr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write function for client DCB: writes data from MaxScale to Client
|
||||
*
|
||||
@ -700,35 +658,28 @@ int gw_read_client_event(
|
||||
}
|
||||
else
|
||||
{
|
||||
char* fail_str;
|
||||
char* fail_str = NULL;
|
||||
|
||||
protocol->protocol_auth_state = MYSQL_AUTH_FAILED;
|
||||
|
||||
if (auth_val == 2) {
|
||||
char *dberr;
|
||||
dberr= calloc(1, 100);
|
||||
sprintf(dberr, "Unknown database '%s'", (char*)((MYSQL_session *)dcb->data)->db);
|
||||
/** Send error 1049 to client */
|
||||
int message_len = 25 + MYSQL_DATABASE_MAXLEN;
|
||||
|
||||
modutil_send_mysql_packet(
|
||||
//mysql_send_auth_error(
|
||||
dcb,
|
||||
2,
|
||||
0,
|
||||
dberr);
|
||||
fail_str = calloc(1, message_len+1);
|
||||
snprintf(fail_str, message_len, "Unknown database '%s'", (char*)((MYSQL_session *)dcb->data)->db);
|
||||
|
||||
free(dberr);
|
||||
modutil_send_mysql_err_packet(dcb, 2, 0, 1049, "42000", fail_str);
|
||||
} else {
|
||||
/** Send error 1045 to client */
|
||||
fail_str = create_auth_fail_str(read_buffer,
|
||||
fail_str = create_auth_fail_str((char *)((MYSQL_session *)dcb->data)->user,
|
||||
dcb->remote,
|
||||
(char*)((MYSQL_session *)dcb->data)->client_sha1, (char*)((MYSQL_session *)dcb->data)->db);
|
||||
mysql_send_auth_error(
|
||||
dcb,
|
||||
2,
|
||||
0,
|
||||
fail_str);
|
||||
free(fail_str);
|
||||
(char*)((MYSQL_session *)dcb->data)->client_sha1,
|
||||
(char*)((MYSQL_session *)dcb->data)->db);
|
||||
modutil_send_mysql_err_packet(dcb, 2, 0, 1045, "28000", fail_str);
|
||||
}
|
||||
if (fail_str)
|
||||
free(fail_str);
|
||||
|
||||
LOGIF(LD, (skygw_log_write(
|
||||
LOGFILE_DEBUG,
|
||||
|
@ -34,6 +34,7 @@
|
||||
* 29/09/2014 Massimiliano Pinto Added Mysql user@host authentication with wildcard in IPv4 hosts:
|
||||
* x.y.z.%, x.y.%.%, x.%.%.%
|
||||
* 03/10/2014 Massimiliano Pinto Added netmask for wildcard in IPv4 hosts.
|
||||
* 24/10/2014 Massimiliano Pinto Added Mysql user@host @db authentication support
|
||||
*
|
||||
*/
|
||||
|
||||
@ -1986,19 +1987,18 @@ void protocol_set_response_status (
|
||||
char* create_auth_failed_msg(
|
||||
GWBUF* readbuf,
|
||||
char* hostaddr,
|
||||
uint8_t* sha1, int dbmatch)
|
||||
uint8_t* sha1)
|
||||
{
|
||||
char* errstr;
|
||||
char* uname=(char *)GWBUF_DATA(readbuf) + 5;
|
||||
const char* ferrstr = "Access denied for user '%s'@'%s' (using password: %s)";
|
||||
|
||||
/** -4 comes from 2X'%s' minus terminating char */
|
||||
errstr = (char *)malloc(strlen(uname)+strlen(ferrstr)+strlen(hostaddr)+strlen("YES")-6+1 + strlen(" to database ") + strlen("''") + strlen("datbase") +1);
|
||||
errstr = (char *)malloc(strlen(uname)+strlen(ferrstr)+strlen(hostaddr)+strlen("YES")-6 + 1);
|
||||
|
||||
if (errstr != NULL)
|
||||
{
|
||||
sprintf(errstr, ferrstr, uname, hostaddr, (*sha1 == '\0' ? "NO" : "YES"));
|
||||
strcat(errstr, " to database 'database'");
|
||||
}
|
||||
|
||||
return errstr;
|
||||
@ -2007,6 +2007,8 @@ char* create_auth_failed_msg(
|
||||
/**
|
||||
* Read username from MySQL authentication packet.
|
||||
*
|
||||
* Only for client to server packet, COM_CHANGE_USER packet has different format.
|
||||
*
|
||||
* @param ptr address where to write the result or NULL if memory
|
||||
* is allocated here.
|
||||
* @param data Address of MySQL packet.
|
||||
@ -2075,3 +2077,45 @@ int check_db_name_after_auth(DCB *dcb, char *database, int auth_ret) {
|
||||
|
||||
return auth_ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a message error string to send via MySQL ERR packet.
|
||||
*
|
||||
* @param username the MySQL user
|
||||
* @param hostaddr the client IP
|
||||
* @param sha1 authentication scramble data
|
||||
* @param db the MySQL db to connect to
|
||||
*
|
||||
* @return Pointer to the allocated string or NULL on failure
|
||||
*/
|
||||
char *create_auth_fail_str(
|
||||
char *username,
|
||||
char *hostaddr,
|
||||
char *sha1,
|
||||
char *db)
|
||||
{
|
||||
char* errstr;
|
||||
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)";
|
||||
|
||||
errstr = (char *)malloc(strlen(username)+strlen(ferrstr)+strlen(hostaddr)+strlen("YES")-6 + db_len + ((db_len > 0) ? (strlen(" to database ") +2) : 0) + 1);
|
||||
|
||||
if (errstr != NULL) {
|
||||
if (db_len>0)
|
||||
sprintf(errstr, ferrstr, username, hostaddr, (*sha1 == '\0' ? "NO" : "YES"), db);
|
||||
else
|
||||
sprintf(errstr, ferrstr, username, hostaddr, (*sha1 == '\0' ? "NO" : "YES"));
|
||||
}
|
||||
|
||||
return errstr;
|
||||
}
|
||||
|
Reference in New Issue
Block a user