From 71966c7306d6ae24bc052d5433e6d97cc81a436a Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Fri, 26 Nov 2021 18:41:35 +0100 Subject: MDEV-26713 allow users with non-UTF8 passwords to login after upgrade. Translate username, password and database from UTF8 into desired charset, if non-auto default-character-set was used, on Windows10 1903 This change is implemented only in the command line client, and mainly to allow users with non-UTF8 passwords to login. The user is supposed to use the same charset that was used during setting password (usually, console CP if used in CLI) Add a test to document the behavior. --- client/mysql.cc | 44 +++++++++++++++++++++++ mysql-test/main/charset_client_win_utf8mb4.result | 4 +++ mysql-test/main/charset_client_win_utf8mb4.test | 19 ++++++++++ 3 files changed, 67 insertions(+) diff --git a/client/mysql.cc b/client/mysql.cc index d15a5ebdb40..49e6d29e964 100644 --- a/client/mysql.cc +++ b/client/mysql.cc @@ -1442,6 +1442,46 @@ sig_handler mysql_end(int sig) exit(status.exit_status); } +#ifdef _WIN32 +#define CNV_BUFSIZE 1024 + +/** + Convert user,database,and password to requested charset. + + This is done in the single case when user connects with non-UTF8 + default-character-set, on UTF8 capable Windows. + + User, password, and database are UTF8 encoded, prior to the function, + this needs to be fixed, in case they contain non-ASCIIs. + + Mostly a workaround, to allow existng users with non-ASCII password + to survive upgrade without losing connectivity. +*/ +static void maybe_convert_charset(const char **user, const char **password, + const char **database, const char *csname) +{ + if (GetACP() != CP_UTF8 || !strncmp(csname, "utf8", 4)) + return; + static char bufs[3][CNV_BUFSIZE]; + const char **from[]= {user, password, database}; + CHARSET_INFO *cs= get_charset_by_csname(csname, MY_CS_PRIMARY, + MYF(MY_UTF8_IS_UTF8MB3 | MY_WME)); + if (!cs) + return; + for (int i= 0; i < 3; i++) + { + const char *str= *from[i]; + if (!str) + continue; + uint errors; + uint len= my_convert(bufs[i], CNV_BUFSIZE, cs, str, (uint32) strlen(str), + &my_charset_utf8mb4_bin, &errors); + bufs[i][len]= 0; + *from[i]= bufs[i]; + } +} +#endif + /* set connection-specific options and call mysql_real_connect */ @@ -1473,6 +1513,10 @@ static bool do_connect(MYSQL *mysql, const char *host, const char *user, mysql_options(mysql, MYSQL_OPT_CONNECT_ATTR_RESET, 0); mysql_options4(mysql, MYSQL_OPT_CONNECT_ATTR_ADD, "program_name", "mysql"); +#ifdef _WIN32 + maybe_convert_charset(&user, &password, &database,default_charset); +#endif + return mysql_real_connect(mysql, host, user, password, database, opt_mysql_port, opt_mysql_unix_port, flags); } diff --git a/mysql-test/main/charset_client_win_utf8mb4.result b/mysql-test/main/charset_client_win_utf8mb4.result index f7b5d376f9a..9bbf751e45c 100644 --- a/mysql-test/main/charset_client_win_utf8mb4.result +++ b/mysql-test/main/charset_client_win_utf8mb4.result @@ -1,2 +1,6 @@ @@character_set_client utf8mb4 +ERROR 1045 (28000): Access denied for user 'u'@'localhost' (using password: YES) +2 +2 +DROP user u; diff --git a/mysql-test/main/charset_client_win_utf8mb4.test b/mysql-test/main/charset_client_win_utf8mb4.test index 2baf0d7c050..e08afa250bd 100644 --- a/mysql-test/main/charset_client_win_utf8mb4.test +++ b/mysql-test/main/charset_client_win_utf8mb4.test @@ -1,3 +1,22 @@ --source include/windows.inc --source include/check_utf8_cli.inc --exec $MYSQL --default-character-set=auto -e "select @@character_set_client" + +# Test that a user with old, non-UTF8 password can still connect +# by setting setting non-auto --default-character-set +# This is important for backward compatibility + +# Emulate creating password in an interactive client session, with older clients +# which communicates with the server using with something like cp850 + +exec chcp 850 > NUL && echo CREATE USER 'u' IDENTIFIED by 'ü' | $MYSQL --default-character-set=cp850; + + +# Can't connect with UTF8 +--error 1 +exec $MYSQL --default-character-set=auto --user=u --password=ü -e "select 1" 2>&1; + +# Can connect with tweaked --default-character-set +exec $MYSQL --default-character-set=cp850 --user=u --password=ü -e "select 2"; +DROP user u; + -- cgit v1.2.1