Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions mysql-test/suite/plugins/r/mdev38550.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#
# Setup
#
INSTALL PLUGIN IF NOT EXISTS cleartext_plugin_server SONAME '';
Warnings:
Note 1968 Plugin 'cleartext_plugin_server' already installed
CREATE DATABASE mdev38550_db;
#
# Test 1: COM_CHANGE_USER with short password
# Verify mysql_change_user() works correctly with database parameter
#
CREATE USER changeusertest IDENTIFIED VIA cleartext_plugin_server USING 'changepwd';
GRANT ALL ON *.* TO changeusertest;
SELECT DATABASE() AS db;
db
mdev38550_db
#
# Test 2: COM_CHANGE_USER with long password (260 bytes)
# This works because auth plugin switching sends password in a SECOND packet
# (via ma_net_write), bypassing the 255-byte limit in send_change_user_packet()
#
# Note: If connection used cleartext directly (no auth switch), it would fail
# due to libmariadb's 255-byte limit in send_change_user_packet()
#
CREATE USER changeuserlongpwd IDENTIFIED VIA cleartext_plugin_server USING 'cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc';
GRANT ALL ON *.* TO changeuserlongpwd;
SELECT DATABASE() AS db;
db
mdev38550_db
#
# Test 3: COM_CHANGE_USER with long password - no auth switch
# Connection uses cleartext directly, password goes in first packet
# Requires LENENC support in both client and server for COM_CHANGE_USER
#
connect cleartext_con, 127.0.0.1, changeuserlongpwd, $change_pwd, mdev38550_db, $MASTER_MYPORT, , , mysql_clear_password;
SELECT DATABASE() AS db;
db
mdev38550_db
SELECT CURRENT_USER() AS user;
user
changeuserlongpwd@%
SELECT DATABASE() AS db;
db
mdev38550_db
connection default;
disconnect cleartext_con;
#
# Cleanup
#
DROP USER changeusertest, changeuserlongpwd;
DROP DATABASE mdev38550_db;
1 change: 0 additions & 1 deletion mysql-test/suite/plugins/t/mdev38431.test
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,3 @@ GRANT ALL ON *.* TO verylonguser;
--echo #
DROP USER shortuser, longuser, verylonguser;
DROP DATABASE mdev38431_db;
# Note: Do not uninstall cleartext_plugin_server as it was pre-loaded by MTR
66 changes: 66 additions & 0 deletions mysql-test/suite/plugins/t/mdev38550.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#
# MDEV-38550: COM_CHANGE_USER with Long Password Corrupts Database Name
#
# When password > 255 bytes with COM_CHANGE_USER, the password length was
# truncated to a single byte, causing the server to read garbage as the
# database name.
#
# Fix: Add LENENC support for COM_CHANGE_USER password field in both
# client (libmariadb) and server (sql_acl.cc).
#

--source include/not_embedded.inc
--source include/have_plugin_auth.inc

--echo #
--echo # Setup
--echo #
eval INSTALL PLUGIN IF NOT EXISTS cleartext_plugin_server SONAME '$PLUGIN_AUTH';
CREATE DATABASE mdev38550_db;

--echo #
--echo # Test 1: COM_CHANGE_USER with short password
--echo # Verify mysql_change_user() works correctly with database parameter
--echo #
CREATE USER changeusertest IDENTIFIED VIA cleartext_plugin_server USING 'changepwd';
GRANT ALL ON *.* TO changeusertest;

# Use change_user command to switch user with password and database
change_user changeusertest,changepwd,mdev38550_db;
SELECT DATABASE() AS db;
change_user root;

--echo #
--echo # Test 2: COM_CHANGE_USER with long password (260 bytes)
--echo # This works because auth plugin switching sends password in a SECOND packet
--echo # (via ma_net_write), bypassing the 255-byte limit in send_change_user_packet()
--echo #
--echo # Note: If connection used cleartext directly (no auth switch), it would fail
--echo # due to libmariadb's 255-byte limit in send_change_user_packet()
--echo #
--let $change_pwd=`SELECT REPEAT('c', 260)`
eval CREATE USER changeuserlongpwd IDENTIFIED VIA cleartext_plugin_server USING '$change_pwd';
GRANT ALL ON *.* TO changeuserlongpwd;

change_user changeuserlongpwd,$change_pwd,mdev38550_db;
SELECT DATABASE() AS db;
change_user root;

--echo #
--echo # Test 3: COM_CHANGE_USER with long password - no auth switch
--echo # Connection uses cleartext directly, password goes in first packet
--echo # Requires LENENC support in both client and server for COM_CHANGE_USER
--echo #
--connect (cleartext_con, 127.0.0.1, changeuserlongpwd, $change_pwd, mdev38550_db, $MASTER_MYPORT, , , mysql_clear_password)
SELECT DATABASE() AS db;
SELECT CURRENT_USER() AS user;
change_user changeuserlongpwd,$change_pwd,mdev38550_db;
SELECT DATABASE() AS db;
--connection default
--disconnect cleartext_con

--echo #
--echo # Cleanup
--echo #
DROP USER changeusertest, changeuserlongpwd;
DROP DATABASE mdev38550_db;
28 changes: 24 additions & 4 deletions sql/sql_acl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13613,10 +13613,30 @@ static bool parse_com_change_user_packet(MPVIO_EXT *mpvio, uint packet_length)
Cast *passwd to an unsigned char, so that it doesn't extend the sign for
*passwd > 127 and become 2**32-127+ after casting to uint.
*/
uint passwd_len= (thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
(uchar) (*passwd++) : (uint)strlen(passwd));

db+= passwd_len + 1;
size_t passwd_len;
if (!(thd->client_capabilities & CLIENT_SECURE_CONNECTION))
{
passwd_len= strlen(passwd);
db= passwd + passwd_len + 1; /* +1 to skip null terminator */
}
else if (!(thd->client_capabilities & CLIENT_PLUGIN_AUTH_LENENC_CLIENT_DATA))
{
passwd_len= (uchar)(*passwd++);
db= passwd + passwd_len;
}
else
{
ulonglong len= safe_net_field_length_ll((uchar**)&passwd,
end - passwd);
if (len > packet_length)
{
my_message(ER_UNKNOWN_COM_ERROR, ER_THD(thd, ER_UNKNOWN_COM_ERROR),
MYF(0));
DBUG_RETURN(1);
}
passwd_len= (size_t)len;
db= passwd + passwd_len;
}
/*
Database name is always NUL-terminated, so in case of empty database
the packet must contain at least the trailing '\0'.
Expand Down