mirror of
https://github.com/MariaDB/server.git
synced 2025-08-07 00:04:31 +03:00
MDEV-24207: recognise mysql forms of invalid password for mysql_native_password
The main goal of this patch is to prevent MariaDB's native_password_plugin from "parsing" the hex (or non hex) authentication_string. Due to how the current code is written, we convert any string (within native_password_get_salt) that has the appropriate length to a "binary" representation, that can potentially match a real password. More specifically, "*THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE" produces the same results as "*d13c3c78dafa52d9bce09bdd1adcb7befced1ebe". The length indicator is the main indicator of an invalid password. We use use same trick with "invalid" to change its internal representation. The "parsing" mentioned is by get_salt_from_password down to char_val() and because if where it is, its effectively a static plugin API that cannot change. In supporting these, we support the SHOW CREATE USER from MySQL may have the hashed password string: *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE. Obviously this isn't a hash because it contains non-hex characters. After this patch we do however recognise the pattern; [any char, notionally *]{40 chars not all are hex} as a pattern for an invalid password. This was determined to be the general pattern that MySQL used. Reviewers: Sergei G, Vicentiu
This commit is contained in:
@@ -11,9 +11,11 @@ create user oldauth@localhost identified with 'mysql_old_password' using '378b24
|
|||||||
create user oldpass@localhost identified by password '378b243e220ca493';
|
create user oldpass@localhost identified by password '378b243e220ca493';
|
||||||
create user oldpassold@localhost identified with 'mysql_old_password';
|
create user oldpassold@localhost identified with 'mysql_old_password';
|
||||||
set password for oldpassold@localhost = '378b243e220ca493';
|
set password for oldpassold@localhost = '378b243e220ca493';
|
||||||
|
create user invalidmysql57auth@localhost identified via 'mysql_native_password' using '*THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE';
|
||||||
select user, host, password, plugin, authentication_string from mysql.user where user != 'root';
|
select user, host, password, plugin, authentication_string from mysql.user where user != 'root';
|
||||||
User Host Password plugin authentication_string
|
User Host Password plugin authentication_string
|
||||||
invalidauth localhost invalid mysql_native_password invalid
|
invalidauth localhost invalid mysql_native_password invalid
|
||||||
|
invalidmysql57auth localhost *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE mysql_native_password *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE
|
||||||
invalidpass localhost invalid mysql_native_password invalid
|
invalidpass localhost invalid mysql_native_password invalid
|
||||||
invalidpassnat localhost invalid mysql_native_password invalid
|
invalidpassnat localhost invalid mysql_native_password invalid
|
||||||
mariadb.sys localhost mysql_native_password
|
mariadb.sys localhost mysql_native_password
|
||||||
@@ -95,6 +97,7 @@ set password for oldpassold@localhost = PASSWORD('test2');
|
|||||||
select user, host, password, plugin, authentication_string from mysql.user where user != 'root';
|
select user, host, password, plugin, authentication_string from mysql.user where user != 'root';
|
||||||
User Host Password plugin authentication_string
|
User Host Password plugin authentication_string
|
||||||
invalidauth localhost invalid mysql_native_password invalid
|
invalidauth localhost invalid mysql_native_password invalid
|
||||||
|
invalidmysql57auth localhost *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE mysql_native_password *THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE
|
||||||
invalidpass localhost invalid mysql_native_password invalid
|
invalidpass localhost invalid mysql_native_password invalid
|
||||||
invalidpassnat localhost invalid mysql_native_password invalid
|
invalidpassnat localhost invalid mysql_native_password invalid
|
||||||
mariadb.sys localhost mysql_native_password
|
mariadb.sys localhost mysql_native_password
|
||||||
@@ -160,6 +163,9 @@ ERROR 28000: Access denied for user 'invalidpass'@'localhost' (using password: Y
|
|||||||
connect(localhost,invalidpassnat,invalid,test,MASTER_PORT,MASTER_SOCKET);
|
connect(localhost,invalidpassnat,invalid,test,MASTER_PORT,MASTER_SOCKET);
|
||||||
connect con,localhost,invalidpassnat,invalid,;
|
connect con,localhost,invalidpassnat,invalid,;
|
||||||
ERROR 28000: Access denied for user 'invalidpassnat'@'localhost' (using password: YES)
|
ERROR 28000: Access denied for user 'invalidpassnat'@'localhost' (using password: YES)
|
||||||
|
connect(localhost,invalidmysql57auth,invalid,test,MASTER_PORT,MASTER_SOCKET);
|
||||||
|
connect con,localhost,invalidmysql57auth,invalid,;
|
||||||
|
ERROR 28000: Access denied for user 'invalidmysql57auth'@'localhost' (using password: YES)
|
||||||
connect con,localhost,oldauth,test2,;
|
connect con,localhost,oldauth,test2,;
|
||||||
select current_user();
|
select current_user();
|
||||||
current_user()
|
current_user()
|
||||||
@@ -177,7 +183,7 @@ oldpassold@localhost
|
|||||||
disconnect con;
|
disconnect con;
|
||||||
connection default;
|
connection default;
|
||||||
drop user natauth@localhost, newpass@localhost, newpassnat@localhost;
|
drop user natauth@localhost, newpass@localhost, newpassnat@localhost;
|
||||||
drop user invalidauth@localhost, invalidpass@localhost, invalidpassnat@localhost;
|
drop user invalidauth@localhost, invalidpass@localhost, invalidpassnat@localhost,invalidmysql57auth@localhost;
|
||||||
drop user oldauth@localhost, oldpass@localhost, oldpassold@localhost;
|
drop user oldauth@localhost, oldpass@localhost, oldpassold@localhost;
|
||||||
set global secure_auth=default;
|
set global secure_auth=default;
|
||||||
# switching from mysql.global_priv to mysql.user
|
# switching from mysql.global_priv to mysql.user
|
||||||
|
@@ -31,6 +31,8 @@ create user oldpass@localhost identified by password '378b243e220ca493';
|
|||||||
create user oldpassold@localhost identified with 'mysql_old_password';
|
create user oldpassold@localhost identified with 'mysql_old_password';
|
||||||
set password for oldpassold@localhost = '378b243e220ca493';
|
set password for oldpassold@localhost = '378b243e220ca493';
|
||||||
|
|
||||||
|
create user invalidmysql57auth@localhost identified via 'mysql_native_password' using '*THISISNOTAVALIDPASSWORDTHATCANBEUSEDHERE';
|
||||||
|
|
||||||
--sorted_result
|
--sorted_result
|
||||||
select user, host, password, plugin, authentication_string from mysql.user where user != 'root';
|
select user, host, password, plugin, authentication_string from mysql.user where user != 'root';
|
||||||
|
|
||||||
@@ -131,6 +133,9 @@ select current_user();
|
|||||||
--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
|
--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
|
||||||
--error ER_ACCESS_DENIED_ERROR
|
--error ER_ACCESS_DENIED_ERROR
|
||||||
--connect(con,localhost,invalidpassnat,invalid,)
|
--connect(con,localhost,invalidpassnat,invalid,)
|
||||||
|
--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
|
||||||
|
--error ER_ACCESS_DENIED_ERROR
|
||||||
|
--connect(con,localhost,invalidmysql57auth,invalid,)
|
||||||
|
|
||||||
--connect(con,localhost,oldauth,test2,)
|
--connect(con,localhost,oldauth,test2,)
|
||||||
select current_user();
|
select current_user();
|
||||||
@@ -144,7 +149,7 @@ select current_user();
|
|||||||
|
|
||||||
--connection default
|
--connection default
|
||||||
drop user natauth@localhost, newpass@localhost, newpassnat@localhost;
|
drop user natauth@localhost, newpass@localhost, newpassnat@localhost;
|
||||||
drop user invalidauth@localhost, invalidpass@localhost, invalidpassnat@localhost;
|
drop user invalidauth@localhost, invalidpass@localhost, invalidpassnat@localhost,invalidmysql57auth@localhost;
|
||||||
drop user oldauth@localhost, oldpass@localhost, oldpassold@localhost;
|
drop user oldauth@localhost, oldpass@localhost, oldpassold@localhost;
|
||||||
set global secure_auth=default;
|
set global secure_auth=default;
|
||||||
|
|
||||||
|
@@ -14203,6 +14203,7 @@ static int native_password_get_salt(const char *hash, size_t hash_length,
|
|||||||
{
|
{
|
||||||
DBUG_ASSERT(sizeof(invalid_password) > SCRAMBLE_LENGTH);
|
DBUG_ASSERT(sizeof(invalid_password) > SCRAMBLE_LENGTH);
|
||||||
DBUG_ASSERT(*out_length >= SCRAMBLE_LENGTH);
|
DBUG_ASSERT(*out_length >= SCRAMBLE_LENGTH);
|
||||||
|
DBUG_ASSERT(*out_length >= sizeof(invalid_password));
|
||||||
if (hash_length == 0)
|
if (hash_length == 0)
|
||||||
{
|
{
|
||||||
*out_length= 0;
|
*out_length= 0;
|
||||||
@@ -14213,14 +14214,27 @@ static int native_password_get_salt(const char *hash, size_t hash_length,
|
|||||||
{
|
{
|
||||||
if (hash_length == 7 && strcmp(hash, "invalid") == 0)
|
if (hash_length == 7 && strcmp(hash, "invalid") == 0)
|
||||||
{
|
{
|
||||||
memcpy(out, invalid_password, SCRAMBLED_PASSWORD_CHAR_LENGTH);
|
memcpy(out, invalid_password, sizeof(invalid_password));
|
||||||
*out_length= SCRAMBLED_PASSWORD_CHAR_LENGTH;
|
*out_length= sizeof(invalid_password);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
my_error(ER_PASSWD_LENGTH, MYF(0), SCRAMBLED_PASSWORD_CHAR_LENGTH);
|
my_error(ER_PASSWD_LENGTH, MYF(0), SCRAMBLED_PASSWORD_CHAR_LENGTH);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const char *c= hash + 1; c < (hash + hash_length); c++)
|
||||||
|
{
|
||||||
|
/* If any non-hex characters are found, mark the password as invalid. */
|
||||||
|
if (!(*c >= '0' && *c <= '9') &&
|
||||||
|
!(*c >= 'A' && *c <= 'F') &&
|
||||||
|
!(*c >= 'a' && *c <= 'f'))
|
||||||
|
{
|
||||||
|
memcpy(out, invalid_password, sizeof(invalid_password));
|
||||||
|
*out_length= sizeof(invalid_password);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
*out_length= SCRAMBLE_LENGTH;
|
*out_length= SCRAMBLE_LENGTH;
|
||||||
get_salt_from_password(out, hash);
|
get_salt_from_password(out, hash);
|
||||||
return 0;
|
return 0;
|
||||||
|
Reference in New Issue
Block a user