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)
{
int current_index = 0;
char ch;
int utf8_read = 0;
char utf8_char[4];
wchar_t ch;
wchar_t* wtmp = NULL;
if (outBufLen == 0) {
@ -1210,7 +1212,7 @@ readpassphrase(const char *prompt, char *outBuf, size_t outBufLen, int flags)
return NULL;
}
while (_kbhit()) _getch();
while (_kbhit()) _getwch();
wtmp = utf8_to_utf16(prompt);
if (wtmp == NULL)
@ -1220,36 +1222,51 @@ readpassphrase(const char *prompt, char *outBuf, size_t outBufLen, int flags)
free(wtmp);
while (current_index < (int)outBufLen - 1) {
ch = _getch();
ch = _getwch();
if (ch == '\r') {
if (_kbhit()) _getch(); /* read linefeed if its there */
if (ch == L'\r') {
if (_kbhit()) _getwch(); /* read linefeed if its there */
break;
} else if (ch == '\n') {
} else if (ch == L'\n') {
break;
} else if (ch == '\b') { /* backspace */
} else if (ch == L'\b') { /* backspace */
if (current_index > 0) {
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("");
} else {
if (flags & RPP_SEVENBIT)
ch &= 0x7f;
if (isalpha((unsigned char)ch)) {
if (iswalpha(ch)) {
if(flags & RPP_FORCELOWER)
ch = tolower((unsigned char)ch);
ch = towlower(ch);
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)
printf_s("%c", ch);
wprintf_s(L"%c", ch);
}
}
@ -1710,186 +1727,186 @@ build_exec_command(const char * command)
return cmd_sp;
}
/*
* cmd is internally decoarated with a set of '"'
* to account for any spaces within the commandline
* the double quotes and backslash is escaped if needed
* this decoration is done only when additional arguments are passed in argv
*/
char *
build_commandline_string(const char* cmd, char *const argv[], BOOLEAN prepend_module_path)
{
char *cmdline, *t, *tmp = NULL, *path = NULL, *ret = NULL;
char * const *t1;
DWORD cmdline_len = 0, path_len = 0;
int add_module_path = 0;
if (!cmd) {
error("%s invalid argument cmd:%s", __func__, cmd);
return NULL;
}
if (!(path = _strdup(cmd))) {
error("failed to duplicate %s", cmd);
return NULL;
}
path_len = (DWORD)strlen(path);
if (is_bash_test_env()) {
memset(path, 0, path_len + 1);
bash_to_win_path(cmd, path, path_len + 1);
path_len = (DWORD)strlen(path);
}
if (!is_absolute_path(path) && prepend_module_path)
add_module_path = 1;
/* compute total cmdline len*/
if (add_module_path)
cmdline_len += (DWORD)strlen(__progdir) + 1 + (DWORD)strlen(path) + 1 + 2;
else
cmdline_len += (DWORD)strlen(path) + 1 + 2;
if (argv) {
t1 = argv;
while (*t1) {
char *p = *t1++;
for (int i = 0; i < (int)strlen(p); i++) {
if (p[i] == '\\') {
char * b = p + i;
int additional_backslash = 0;
int backslash_count = 0;
/*
Backslashes are interpreted literally, unless they immediately
precede a double quotation mark.
*/
while (b != NULL && *b == '\\') {
backslash_count++;
b++;
if (b != NULL && *b == '\"') {
additional_backslash = 1;
break;
}
}
cmdline_len += backslash_count * (additional_backslash + 1);
i += backslash_count - 1;
}
else if (p[i] == '\"')
/* backslash will be added for every double quote.*/
cmdline_len += 2;
else
cmdline_len++;
}
cmdline_len += 1 + 2; /*for "around cmd arg and traling space*/
}
}
if ((cmdline = malloc(cmdline_len)) == NULL) {
errno = ENOMEM;
goto cleanup;
}
t = cmdline;
*t++ = '\"';
if (add_module_path) {
/* add current module path to start if needed */
memcpy(t, __progdir, strlen(__progdir));
t += strlen(__progdir);
*t++ = '\\';
}
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().
* 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
* to the CreateProcess() otherwise CreateProcess() will fail with error code 2.
*/
if (strstr(path, ".exe") && (tmp = strstr(strstr(path, ".exe"), " ")))
{
size_t tmp_pos = tmp - path;
memcpy(t, path, tmp_pos);
t += tmp_pos;
*t++ = '\"';
memcpy(t, tmp, strlen(path) - tmp_pos);
t += (strlen(path) - tmp_pos);
}
else {
memcpy(t, path, path_len);
t += path_len;
*t++ = '\"';
}
}
else {
/*path already contains "*/
memcpy(t, path + 1, path_len - 1);
t += path_len - 1;
}
*t = '\0';
t = cmdline + strlen(cmdline);
if (argv) {
t1 = argv;
while (*t1) {
*t++ = ' ';
char * p1 = *t1++;
BOOL add_quotes = FALSE;
/* leave as is if the command is surrounded by single quotes*/
if (p1[0] != '\'')
for (int i = 0; i < (int)strlen(p1); i++) {
if (p1[i] == ' ') {
add_quotes = TRUE;
break;
}
}
if (add_quotes)
*t++ = '\"';
for (int i = 0; i < (int)strlen(p1); i++) {
if (p1[i] == '\\') {
char * b = p1 + i;
int additional_backslash = 0;
int backslash_count = 0;
/*
* Backslashes are interpreted literally, unless they immediately
* precede a double quotation mark.
*/
while (b != NULL && *b == '\\') {
backslash_count++;
b++;
if (b != NULL && *b == '\"') {
additional_backslash = 1;
break;
}
}
i += backslash_count - 1;
int escaped_backslash_count = backslash_count * (additional_backslash + 1);
while (escaped_backslash_count--)
*t++ = '\\';
}
else if (p1[i] == '\"') {
/* Add backslash for every double quote.*/
*t++ = '\\';
*t++ = '\"';
}
else
*t++ = p1[i];
}
if (add_quotes)
*t++ = '\"';
}
}
*t = '\0';
ret = cmdline;
cmdline = NULL;
cleanup:
if (path)
free(path);
if (cmdline)
free(cmdline);
return ret;
}
/*
* cmd is internally decoarated with a set of '"'
* to account for any spaces within the commandline
* the double quotes and backslash is escaped if needed
* this decoration is done only when additional arguments are passed in argv
*/
char *
build_commandline_string(const char* cmd, char *const argv[], BOOLEAN prepend_module_path)
{
char *cmdline, *t, *tmp = NULL, *path = NULL, *ret = NULL;
char * const *t1;
DWORD cmdline_len = 0, path_len = 0;
int add_module_path = 0;
if (!cmd) {
error("%s invalid argument cmd:%s", __func__, cmd);
return NULL;
}
if (!(path = _strdup(cmd))) {
error("failed to duplicate %s", cmd);
return NULL;
}
path_len = (DWORD)strlen(path);
if (is_bash_test_env()) {
memset(path, 0, path_len + 1);
bash_to_win_path(cmd, path, path_len + 1);
path_len = (DWORD)strlen(path);
}
if (!is_absolute_path(path) && prepend_module_path)
add_module_path = 1;
/* compute total cmdline len*/
if (add_module_path)
cmdline_len += (DWORD)strlen(__progdir) + 1 + (DWORD)strlen(path) + 1 + 2;
else
cmdline_len += (DWORD)strlen(path) + 1 + 2;
if (argv) {
t1 = argv;
while (*t1) {
char *p = *t1++;
for (int i = 0; i < (int)strlen(p); i++) {
if (p[i] == '\\') {
char * b = p + i;
int additional_backslash = 0;
int backslash_count = 0;
/*
Backslashes are interpreted literally, unless they immediately
precede a double quotation mark.
*/
while (b != NULL && *b == '\\') {
backslash_count++;
b++;
if (b != NULL && *b == '\"') {
additional_backslash = 1;
break;
}
}
cmdline_len += backslash_count * (additional_backslash + 1);
i += backslash_count - 1;
}
else if (p[i] == '\"')
/* backslash will be added for every double quote.*/
cmdline_len += 2;
else
cmdline_len++;
}
cmdline_len += 1 + 2; /*for "around cmd arg and traling space*/
}
}
if ((cmdline = malloc(cmdline_len)) == NULL) {
errno = ENOMEM;
goto cleanup;
}
t = cmdline;
*t++ = '\"';
if (add_module_path) {
/* add current module path to start if needed */
memcpy(t, __progdir, strlen(__progdir));
t += strlen(__progdir);
*t++ = '\\';
}
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().
* 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
* to the CreateProcess() otherwise CreateProcess() will fail with error code 2.
*/
if (strstr(path, ".exe") && (tmp = strstr(strstr(path, ".exe"), " ")))
{
size_t tmp_pos = tmp - path;
memcpy(t, path, tmp_pos);
t += tmp_pos;
*t++ = '\"';
memcpy(t, tmp, strlen(path) - tmp_pos);
t += (strlen(path) - tmp_pos);
}
else {
memcpy(t, path, path_len);
t += path_len;
*t++ = '\"';
}
}
else {
/*path already contains "*/
memcpy(t, path + 1, path_len - 1);
t += path_len - 1;
}
*t = '\0';
t = cmdline + strlen(cmdline);
if (argv) {
t1 = argv;
while (*t1) {
*t++ = ' ';
char * p1 = *t1++;
BOOL add_quotes = FALSE;
/* leave as is if the command is surrounded by single quotes*/
if (p1[0] != '\'')
for (int i = 0; i < (int)strlen(p1); i++) {
if (p1[i] == ' ') {
add_quotes = TRUE;
break;
}
}
if (add_quotes)
*t++ = '\"';
for (int i = 0; i < (int)strlen(p1); i++) {
if (p1[i] == '\\') {
char * b = p1 + i;
int additional_backslash = 0;
int backslash_count = 0;
/*
* Backslashes are interpreted literally, unless they immediately
* precede a double quotation mark.
*/
while (b != NULL && *b == '\\') {
backslash_count++;
b++;
if (b != NULL && *b == '\"') {
additional_backslash = 1;
break;
}
}
i += backslash_count - 1;
int escaped_backslash_count = backslash_count * (additional_backslash + 1);
while (escaped_backslash_count--)
*t++ = '\\';
}
else if (p1[i] == '\"') {
/* Add backslash for every double quote.*/
*t++ = '\\';
*t++ = '\"';
}
else
*t++ = p1[i];
}
if (add_quotes)
*t++ = '\"';
}
}
*t = '\0';
ret = cmdline;
cmdline = NULL;
cleanup:
if (path)
free(path);
if (cmdline)
free(cmdline);
return ret;
}
BOOL
is_bash_test_env()