Allow Use Of Non-ASCII Character In SSH Client Passwords (#322)

* Allow Use Of Non-ASCII Character In SSH Client Passwords
This commit is contained in:
Bryan Berns 2019-12-12 17:33:05 -05:00 committed by bagajjal
parent 17c9c6dbb3
commit 7dd58ed31f
1 changed files with 212 additions and 195 deletions

View File

@ -1202,7 +1202,9 @@ char *
readpassphrase(const char *prompt, char *outBuf, size_t outBufLen, int flags) readpassphrase(const char *prompt, char *outBuf, size_t outBufLen, int flags)
{ {
int current_index = 0; int current_index = 0;
char ch; int utf8_read = 0;
char utf8_char[4];
wchar_t ch;
wchar_t* wtmp = NULL; wchar_t* wtmp = NULL;
if (outBufLen == 0) { if (outBufLen == 0) {
@ -1210,7 +1212,7 @@ readpassphrase(const char *prompt, char *outBuf, size_t outBufLen, int flags)
return NULL; return NULL;
} }
while (_kbhit()) _getch(); while (_kbhit()) _getwch();
wtmp = utf8_to_utf16(prompt); wtmp = utf8_to_utf16(prompt);
if (wtmp == NULL) if (wtmp == NULL)
@ -1220,36 +1222,51 @@ readpassphrase(const char *prompt, char *outBuf, size_t outBufLen, int flags)
free(wtmp); free(wtmp);
while (current_index < (int)outBufLen - 1) { while (current_index < (int)outBufLen - 1) {
ch = _getch(); ch = _getwch();
if (ch == '\r') { if (ch == L'\r') {
if (_kbhit()) _getch(); /* read linefeed if its there */ if (_kbhit()) _getwch(); /* read linefeed if its there */
break; break;
} else if (ch == '\n') { } else if (ch == L'\n') {
break; break;
} else if (ch == '\b') { /* backspace */ } else if (ch == L'\b') { /* backspace */
if (current_index > 0) { if (current_index > 0) {
if (flags & RPP_ECHO_ON) if (flags & RPP_ECHO_ON)
printf_s("%c \b", ch); wprintf_s(L"%c \b", ch);
current_index--; /* overwrite last character */ /* overwrite last character - remove any utf8 extended chars */
while (current_index > 0 && (outBuf[current_index - 1] & 0xC0) == 0x80)
current_index--;
/* overwrite last character - remove first utf8 byte */
if (current_index > 0)
current_index--;
} }
} else if (ch == '\003') { /* exit on Ctrl+C */ } else if (ch == L'\003') { /* exit on Ctrl+C */
fatal(""); fatal("");
} else { } else {
if (flags & RPP_SEVENBIT) if (flags & RPP_SEVENBIT)
ch &= 0x7f; ch &= 0x7f;
if (isalpha((unsigned char)ch)) { if (iswalpha(ch)) {
if(flags & RPP_FORCELOWER) if(flags & RPP_FORCELOWER)
ch = tolower((unsigned char)ch); ch = towlower(ch);
if(flags & RPP_FORCEUPPER) if(flags & RPP_FORCEUPPER)
ch = toupper((unsigned char)ch); ch = towupper(ch);
} }
outBuf[current_index++] = ch; /* convert unicode to utf8 characters */
int utf8_char_size = sizeof(utf8_char);
if ((utf8_read = WideCharToMultiByte(CP_UTF8, 0, &ch, 1, utf8_char, sizeof(utf8_char), NULL, NULL)) == 0)
fatal("character conversion failed");
/* append to output buffer if the characters fit */
if (current_index + utf8_read >= outBufLen - 1) break;
memcpy(&outBuf[current_index], utf8_char, utf8_read);
current_index += utf8_read;
if(flags & RPP_ECHO_ON) if(flags & RPP_ECHO_ON)
printf_s("%c", ch); wprintf_s(L"%c", ch);
} }
} }
@ -1710,186 +1727,186 @@ build_exec_command(const char * command)
return cmd_sp; return cmd_sp;
} }
/* /*
* cmd is internally decoarated with a set of '"' * cmd is internally decoarated with a set of '"'
* to account for any spaces within the commandline * to account for any spaces within the commandline
* the double quotes and backslash is escaped if needed * the double quotes and backslash is escaped if needed
* this decoration is done only when additional arguments are passed in argv * this decoration is done only when additional arguments are passed in argv
*/ */
char * char *
build_commandline_string(const char* cmd, char *const argv[], BOOLEAN prepend_module_path) build_commandline_string(const char* cmd, char *const argv[], BOOLEAN prepend_module_path)
{ {
char *cmdline, *t, *tmp = NULL, *path = NULL, *ret = NULL; char *cmdline, *t, *tmp = NULL, *path = NULL, *ret = NULL;
char * const *t1; char * const *t1;
DWORD cmdline_len = 0, path_len = 0; DWORD cmdline_len = 0, path_len = 0;
int add_module_path = 0; int add_module_path = 0;
if (!cmd) { if (!cmd) {
error("%s invalid argument cmd:%s", __func__, cmd); error("%s invalid argument cmd:%s", __func__, cmd);
return NULL; return NULL;
} }
if (!(path = _strdup(cmd))) { if (!(path = _strdup(cmd))) {
error("failed to duplicate %s", cmd); error("failed to duplicate %s", cmd);
return NULL; return NULL;
} }
path_len = (DWORD)strlen(path); path_len = (DWORD)strlen(path);
if (is_bash_test_env()) { if (is_bash_test_env()) {
memset(path, 0, path_len + 1); memset(path, 0, path_len + 1);
bash_to_win_path(cmd, path, path_len + 1); bash_to_win_path(cmd, path, path_len + 1);
path_len = (DWORD)strlen(path); path_len = (DWORD)strlen(path);
} }
if (!is_absolute_path(path) && prepend_module_path) if (!is_absolute_path(path) && prepend_module_path)
add_module_path = 1; add_module_path = 1;
/* compute total cmdline len*/ /* compute total cmdline len*/
if (add_module_path) if (add_module_path)
cmdline_len += (DWORD)strlen(__progdir) + 1 + (DWORD)strlen(path) + 1 + 2; cmdline_len += (DWORD)strlen(__progdir) + 1 + (DWORD)strlen(path) + 1 + 2;
else else
cmdline_len += (DWORD)strlen(path) + 1 + 2; cmdline_len += (DWORD)strlen(path) + 1 + 2;
if (argv) { if (argv) {
t1 = argv; t1 = argv;
while (*t1) { while (*t1) {
char *p = *t1++; char *p = *t1++;
for (int i = 0; i < (int)strlen(p); i++) { for (int i = 0; i < (int)strlen(p); i++) {
if (p[i] == '\\') { if (p[i] == '\\') {
char * b = p + i; char * b = p + i;
int additional_backslash = 0; int additional_backslash = 0;
int backslash_count = 0; int backslash_count = 0;
/* /*
Backslashes are interpreted literally, unless they immediately Backslashes are interpreted literally, unless they immediately
precede a double quotation mark. precede a double quotation mark.
*/ */
while (b != NULL && *b == '\\') { while (b != NULL && *b == '\\') {
backslash_count++; backslash_count++;
b++; b++;
if (b != NULL && *b == '\"') { if (b != NULL && *b == '\"') {
additional_backslash = 1; additional_backslash = 1;
break; break;
} }
} }
cmdline_len += backslash_count * (additional_backslash + 1); cmdline_len += backslash_count * (additional_backslash + 1);
i += backslash_count - 1; i += backslash_count - 1;
} }
else if (p[i] == '\"') else if (p[i] == '\"')
/* backslash will be added for every double quote.*/ /* backslash will be added for every double quote.*/
cmdline_len += 2; cmdline_len += 2;
else else
cmdline_len++; cmdline_len++;
} }
cmdline_len += 1 + 2; /*for "around cmd arg and traling space*/ cmdline_len += 1 + 2; /*for "around cmd arg and traling space*/
} }
} }
if ((cmdline = malloc(cmdline_len)) == NULL) { if ((cmdline = malloc(cmdline_len)) == NULL) {
errno = ENOMEM; errno = ENOMEM;
goto cleanup; goto cleanup;
} }
t = cmdline; t = cmdline;
*t++ = '\"'; *t++ = '\"';
if (add_module_path) { if (add_module_path) {
/* add current module path to start if needed */ /* add current module path to start if needed */
memcpy(t, __progdir, strlen(__progdir)); memcpy(t, __progdir, strlen(__progdir));
t += strlen(__progdir); t += strlen(__progdir);
*t++ = '\\'; *t++ = '\\';
} }
if (path[0] != '\"') { if (path[0] != '\"') {
/* If path is <executable_path> <arg> then we should add double quotes after <executable_path> i.e., "<executable_path>" <arg> should be passed to CreateProcess(). /* If path is <executable_path> <arg> then we should add double quotes after <executable_path> i.e., "<executable_path>" <arg> should be passed to CreateProcess().
* Example - If path is C:\cygwin64\bin\bash.exe /cygdrive/e/openssh-portable-latestw_all/openssh-portable/regress/scp-ssh-wrapper.sh then * Example - If path is C:\cygwin64\bin\bash.exe /cygdrive/e/openssh-portable-latestw_all/openssh-portable/regress/scp-ssh-wrapper.sh then
* we should pass "C:\cygwin64\bin\bash.exe" /cygdrive/e/openssh-portable-latestw_all/openssh-portable/regress/scp-ssh-wrapper.sh * we should pass "C:\cygwin64\bin\bash.exe" /cygdrive/e/openssh-portable-latestw_all/openssh-portable/regress/scp-ssh-wrapper.sh
* to the CreateProcess() otherwise CreateProcess() will fail with error code 2. * to the CreateProcess() otherwise CreateProcess() will fail with error code 2.
*/ */
if (strstr(path, ".exe") && (tmp = strstr(strstr(path, ".exe"), " "))) if (strstr(path, ".exe") && (tmp = strstr(strstr(path, ".exe"), " ")))
{ {
size_t tmp_pos = tmp - path; size_t tmp_pos = tmp - path;
memcpy(t, path, tmp_pos); memcpy(t, path, tmp_pos);
t += tmp_pos; t += tmp_pos;
*t++ = '\"'; *t++ = '\"';
memcpy(t, tmp, strlen(path) - tmp_pos); memcpy(t, tmp, strlen(path) - tmp_pos);
t += (strlen(path) - tmp_pos); t += (strlen(path) - tmp_pos);
} }
else { else {
memcpy(t, path, path_len); memcpy(t, path, path_len);
t += path_len; t += path_len;
*t++ = '\"'; *t++ = '\"';
} }
} }
else { else {
/*path already contains "*/ /*path already contains "*/
memcpy(t, path + 1, path_len - 1); memcpy(t, path + 1, path_len - 1);
t += path_len - 1; t += path_len - 1;
} }
*t = '\0'; *t = '\0';
t = cmdline + strlen(cmdline); t = cmdline + strlen(cmdline);
if (argv) { if (argv) {
t1 = argv; t1 = argv;
while (*t1) { while (*t1) {
*t++ = ' '; *t++ = ' ';
char * p1 = *t1++; char * p1 = *t1++;
BOOL add_quotes = FALSE; BOOL add_quotes = FALSE;
/* leave as is if the command is surrounded by single quotes*/ /* leave as is if the command is surrounded by single quotes*/
if (p1[0] != '\'') if (p1[0] != '\'')
for (int i = 0; i < (int)strlen(p1); i++) { for (int i = 0; i < (int)strlen(p1); i++) {
if (p1[i] == ' ') { if (p1[i] == ' ') {
add_quotes = TRUE; add_quotes = TRUE;
break; break;
} }
} }
if (add_quotes) if (add_quotes)
*t++ = '\"'; *t++ = '\"';
for (int i = 0; i < (int)strlen(p1); i++) { for (int i = 0; i < (int)strlen(p1); i++) {
if (p1[i] == '\\') { if (p1[i] == '\\') {
char * b = p1 + i; char * b = p1 + i;
int additional_backslash = 0; int additional_backslash = 0;
int backslash_count = 0; int backslash_count = 0;
/* /*
* Backslashes are interpreted literally, unless they immediately * Backslashes are interpreted literally, unless they immediately
* precede a double quotation mark. * precede a double quotation mark.
*/ */
while (b != NULL && *b == '\\') { while (b != NULL && *b == '\\') {
backslash_count++; backslash_count++;
b++; b++;
if (b != NULL && *b == '\"') { if (b != NULL && *b == '\"') {
additional_backslash = 1; additional_backslash = 1;
break; break;
} }
} }
i += backslash_count - 1; i += backslash_count - 1;
int escaped_backslash_count = backslash_count * (additional_backslash + 1); int escaped_backslash_count = backslash_count * (additional_backslash + 1);
while (escaped_backslash_count--) while (escaped_backslash_count--)
*t++ = '\\'; *t++ = '\\';
} }
else if (p1[i] == '\"') { else if (p1[i] == '\"') {
/* Add backslash for every double quote.*/ /* Add backslash for every double quote.*/
*t++ = '\\'; *t++ = '\\';
*t++ = '\"'; *t++ = '\"';
} }
else else
*t++ = p1[i]; *t++ = p1[i];
} }
if (add_quotes) if (add_quotes)
*t++ = '\"'; *t++ = '\"';
} }
} }
*t = '\0'; *t = '\0';
ret = cmdline; ret = cmdline;
cmdline = NULL; cmdline = NULL;
cleanup: cleanup:
if (path) if (path)
free(path); free(path);
if (cmdline) if (cmdline)
free(cmdline); free(cmdline);
return ret; return ret;
} }
BOOL BOOL
is_bash_test_env() is_bash_test_env()