Commit 3bba29a3 authored by Venkata Sidagam's avatar Venkata Sidagam

Bug #17357528 BACKPORT BUG#16513435 TO 5.5 AND 5.6

Description: Backporting BUG#16513435 to 5.5 and 5.6
This is a fix for REMOTE PREAUTH USER ENUMERATION FLAW bug
parent 1edfef74
...@@ -6,6 +6,6 @@ exec MYSQL PLUGIN_AUTH_OPT --default_auth=qa_auth_client -h localhost -P MASTER_ ...@@ -6,6 +6,6 @@ exec MYSQL PLUGIN_AUTH_OPT --default_auth=qa_auth_client -h localhost -P MASTER_
current_user() user() @@local.proxy_user @@local.external_user current_user() user() @@local.proxy_user @@local.external_user
qa_test_11_dest@% qa_test_11_user@localhost 'qa_test_11_user'@'%' 'qa_test_11_user'@'%' qa_test_11_dest@% qa_test_11_user@localhost 'qa_test_11_user'@'%' 'qa_test_11_user'@'%'
exec MYSQL PLUGIN_AUTH_OPT --default_auth=qa_auth_client -h localhost -P MASTER_MYPORT -u qa_test_2_user --password=qa_test_11_dest test_user_db -e "SELECT current_user(),user(),@@local.proxy_user,@@local.external_user;" 2>&1 exec MYSQL PLUGIN_AUTH_OPT --default_auth=qa_auth_client -h localhost -P MASTER_MYPORT -u qa_test_2_user --password=qa_test_11_dest test_user_db -e "SELECT current_user(),user(),@@local.proxy_user,@@local.external_user;" 2>&1
ERROR 1045 (28000): Access denied for user 'qa_test_2_user'@'localhost' (using password: NO) ERROR 1045 (28000): Access denied for user 'qa_test_2_user'@'localhost' (using password: YES)
DROP USER qa_test_11_user, qa_test_11_dest; DROP USER qa_test_11_user, qa_test_11_dest;
DROP DATABASE test_user_db; DROP DATABASE test_user_db;
...@@ -222,6 +222,7 @@ class ACL_USER :public ACL_ACCESS ...@@ -222,6 +222,7 @@ class ACL_USER :public ACL_ACCESS
const char *ssl_cipher, *x509_issuer, *x509_subject; const char *ssl_cipher, *x509_issuer, *x509_subject;
LEX_STRING plugin; LEX_STRING plugin;
LEX_STRING auth_string; LEX_STRING auth_string;
bool can_authenticate;
ACL_USER *copy(MEM_ROOT *root) ACL_USER *copy(MEM_ROOT *root)
{ {
...@@ -811,6 +812,16 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables) ...@@ -811,6 +812,16 @@ static my_bool acl_load(THD *thd, TABLE_LIST *tables)
{ {
ACL_USER user; ACL_USER user;
bzero(&user, sizeof(user)); bzero(&user, sizeof(user));
/*
All accounts can authenticate per default. This will change when
we add a new field to the user table.
Currently this flag is only set to false when authentication is attempted
using an unknown user name.
*/
user.can_authenticate= true;
update_hostname(&user.host, get_field(&mem, table->field[0])); update_hostname(&user.host, get_field(&mem, table->field[0]));
user.user= get_field(&mem, table->field[1]); user.user= get_field(&mem, table->field[1]);
if (check_no_resolve && hostname_requires_resolving(user.host.hostname)) if (check_no_resolve && hostname_requires_resolving(user.host.hostname))
...@@ -1465,6 +1476,14 @@ static void acl_insert_user(const char *user, const char *host, ...@@ -1465,6 +1476,14 @@ static void acl_insert_user(const char *user, const char *host,
ACL_USER acl_user; ACL_USER acl_user;
mysql_mutex_assert_owner(&acl_cache->lock); mysql_mutex_assert_owner(&acl_cache->lock);
/*
All accounts can authenticate per default. This will change when
we add a new field to the user table.
Currently this flag is only set to false when authentication is attempted
using an unknown user name.
*/
acl_user.can_authenticate= true;
acl_user.user=*user ? strdup_root(&mem,user) : 0; acl_user.user=*user ? strdup_root(&mem,user) : 0;
update_hostname(&acl_user.host, *host ? strdup_root(&mem, host): 0); update_hostname(&acl_user.host, *host ? strdup_root(&mem, host): 0);
...@@ -8000,6 +8019,10 @@ struct MPVIO_EXT :public MYSQL_PLUGIN_VIO ...@@ -8000,6 +8019,10 @@ struct MPVIO_EXT :public MYSQL_PLUGIN_VIO
char *host; char *host;
Thd_charset_adapter *charset_adapter; Thd_charset_adapter *charset_adapter;
LEX_STRING acl_user_plugin; LEX_STRING acl_user_plugin;
bool can_authenticate()
{
return (acl_user && acl_user->can_authenticate);
}
}; };
/** /**
...@@ -8301,6 +8324,34 @@ static bool send_plugin_request_packet(MPVIO_EXT *mpvio, ...@@ -8301,6 +8324,34 @@ static bool send_plugin_request_packet(MPVIO_EXT *mpvio,
} }
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
/**
When authentication is attempted using an unknown username a dummy user
account with no authentication capabilites is assigned to the connection.
This is done increase the cost of enumerating user accounts based on
authentication protocol.
*/
ACL_USER *decoy_user(const LEX_STRING &username,
MEM_ROOT *mem)
{
ACL_USER *user= (ACL_USER *) alloc_root(mem, sizeof(ACL_USER));
user->can_authenticate= false;
user->user= strmake_root(mem, username.str, username.length);
user->auth_string= empty_lex_str;
user->ssl_cipher= empty_c_string;
user->x509_issuer= empty_c_string;
user->x509_subject= empty_c_string;
user->salt_len= 0;
/*
For now the common default account is used. Improvements might involve
mapping a consistent hash of a username to a range of plugins.
*/
user->plugin= *default_auth_plugin_name;
return user;
}
/** /**
Finds acl entry in user database for authentication purposes. Finds acl entry in user database for authentication purposes.
...@@ -8342,8 +8393,14 @@ static bool find_mpvio_user(MPVIO_EXT *mpvio) ...@@ -8342,8 +8393,14 @@ static bool find_mpvio_user(MPVIO_EXT *mpvio)
if (!mpvio->acl_user) if (!mpvio->acl_user)
{ {
login_failed_error(mpvio, mpvio->auth_info.password_used); /*
DBUG_RETURN (1); Pretend the user exists; let the plugin decide how to handle
bad credentials.
*/
LEX_STRING usr= { mpvio->auth_info.user_name,
mpvio->auth_info.user_name_length };
mpvio->acl_user= decoy_user(usr, mpvio->mem_root);
mpvio->acl_user_plugin= mpvio->acl_user->plugin;
} }
/* user account requires non-default plugin and the client is too old */ /* user account requires non-default plugin and the client is too old */
...@@ -8465,7 +8522,9 @@ static bool parse_com_change_user_packet(MPVIO_EXT *mpvio, uint packet_length) ...@@ -8465,7 +8522,9 @@ static bool parse_com_change_user_packet(MPVIO_EXT *mpvio, uint packet_length)
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
if (find_mpvio_user(mpvio)) if (find_mpvio_user(mpvio))
{
DBUG_RETURN(1); DBUG_RETURN(1);
}
char *client_plugin; char *client_plugin;
if (mpvio->client_capabilities & CLIENT_PLUGIN_AUTH) if (mpvio->client_capabilities & CLIENT_PLUGIN_AUTH)
...@@ -9450,6 +9509,8 @@ acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_len) ...@@ -9450,6 +9509,8 @@ acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_len)
if (parse_com_change_user_packet(&mpvio, com_change_user_pkt_len)) if (parse_com_change_user_packet(&mpvio, com_change_user_pkt_len))
{ {
if (!thd->is_error())
login_failed_error(&mpvio, mpvio.auth_info.password_used);
server_mpvio_update_thd(thd, &mpvio); server_mpvio_update_thd(thd, &mpvio);
DBUG_RETURN(1); DBUG_RETURN(1);
} }
...@@ -9515,6 +9576,11 @@ acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_len) ...@@ -9515,6 +9576,11 @@ acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_len)
mpvio.db.str ? mpvio.db.str : (char*) ""); mpvio.db.str ? mpvio.db.str : (char*) "");
} }
if (res == CR_OK && !mpvio.can_authenticate())
{
res= CR_ERROR;
}
if (res > CR_OK && mpvio.status != MPVIO_EXT::SUCCESS) if (res > CR_OK && mpvio.status != MPVIO_EXT::SUCCESS)
{ {
DBUG_ASSERT(mpvio.status == MPVIO_EXT::FAILURE); DBUG_ASSERT(mpvio.status == MPVIO_EXT::FAILURE);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment