MDEV-7598 Lock user after too many password errors
This commit is contained in:
parent
30da40bb8c
commit
83c81d8991
13
mysql-test/include/have_auth_named_pipe.inc
Normal file
13
mysql-test/include/have_auth_named_pipe.inc
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
--source include/not_embedded.inc
|
||||||
|
|
||||||
|
if (!$AUTH_NAMED_PIPE_SO) {
|
||||||
|
skip No auth_named_pipe plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$USERNAME) {
|
||||||
|
skip USER variable is undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (`SELECT count(*) <> 0 FROM mysql.user WHERE user = '$USERNAME'`) {
|
||||||
|
skip %USERNAME%=$USER which exists in mysql.user;
|
||||||
|
}
|
45
mysql-test/main/max_password_errors.result
Normal file
45
mysql-test/main/max_password_errors.result
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
set @old_max_password_errors=@@max_password_errors;
|
||||||
|
set global max_password_errors=2;
|
||||||
|
create user u identified by 'good_pass';
|
||||||
|
connect(localhost,u,bas_pass,test,MASTER_PORT,MASTER_SOCKET);
|
||||||
|
connect con1, localhost, u, bas_pass;
|
||||||
|
ERROR 28000: Access denied for user 'u'@'localhost' (using password: YES)
|
||||||
|
connect(localhost,u,bad_pass,test,MASTER_PORT,MASTER_SOCKET);
|
||||||
|
connect con1, localhost, u, bad_pass;
|
||||||
|
ERROR 28000: Access denied for user 'u'@'localhost' (using password: YES)
|
||||||
|
connect(localhost,u,good_pass,test,MASTER_PORT,MASTER_SOCKET);
|
||||||
|
connect con1, localhost, u, good_pass;
|
||||||
|
ERROR HY000: User is blocked because of too many credential errors; unblock with 'FLUSH PRIVILEGES'
|
||||||
|
connect(localhost,u,bad_pass,test,MASTER_PORT,MASTER_SOCKET);
|
||||||
|
connect con1, localhost, u, bad_pass;
|
||||||
|
ERROR HY000: User is blocked because of too many credential errors; unblock with 'FLUSH PRIVILEGES'
|
||||||
|
FLUSH PRIVILEGES;
|
||||||
|
connect con1, localhost, u, good_pass;
|
||||||
|
disconnect con1;
|
||||||
|
connect(localhost,u,bad_pass,test,MASTER_PORT,MASTER_SOCKET);
|
||||||
|
connect con1, localhost, u, bad_pass;
|
||||||
|
ERROR 28000: Access denied for user 'u'@'localhost' (using password: YES)
|
||||||
|
connect con1, localhost, u, good_pass;
|
||||||
|
disconnect con1;
|
||||||
|
connect(localhost,u,bad_pass,test,MASTER_PORT,MASTER_SOCKET);
|
||||||
|
connect con1, localhost, u, bad_pass;
|
||||||
|
ERROR 28000: Access denied for user 'u'@'localhost' (using password: YES)
|
||||||
|
connect con1, localhost, u, good_pass;
|
||||||
|
ERROR 28000: Access denied for user 'u'@'localhost' (using password: YES)
|
||||||
|
ERROR 28000: Access denied for user 'u'@'localhost' (using password: YES)
|
||||||
|
ERROR HY000: User is blocked because of too many credential errors; unblock with 'FLUSH PRIVILEGES'
|
||||||
|
disconnect con1;
|
||||||
|
connection default;
|
||||||
|
FLUSH PRIVILEGES;
|
||||||
|
connect(localhost,root,bas_pass,test,MASTER_PORT,MASTER_SOCKET);
|
||||||
|
connect con1, localhost, root, bas_pass;
|
||||||
|
ERROR 28000: Access denied for user 'root'@'localhost' (using password: YES)
|
||||||
|
connect(localhost,root,bad_pass,test,MASTER_PORT,MASTER_SOCKET);
|
||||||
|
connect con1, localhost, root, bad_pass;
|
||||||
|
ERROR 28000: Access denied for user 'root'@'localhost' (using password: YES)
|
||||||
|
connect con1, localhost, u, good_pass;
|
||||||
|
disconnect con1;
|
||||||
|
connection default;
|
||||||
|
DROP USER u;
|
||||||
|
FLUSH PRIVILEGES;
|
||||||
|
set global max_password_errors=@old_max_password_errors;
|
64
mysql-test/main/max_password_errors.test
Normal file
64
mysql-test/main/max_password_errors.test
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
--source include/not_embedded.inc
|
||||||
|
set @old_max_password_errors=@@max_password_errors;
|
||||||
|
set global max_password_errors=2;
|
||||||
|
create user u identified by 'good_pass';
|
||||||
|
|
||||||
|
# Test that user is blocked after 'max_password_errors' bad passwords
|
||||||
|
--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
|
||||||
|
error ER_ACCESS_DENIED_ERROR;
|
||||||
|
connect(con1, localhost, u, bas_pass);
|
||||||
|
--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
|
||||||
|
error ER_ACCESS_DENIED_ERROR;
|
||||||
|
connect (con1, localhost, u, bad_pass);
|
||||||
|
--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
|
||||||
|
error ER_USER_IS_BLOCKED;
|
||||||
|
connect(con1, localhost, u, good_pass);
|
||||||
|
--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
|
||||||
|
error ER_USER_IS_BLOCKED;
|
||||||
|
connect(con1, localhost, u, bad_pass);
|
||||||
|
|
||||||
|
|
||||||
|
# Test that FLUSH PRIVILEGES clears the error
|
||||||
|
FLUSH PRIVILEGES;
|
||||||
|
connect (con1, localhost, u, good_pass);
|
||||||
|
disconnect con1;
|
||||||
|
|
||||||
|
# Test that good login clears the error
|
||||||
|
--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
|
||||||
|
error ER_ACCESS_DENIED_ERROR;
|
||||||
|
connect (con1, localhost, u, bad_pass);
|
||||||
|
connect (con1, localhost, u, good_pass);
|
||||||
|
disconnect con1;
|
||||||
|
--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
|
||||||
|
error ER_ACCESS_DENIED_ERROR;
|
||||||
|
connect (con1, localhost, u, bad_pass);
|
||||||
|
connect (con1, localhost, u, good_pass);
|
||||||
|
|
||||||
|
# Test the behavior of change_user
|
||||||
|
--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
|
||||||
|
error ER_ACCESS_DENIED_ERROR;
|
||||||
|
change_user u,bad_pass;
|
||||||
|
--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
|
||||||
|
error ER_ACCESS_DENIED_ERROR;
|
||||||
|
change_user u,bad_pass;
|
||||||
|
--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
|
||||||
|
error ER_USER_IS_BLOCKED;
|
||||||
|
change_user u,good_pass;
|
||||||
|
disconnect con1;
|
||||||
|
|
||||||
|
connection default;
|
||||||
|
FLUSH PRIVILEGES;
|
||||||
|
|
||||||
|
#Test that root@localhost is not blocked, with password errors
|
||||||
|
--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
|
||||||
|
error ER_ACCESS_DENIED_ERROR;
|
||||||
|
connect(con1, localhost, root, bas_pass);
|
||||||
|
--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
|
||||||
|
error ER_ACCESS_DENIED_ERROR;
|
||||||
|
connect (con1, localhost, root, bad_pass);
|
||||||
|
connect (con1, localhost, u, good_pass);
|
||||||
|
disconnect con1;
|
||||||
|
connection default;
|
||||||
|
DROP USER u;
|
||||||
|
FLUSH PRIVILEGES;
|
||||||
|
set global max_password_errors=@old_max_password_errors;
|
@ -546,6 +546,10 @@ The following specify which files/extra groups are read (specified before remain
|
|||||||
The maximum BLOB length to send to server from
|
The maximum BLOB length to send to server from
|
||||||
mysql_send_long_data API. Deprecated option; use
|
mysql_send_long_data API. Deprecated option; use
|
||||||
max_allowed_packet instead.
|
max_allowed_packet instead.
|
||||||
|
--max-password-errors=#
|
||||||
|
If there is more than this number of failed connect
|
||||||
|
attempts due to invalid password, user will be blocked
|
||||||
|
from further connections until FLUSH_PRIVILEGES.
|
||||||
--max-prepared-stmt-count=#
|
--max-prepared-stmt-count=#
|
||||||
Maximum number of prepared statements in the server
|
Maximum number of prepared statements in the server
|
||||||
--max-recursive-iterations[=#]
|
--max-recursive-iterations[=#]
|
||||||
@ -1518,6 +1522,7 @@ max-heap-table-size 16777216
|
|||||||
max-join-size 18446744073709551615
|
max-join-size 18446744073709551615
|
||||||
max-length-for-sort-data 1024
|
max-length-for-sort-data 1024
|
||||||
max-long-data-size 16777216
|
max-long-data-size 16777216
|
||||||
|
max-password-errors 18446744073709551615
|
||||||
max-prepared-stmt-count 16382
|
max-prepared-stmt-count 16382
|
||||||
max-recursive-iterations 18446744073709551615
|
max-recursive-iterations 18446744073709551615
|
||||||
max-relay-log-size 1073741824
|
max-relay-log-size 1073741824
|
||||||
|
@ -0,0 +1,12 @@
|
|||||||
|
set @old_max_password_errors=@@max_password_errors;
|
||||||
|
create user nosuchuser identified with 'named_pipe';
|
||||||
|
set global max_password_errors=1;
|
||||||
|
connect(localhost,nosuchuser,,test,MASTER_PORT,MASTER_SOCKET);
|
||||||
|
connect pipe_con,localhost,nosuchuser,,,,,PIPE;
|
||||||
|
ERROR 28000: Access denied for user 'nosuchuser'@'localhost'
|
||||||
|
connect(localhost,nosuchuser,,test,MASTER_PORT,MASTER_SOCKET);
|
||||||
|
connect pipe_con,localhost,nosuchuser,,,,,PIPE;
|
||||||
|
ERROR 28000: Access denied for user 'nosuchuser'@'localhost'
|
||||||
|
DROP USER nosuchuser;
|
||||||
|
FLUSH PRIVILEGES;
|
||||||
|
set global max_password_errors=@old_max_password_errors;
|
@ -0,0 +1,12 @@
|
|||||||
|
set @old_max_password_errors=@@max_password_errors;
|
||||||
|
create user nosuchuser identified with 'unix_socket';
|
||||||
|
set global max_password_errors=1;
|
||||||
|
connect(localhost,nosuchuser,,test,MASTER_PORT,MASTER_SOCKET);
|
||||||
|
connect pipe_con,localhost,nosuchuser;
|
||||||
|
ERROR 28000: Access denied for user 'nosuchuser'@'localhost'
|
||||||
|
connect(localhost,nosuchuser,,test,MASTER_PORT,MASTER_SOCKET);
|
||||||
|
connect pipe_con,localhost,nosuchuser;
|
||||||
|
ERROR 28000: Access denied for user 'nosuchuser'@'localhost'
|
||||||
|
DROP USER nosuchuser;
|
||||||
|
FLUSH PRIVILEGES;
|
||||||
|
set global max_password_errors=@old_max_password_errors;
|
@ -0,0 +1 @@
|
|||||||
|
--loose-enable-named-pipe --plugin-load=$AUTH_NAMED_PIPE_SO
|
@ -0,0 +1,22 @@
|
|||||||
|
# Tests that max_password_errors has no effect on login errors with
|
||||||
|
# passwordless plugins (Windows version / auth_named_pipe)
|
||||||
|
|
||||||
|
--source include/not_embedded.inc
|
||||||
|
--source include/have_auth_named_pipe.inc
|
||||||
|
if (`SELECT '$USERNAME' = 'nosuchuser'`) {
|
||||||
|
skip skipped for nosuchuser;
|
||||||
|
}
|
||||||
|
set @old_max_password_errors=@@max_password_errors;
|
||||||
|
create user nosuchuser identified with 'named_pipe';
|
||||||
|
|
||||||
|
set global max_password_errors=1;
|
||||||
|
--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
|
||||||
|
error ER_ACCESS_DENIED_NO_PASSWORD_ERROR;
|
||||||
|
connect(pipe_con,localhost,nosuchuser,,,,,PIPE);
|
||||||
|
--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
|
||||||
|
error ER_ACCESS_DENIED_NO_PASSWORD_ERROR;
|
||||||
|
connect(pipe_con,localhost,nosuchuser,,,,,PIPE);
|
||||||
|
|
||||||
|
DROP USER nosuchuser;
|
||||||
|
FLUSH PRIVILEGES;
|
||||||
|
set global max_password_errors=@old_max_password_errors;
|
@ -0,0 +1 @@
|
|||||||
|
--loose-enable-named-pipe --plugin-load=$AUTH_SOCKET_SO
|
@ -0,0 +1,23 @@
|
|||||||
|
# Tests that max_password_errors has no effect on login errors with
|
||||||
|
# passwordless plugins (Unix version / auth_unix_socket)
|
||||||
|
|
||||||
|
--source include/not_embedded.inc
|
||||||
|
--source include/have_unix_socket.inc
|
||||||
|
|
||||||
|
if (`SELECT '$USER' = 'nosuchuser'`) {
|
||||||
|
skip USER is nosuchuser;
|
||||||
|
}
|
||||||
|
set @old_max_password_errors=@@max_password_errors;
|
||||||
|
create user nosuchuser identified with 'unix_socket';
|
||||||
|
|
||||||
|
set global max_password_errors=1;
|
||||||
|
--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
|
||||||
|
error ER_ACCESS_DENIED_NO_PASSWORD_ERROR;
|
||||||
|
connect(pipe_con,localhost,nosuchuser);
|
||||||
|
--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
|
||||||
|
error ER_ACCESS_DENIED_NO_PASSWORD_ERROR;
|
||||||
|
connect(pipe_con,localhost,nosuchuser);
|
||||||
|
|
||||||
|
DROP USER nosuchuser;
|
||||||
|
FLUSH PRIVILEGES;
|
||||||
|
set global max_password_errors=@old_max_password_errors;
|
@ -2210,6 +2210,20 @@ NUMERIC_BLOCK_SIZE 1
|
|||||||
ENUM_VALUE_LIST NULL
|
ENUM_VALUE_LIST NULL
|
||||||
READ_ONLY YES
|
READ_ONLY YES
|
||||||
COMMAND_LINE_ARGUMENT REQUIRED
|
COMMAND_LINE_ARGUMENT REQUIRED
|
||||||
|
VARIABLE_NAME MAX_PASSWORD_ERRORS
|
||||||
|
SESSION_VALUE NULL
|
||||||
|
GLOBAL_VALUE 4294967295
|
||||||
|
GLOBAL_VALUE_ORIGIN COMPILE-TIME
|
||||||
|
DEFAULT_VALUE 4294967295
|
||||||
|
VARIABLE_SCOPE GLOBAL
|
||||||
|
VARIABLE_TYPE INT UNSIGNED
|
||||||
|
VARIABLE_COMMENT If there is more than this number of failed connect attempts due to invalid password, user will be blocked from further connections until FLUSH_PRIVILEGES.
|
||||||
|
NUMERIC_MIN_VALUE 1
|
||||||
|
NUMERIC_MAX_VALUE 4294967295
|
||||||
|
NUMERIC_BLOCK_SIZE 1
|
||||||
|
ENUM_VALUE_LIST NULL
|
||||||
|
READ_ONLY NO
|
||||||
|
COMMAND_LINE_ARGUMENT REQUIRED
|
||||||
VARIABLE_NAME MAX_PREPARED_STMT_COUNT
|
VARIABLE_NAME MAX_PREPARED_STMT_COUNT
|
||||||
SESSION_VALUE NULL
|
SESSION_VALUE NULL
|
||||||
GLOBAL_VALUE 16382
|
GLOBAL_VALUE 16382
|
||||||
|
@ -2420,6 +2420,20 @@ NUMERIC_BLOCK_SIZE 1
|
|||||||
ENUM_VALUE_LIST NULL
|
ENUM_VALUE_LIST NULL
|
||||||
READ_ONLY YES
|
READ_ONLY YES
|
||||||
COMMAND_LINE_ARGUMENT REQUIRED
|
COMMAND_LINE_ARGUMENT REQUIRED
|
||||||
|
VARIABLE_NAME MAX_PASSWORD_ERRORS
|
||||||
|
SESSION_VALUE NULL
|
||||||
|
GLOBAL_VALUE 4294967295
|
||||||
|
GLOBAL_VALUE_ORIGIN COMPILE-TIME
|
||||||
|
DEFAULT_VALUE 4294967295
|
||||||
|
VARIABLE_SCOPE GLOBAL
|
||||||
|
VARIABLE_TYPE INT UNSIGNED
|
||||||
|
VARIABLE_COMMENT If there is more than this number of failed connect attempts due to invalid password, user will be blocked from further connections until FLUSH_PRIVILEGES.
|
||||||
|
NUMERIC_MIN_VALUE 1
|
||||||
|
NUMERIC_MAX_VALUE 4294967295
|
||||||
|
NUMERIC_BLOCK_SIZE 1
|
||||||
|
ENUM_VALUE_LIST NULL
|
||||||
|
READ_ONLY NO
|
||||||
|
COMMAND_LINE_ARGUMENT REQUIRED
|
||||||
VARIABLE_NAME MAX_PREPARED_STMT_COUNT
|
VARIABLE_NAME MAX_PREPARED_STMT_COUNT
|
||||||
SESSION_VALUE NULL
|
SESSION_VALUE NULL
|
||||||
GLOBAL_VALUE 16382
|
GLOBAL_VALUE 16382
|
||||||
|
@ -513,6 +513,7 @@ ulong specialflag=0;
|
|||||||
ulong binlog_cache_use= 0, binlog_cache_disk_use= 0;
|
ulong binlog_cache_use= 0, binlog_cache_disk_use= 0;
|
||||||
ulong binlog_stmt_cache_use= 0, binlog_stmt_cache_disk_use= 0;
|
ulong binlog_stmt_cache_use= 0, binlog_stmt_cache_disk_use= 0;
|
||||||
ulong max_connections, max_connect_errors;
|
ulong max_connections, max_connect_errors;
|
||||||
|
uint max_password_errors;
|
||||||
ulong extra_max_connections;
|
ulong extra_max_connections;
|
||||||
uint max_digest_length= 0;
|
uint max_digest_length= 0;
|
||||||
ulong slave_retried_transactions;
|
ulong slave_retried_transactions;
|
||||||
|
@ -241,6 +241,7 @@ extern ulong slow_launch_threads, slow_launch_time;
|
|||||||
extern MYSQL_PLUGIN_IMPORT ulong max_connections;
|
extern MYSQL_PLUGIN_IMPORT ulong max_connections;
|
||||||
extern uint max_digest_length;
|
extern uint max_digest_length;
|
||||||
extern ulong max_connect_errors, connect_timeout;
|
extern ulong max_connect_errors, connect_timeout;
|
||||||
|
extern uint max_password_errors;
|
||||||
extern my_bool slave_allow_batching;
|
extern my_bool slave_allow_batching;
|
||||||
extern my_bool allow_slave_start;
|
extern my_bool allow_slave_start;
|
||||||
extern LEX_CSTRING reason_slave_blocked;
|
extern LEX_CSTRING reason_slave_blocked;
|
||||||
|
@ -7931,3 +7931,5 @@ ER_BACKUP_STAGE_FAILED
|
|||||||
eng "Backup stage '%s' failed"
|
eng "Backup stage '%s' failed"
|
||||||
ER_BACKUP_UNKNOWN_STAGE
|
ER_BACKUP_UNKNOWN_STAGE
|
||||||
eng "Unknown backup stage: '%s'. Stage should be one of START, FLUSH, BLOCK_DDL, BLOCK_COMMIT or END"
|
eng "Unknown backup stage: '%s'. Stage should be one of START, FLUSH, BLOCK_DDL, BLOCK_COMMIT or END"
|
||||||
|
ER_USER_IS_BLOCKED
|
||||||
|
eng "User is blocked because of too many credential errors; unblock with 'FLUSH PRIVILEGES'"
|
||||||
|
@ -147,6 +147,7 @@ public:
|
|||||||
size_t hostname_length;
|
size_t hostname_length;
|
||||||
USER_RESOURCES user_resource;
|
USER_RESOURCES user_resource;
|
||||||
enum SSL_type ssl_type;
|
enum SSL_type ssl_type;
|
||||||
|
uint password_errors;
|
||||||
const char *ssl_cipher, *x509_issuer, *x509_subject;
|
const char *ssl_cipher, *x509_issuer, *x509_subject;
|
||||||
LEX_CSTRING plugin;
|
LEX_CSTRING plugin;
|
||||||
LEX_CSTRING auth_string;
|
LEX_CSTRING auth_string;
|
||||||
@ -12325,6 +12326,23 @@ static bool send_plugin_request_packet(MPVIO_EXT *mpvio,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||||
|
|
||||||
|
/**
|
||||||
|
Safeguard to avoid blocking the root, when max_password_errors
|
||||||
|
limit is reached.
|
||||||
|
|
||||||
|
Currently, we allow password errors for superuser on localhost.
|
||||||
|
|
||||||
|
@return true, if password errors should be ignored, and user should not be locked.
|
||||||
|
*/
|
||||||
|
static bool ignore_max_password_errors(const ACL_USER *acl_user)
|
||||||
|
{
|
||||||
|
const char *host= acl_user->host.hostname;
|
||||||
|
return (acl_user->access & SUPER_ACL)
|
||||||
|
&& (!strcasecmp(host, "localhost") ||
|
||||||
|
!strcmp(host, "127.0.0.1") ||
|
||||||
|
!strcmp(host, "::1"));
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
Finds acl entry in user database for authentication purposes.
|
Finds acl entry in user database for authentication purposes.
|
||||||
|
|
||||||
@ -12343,6 +12361,16 @@ static bool find_mpvio_user(MPVIO_EXT *mpvio)
|
|||||||
mysql_mutex_lock(&acl_cache->lock);
|
mysql_mutex_lock(&acl_cache->lock);
|
||||||
|
|
||||||
ACL_USER *user= find_user_or_anon(sctx->host, sctx->user, sctx->ip);
|
ACL_USER *user= find_user_or_anon(sctx->host, sctx->user, sctx->ip);
|
||||||
|
|
||||||
|
if (user && user->password_errors >= max_password_errors && !ignore_max_password_errors(user))
|
||||||
|
{
|
||||||
|
mysql_mutex_unlock(&acl_cache->lock);
|
||||||
|
my_error(ER_USER_IS_BLOCKED, MYF(0));
|
||||||
|
general_log_print(mpvio->auth_info.thd, COM_CONNECT,
|
||||||
|
ER_THD(mpvio->auth_info.thd, ER_USER_IS_BLOCKED));
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
}
|
||||||
|
|
||||||
if (user)
|
if (user)
|
||||||
mpvio->acl_user= user->copy(mpvio->auth_info.thd->mem_root);
|
mpvio->acl_user= user->copy(mpvio->auth_info.thd->mem_root);
|
||||||
|
|
||||||
@ -13188,6 +13216,38 @@ static int do_auth_once(THD *thd, const LEX_CSTRING *auth_plugin_name,
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum PASSWD_ERROR_ACTION
|
||||||
|
{
|
||||||
|
PASSWD_ERROR_CLEAR,
|
||||||
|
PASSWD_ERROR_INCREMENT
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Increment, or clear password errors for a user. */
|
||||||
|
static void handle_password_errors(const char *user, const char *hostname, PASSWD_ERROR_ACTION action)
|
||||||
|
{
|
||||||
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||||
|
mysql_mutex_assert_not_owner(&acl_cache->lock);
|
||||||
|
mysql_mutex_lock(&acl_cache->lock);
|
||||||
|
ACL_USER *u = find_user_exact(hostname, user);
|
||||||
|
if (u)
|
||||||
|
{
|
||||||
|
switch(action)
|
||||||
|
{
|
||||||
|
case PASSWD_ERROR_INCREMENT:
|
||||||
|
u->password_errors++;
|
||||||
|
break;
|
||||||
|
case PASSWD_ERROR_CLEAR:
|
||||||
|
u->password_errors= 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DBUG_ASSERT(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mysql_mutex_unlock(&acl_cache->lock);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Perform the handshake, authorize the client and update thd sctx variables.
|
Perform the handshake, authorize the client and update thd sctx variables.
|
||||||
@ -13307,6 +13367,8 @@ bool acl_authenticate(THD *thd, uint com_change_user_pkt_len)
|
|||||||
break;
|
break;
|
||||||
case CR_AUTH_USER_CREDENTIALS:
|
case CR_AUTH_USER_CREDENTIALS:
|
||||||
errors.m_authentication= 1;
|
errors.m_authentication= 1;
|
||||||
|
if (thd->password && !mpvio.make_it_fail)
|
||||||
|
handle_password_errors(acl_user->user.str, acl_user->host.hostname, PASSWD_ERROR_INCREMENT);
|
||||||
break;
|
break;
|
||||||
case CR_ERROR:
|
case CR_ERROR:
|
||||||
default:
|
default:
|
||||||
@ -13321,6 +13383,11 @@ bool acl_authenticate(THD *thd, uint com_change_user_pkt_len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
sctx->proxy_user[0]= 0;
|
sctx->proxy_user[0]= 0;
|
||||||
|
if (thd->password && acl_user->password_errors)
|
||||||
|
{
|
||||||
|
/* Login succeeded, clear password errors.*/
|
||||||
|
handle_password_errors(acl_user->user.str, acl_user->host.hostname, PASSWD_ERROR_CLEAR);
|
||||||
|
}
|
||||||
|
|
||||||
if (initialized) // if not --skip-grant-tables
|
if (initialized) // if not --skip-grant-tables
|
||||||
{
|
{
|
||||||
|
@ -1515,6 +1515,14 @@ static Sys_var_ulong Sys_max_connect_errors(
|
|||||||
VALID_RANGE(1, UINT_MAX), DEFAULT(MAX_CONNECT_ERRORS),
|
VALID_RANGE(1, UINT_MAX), DEFAULT(MAX_CONNECT_ERRORS),
|
||||||
BLOCK_SIZE(1));
|
BLOCK_SIZE(1));
|
||||||
|
|
||||||
|
static Sys_var_uint Sys_max_password_errors(
|
||||||
|
"max_password_errors",
|
||||||
|
"If there is more than this number of failed connect attempts "
|
||||||
|
"due to invalid password, user will be blocked from further connections until FLUSH_PRIVILEGES.",
|
||||||
|
GLOBAL_VAR(max_password_errors), CMD_LINE(REQUIRED_ARG),
|
||||||
|
VALID_RANGE(1, UINT_MAX), DEFAULT(UINT_MAX),
|
||||||
|
BLOCK_SIZE(1));
|
||||||
|
|
||||||
static Sys_var_uint Sys_max_digest_length(
|
static Sys_var_uint Sys_max_digest_length(
|
||||||
"max_digest_length", "Maximum length considered for digest text.",
|
"max_digest_length", "Maximum length considered for digest text.",
|
||||||
READ_ONLY GLOBAL_VAR(max_digest_length),
|
READ_ONLY GLOBAL_VAR(max_digest_length),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user