Commit bfc71e63 authored by Sergei Golubchik's avatar Sergei Golubchik

MDEV-3915 COM_CHANGE_USER allows fast password brute-forcing

  
allow only three failed change_user per connection.
successful change_user do NOT reset the counter

tests/mysql_client_test.c:
  make --error to work for --change_user errors
parent 8127e631
...@@ -3908,7 +3908,10 @@ void do_change_user(struct st_command *command) ...@@ -3908,7 +3908,10 @@ void do_change_user(struct st_command *command)
cur_con->name, ds_user.str, ds_passwd.str, ds_db.str)); cur_con->name, ds_user.str, ds_passwd.str, ds_db.str));
if (mysql_change_user(mysql, ds_user.str, ds_passwd.str, ds_db.str)) if (mysql_change_user(mysql, ds_user.str, ds_passwd.str, ds_db.str))
die("change user failed: %s", mysql_error(mysql)); handle_error(command, mysql_errno(mysql), mysql_error(mysql),
mysql_sqlstate(mysql), &ds_res);
else
handle_no_error(command);
dynstr_free(&ds_user); dynstr_free(&ds_user);
dynstr_free(&ds_passwd); dynstr_free(&ds_passwd);
......
ERROR 28000: Access denied for user 'foo'@'localhost' (using password: NO)
ERROR 28000: Access denied for user 'foo'@'localhost' (using password: NO)
ERROR 28000: Access denied for user 'foo'@'localhost' (using password: NO)
ERROR 08S01: Unknown command
ERROR 08S01: Unknown command
...@@ -847,9 +847,9 @@ a int(11) YES NULL ...@@ -847,9 +847,9 @@ a int(11) YES NULL
b varchar(255) YES NULL b varchar(255) YES NULL
c datetime YES NULL c datetime YES NULL
drop table t1; drop table t1;
mysqltest: At line 1: change user failed: Unknown database 'inexistent' mysqltest: At line 1: query 'change_user root,,inexistent' failed: 1049: Unknown database 'inexistent'
mysqltest: At line 1: change user failed: Access denied for user 'inexistent'@'localhost' (using password: NO) mysqltest: At line 1: query 'change_user inexistent,,test' failed: 1045: Access denied for user 'inexistent'@'localhost' (using password: NO)
mysqltest: At line 1: change user failed: Access denied for user 'root'@'localhost' (using password: YES) mysqltest: At line 1: query 'change_user root,inexistent,test' failed: 1045: Access denied for user 'root'@'localhost' (using password: YES)
REPLACED_FILE1.txt REPLACED_FILE1.txt
file1.txt file1.txt
file2.txt file2.txt
......
source include/not_embedded.inc;
#
# MDEV-3915 COM_CHANGE_USER allows fast password brute-forcing
#
# only three failed change_user per connection.
# successful change_user do NOT reset the counter
#
connect (test,localhost,root,,);
connection test;
--error 1045
change_user foo,bar;
--error 1045
change_user foo;
change_user;
--error 1045
change_user foo,bar;
--error 1047
change_user foo,bar;
--error 1047
change_user;
disconnect test;
connection default;
...@@ -675,6 +675,7 @@ THD::THD() ...@@ -675,6 +675,7 @@ THD::THD()
stmt_depends_on_first_successful_insert_id_in_prev_stmt(FALSE), stmt_depends_on_first_successful_insert_id_in_prev_stmt(FALSE),
examined_row_count(0), examined_row_count(0),
global_read_lock(0), global_read_lock(0),
failed_com_change_user(0),
is_fatal_error(0), is_fatal_error(0),
transaction_rollback_request(0), transaction_rollback_request(0),
is_fatal_sub_stmt_error(0), is_fatal_sub_stmt_error(0),
......
...@@ -1865,6 +1865,7 @@ public: ...@@ -1865,6 +1865,7 @@ public:
bool no_errors, password; bool no_errors, password;
bool extra_port; /* If extra connection */ bool extra_port; /* If extra connection */
uint8 failed_com_change_user;
/** /**
Set to TRUE if execution of the current compound statement Set to TRUE if execution of the current compound statement
can not continue. In particular, disables activation of can not continue. In particular, disables activation of
......
...@@ -1144,6 +1144,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, ...@@ -1144,6 +1144,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
uint save_db_length= thd->db_length; uint save_db_length= thd->db_length;
char *save_db= thd->db; char *save_db= thd->db;
int rc;
USER_CONN *save_user_connect= thd->user_connect; USER_CONN *save_user_connect= thd->user_connect;
Security_context save_security_ctx= *thd->security_ctx; Security_context save_security_ctx= *thd->security_ctx;
CHARSET_INFO *save_character_set_client= CHARSET_INFO *save_character_set_client=
...@@ -1157,7 +1158,19 @@ bool dispatch_command(enum enum_server_command command, THD *thd, ...@@ -1157,7 +1158,19 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
thd->security_ctx->user= 0; thd->security_ctx->user= 0;
thd->user_connect= 0; thd->user_connect= 0;
if (acl_authenticate(thd, 0, packet_length)) /*
to limit COM_CHANGE_USER ability to brute-force passwords,
we only allow three unsuccessful COM_CHANGE_USER per connection.
*/
if (thd->failed_com_change_user >= 3)
{
my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
rc= 1;
}
else
rc= acl_authenticate(thd, 0, packet_length);
if (rc)
{ {
/* Free user if allocated by acl_authenticate */ /* Free user if allocated by acl_authenticate */
x_free(thd->security_ctx->user); x_free(thd->security_ctx->user);
...@@ -1170,6 +1183,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd, ...@@ -1170,6 +1183,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
thd->variables.collation_connection= save_collation_connection; thd->variables.collation_connection= save_collation_connection;
thd->variables.character_set_results= save_character_set_results; thd->variables.character_set_results= save_character_set_results;
thd->update_charset(); thd->update_charset();
thd->failed_com_change_user++;
my_sleep(1000000);
} }
else else
{ {
......
This diff is collapsed.
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