From 9e9b211f22e4130b886188ca6252ffdedfa55ef5 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Fri, 10 Dec 2021 23:35:04 +0100 Subject: [PATCH] MDEV-27089 Windows : incorrect handling of non-ASCIIs in get_tty_password Prior to patch, get_password would echo multple mask characters '*', for a single multibyte input character. Fixed the behavior by using "wide" version of getch, _getwch. Also take care of possible characters outside of BMP (i.e we do not print '*' for high surrogates). The function will now internally construct the "wide" password string, and conver to the console codepage. Some characters could still be lost in that conversion, unless the codepage is utf8, but this is not any new bug. --- mysys/get_password.c | 55 +++++++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 16 deletions(-) diff --git a/mysys/get_password.c b/mysys/get_password.c index 24befa6b5df00..bdd20d0349b34 100644 --- a/mysys/get_password.c +++ b/mysys/get_password.c @@ -62,35 +62,58 @@ char *get_tty_password(const char *opt_message) { - char to[80]; - char *pos=to,*end=to+sizeof(to)-1; + wchar_t wbuf[80]; + char *to; + int to_len; + UINT cp; + wchar_t *pos=wbuf,*end=wbuf + array_elements(wbuf)-1; DBUG_ENTER("get_tty_password"); _cputs(opt_message ? opt_message : "Enter password: "); for (;;) { - char tmp; - tmp=_getch(); - if (tmp == '\b' || (int) tmp == 127) + int wc; + wc=_getwch(); + if (wc == '\b' || wc == 127) { - if (pos != to) + if (pos != wbuf) { - _cputs("\b \b"); - pos--; - continue; + _cputs("\b \b"); + pos--; + continue; } } - if (tmp == '\n' || tmp == '\r' || tmp == 3) + if (wc == '\n' || wc == '\r' || wc == 3 || pos == end) break; - if (iscntrl(tmp) || pos == end) + if (iswcntrl(wc)) continue; - _cputs("*"); - *(pos++) = tmp; + + /* Do not print '*' for half-unicode char(high surrogate)*/ + if (wc < 0xD800 || wc > 0xDBFF) + { + _cputs("*"); + } + *(pos++)= (wchar_t)wc; } - while (pos != to && isspace(pos[-1]) == ' ') - pos--; /* Allow dummy space at end */ *pos=0; _cputs("\n"); - DBUG_RETURN(my_strdup(PSI_INSTRUMENT_ME, to,MYF(MY_FAE))); + + /* + Allocate output string, and convert UTF16 password to output codepage. + */ + cp= GetConsoleCP(); + + if (!(to_len= WideCharToMultiByte(cp, 0, wbuf, -1, NULL, 0, NULL, NULL))) + DBUG_RETURN(NULL); + + if (!(to= my_malloc(PSI_INSTRUMENT_ME, to_len, MYF(MY_FAE)))) + DBUG_RETURN(NULL); + + if (!WideCharToMultiByte(cp, 0, wbuf, -1, to, to_len, NULL, NULL)) + { + my_free(to); + DBUG_RETURN(NULL); + } + DBUG_RETURN(to); } #else