From f80a467c2015f05e36d298c7073cc7a3c4704d1e Mon Sep 17 00:00:00 2001 From: Manoj Ampalam Date: Wed, 15 Feb 2017 21:32:50 -0800 Subject: [PATCH] Multiple Fixes (#82) PowerShell/Win32-OpenSSH#524 PowerShell/Win32-OpenSSH#518 PowerShell/Win32-OpenSSH#517 --- contrib/win32/openssh/Win32-OpenSSH.sln | 3 +- contrib/win32/openssh/config.h.vs | 1 + contrib/win32/openssh/ssh-shellhost.vcxproj | 10 ++- contrib/win32/openssh/win32iocompat.vcxproj | 1 + .../openssh/win32iocompat.vcxproj.filters | 1 + contrib/win32/win32compat/misc.c | 28 +------ contrib/win32/win32compat/shell-host.c | 80 ++++++++++++------- .../win32compat/ssh-agent/authagent-request.c | 2 +- contrib/win32/win32compat/utf.c | 59 ++++++++++++++ session.c | 22 ++++- 10 files changed, 141 insertions(+), 66 deletions(-) create mode 100644 contrib/win32/win32compat/utf.c diff --git a/contrib/win32/openssh/Win32-OpenSSH.sln b/contrib/win32/openssh/Win32-OpenSSH.sln index c73130587..3d860fea9 100644 --- a/contrib/win32/openssh/Win32-OpenSSH.sln +++ b/contrib/win32/openssh/Win32-OpenSSH.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.25123.0 +VisualStudioVersion = 14.0.23107.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ssh", "ssh.vcxproj", "{74E69D5E-A1EF-46EA-9173-19A412774104}" ProjectSection(ProjectDependencies) = postProject @@ -68,6 +68,7 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ssh-shellhost", "ssh-shellhost.vcxproj", "{C0AE8A30-E4FA-49CE-A2B5-0C072C77EC64}" ProjectSection(ProjectDependencies) = postProject {8F9D3B74-8D33-448E-9762-26E8DCC6B2F4} = {8F9D3B74-8D33-448E-9762-26E8DCC6B2F4} + {DD483F7D-C553-4740-BC1A-903805AD0174} = {DD483F7D-C553-4740-BC1A-903805AD0174} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ssh-agent", "ssh-agent.vcxproj", "{F6644EC5-D6B6-42A1-828C-75E2977470E0}" diff --git a/contrib/win32/openssh/config.h.vs b/contrib/win32/openssh/config.h.vs index c6b3b86c0..b4d487838 100644 --- a/contrib/win32/openssh/config.h.vs +++ b/contrib/win32/openssh/config.h.vs @@ -1673,6 +1673,7 @@ #define HAVE_DECL_HOWMANY 0 #define HAVE_STRTOULL 1 #define HAVE_USLEEP 1 +#define HAVE_EVP_RIPEMD160 1 #if defined ( WIN32 ) #define __func__ __FUNCTION__ diff --git a/contrib/win32/openssh/ssh-shellhost.vcxproj b/contrib/win32/openssh/ssh-shellhost.vcxproj index 5c8ac5f82..d43161847 100644 --- a/contrib/win32/openssh/ssh-shellhost.vcxproj +++ b/contrib/win32/openssh/ssh-shellhost.vcxproj @@ -21,6 +21,7 @@ + @@ -113,7 +114,7 @@ Console true - kernel32.lib;user32.lib;%(AdditionalDependencies) + openbsd_compat.lib;kernel32.lib;user32.lib;%(AdditionalDependencies) $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-Win32-Debug-Path)lib;%(AdditionalLibraryDirectories) @@ -133,7 +134,7 @@ Console true - kernel32.lib;user32.lib;%(AdditionalDependencies) + openbsd_compat.lib;kernel32.lib;user32.lib;%(AdditionalDependencies) $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-x64-Debug-Path)lib;%(AdditionalLibraryDirectories) @@ -156,7 +157,7 @@ true true true - kernel32.lib;user32.lib;%(AdditionalDependencies) + openbsd_compat.lib;kernel32.lib;user32.lib;%(AdditionalDependencies) $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-Win32-Release-Path)lib;%(AdditionalLibraryDirectories) true No @@ -181,9 +182,10 @@ true true true - kernel32.lib;user32.lib;%(AdditionalDependencies) + openbsd_compat.lib;kernel32.lib;user32.lib;%(AdditionalDependencies) true No + $(OpenSSH-Lib-Path)$(Platform)\$(Configuration);$(OpenSSL-x64-Release-Path)lib;%(AdditionalLibraryDirectories) diff --git a/contrib/win32/openssh/win32iocompat.vcxproj b/contrib/win32/openssh/win32iocompat.vcxproj index 741649c2c..6039af70c 100644 --- a/contrib/win32/openssh/win32iocompat.vcxproj +++ b/contrib/win32/openssh/win32iocompat.vcxproj @@ -159,6 +159,7 @@ + diff --git a/contrib/win32/openssh/win32iocompat.vcxproj.filters b/contrib/win32/openssh/win32iocompat.vcxproj.filters index ac34a356d..07a88fa4c 100644 --- a/contrib/win32/openssh/win32iocompat.vcxproj.filters +++ b/contrib/win32/openssh/win32iocompat.vcxproj.filters @@ -18,6 +18,7 @@ + diff --git a/contrib/win32/win32compat/misc.c b/contrib/win32/win32compat/misc.c index 4a58b83df..9e87efa1b 100644 --- a/contrib/win32/win32compat/misc.c +++ b/contrib/win32/win32compat/misc.c @@ -42,6 +42,7 @@ #include "inc\sys\types.h" #include "inc\sys\ioctl.h" #include "inc\fcntl.h" +#include "inc\utf.h" #include "signal_internal.h" static char* s_programdir = NULL; @@ -275,33 +276,6 @@ w32_fopen_utf8(const char *path, const char *mode) return f; } - -wchar_t * -utf8_to_utf16(const char *utf8) -{ - int needed = 0; - wchar_t* utf16 = NULL; - if ((needed = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0)) == 0 || - (utf16 = malloc(needed * sizeof(wchar_t))) == NULL || - MultiByteToWideChar(CP_UTF8, 0, utf8, -1, utf16, needed) == 0) - return NULL; - - return utf16; -} - -char * -utf16_to_utf8(const wchar_t* utf16) -{ - int needed = 0; - char* utf8 = NULL; - if ((needed = WideCharToMultiByte(CP_UTF8, 0, utf16, -1, NULL, 0, NULL, NULL)) == 0 || - (utf8 = malloc(needed)) == NULL || - WideCharToMultiByte(CP_UTF8, 0, utf16, -1, utf8, needed, NULL, NULL) == 0) - return NULL; - - return utf8; -} - char * w32_programdir() { diff --git a/contrib/win32/win32compat/shell-host.c b/contrib/win32/win32compat/shell-host.c index b92e02af1..de8ae2f32 100644 --- a/contrib/win32/win32compat/shell-host.c +++ b/contrib/win32/win32compat/shell-host.c @@ -37,6 +37,7 @@ #include #include #include "misc_internal.h" +#include "inc\utf.h" #define MAX_CONSOLE_COLUMNS 9999 #define MAX_CONSOLE_ROWS 9999 @@ -917,7 +918,7 @@ cleanup: } int -start_with_pty(int ac, wchar_t **av) +start_with_pty(wchar_t *command) { STARTUPINFO si; PROCESS_INFORMATION pi; @@ -974,17 +975,12 @@ start_with_pty(int ac, wchar_t **av) /*TODO - pick this up from system32*/ cmd[0] = L'\0'; - if (ac) - GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_CMD_LEN, L"cmd.exe")); - ac--; - av++; - if (ac) + GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_CMD_LEN, L"cmd.exe")); + + if (command) { GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_CMD_LEN, L" /c")); - while (ac) { GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_CMD_LEN, L" ")); - GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_CMD_LEN, *av)); - ac--; - av++; + GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_CMD_LEN, command)); } SetConsoleCtrlHandler(NULL, FALSE); @@ -1047,7 +1043,7 @@ MonitorChild_nopty( _In_ LPVOID lpParameter) } int -start_withno_pty(int ac, wchar_t **av) +start_withno_pty(wchar_t *command) { STARTUPINFO si; PROCESS_INFORMATION pi; @@ -1083,15 +1079,10 @@ start_withno_pty(int ac, wchar_t **av) /*TODO - pick this up from system32*/ cmd[0] = L'\0'; GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_CMD_LEN, L"cmd.exe")); - ac -= 2; - av += 2; - if (ac) + if (command) { GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_CMD_LEN, L" /c")); - while (ac) { GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_CMD_LEN, L" ")); - GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_CMD_LEN, *av)); - ac--; - av++; + GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_CMD_LEN, command)); } GOTO_CLEANUP_ON_FALSE(CreateProcess(NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)); @@ -1181,20 +1172,51 @@ cleanup: return child_exit_code; } +int b64_pton(char const *src, u_char *target, size_t targsize); + int wmain(int ac, wchar_t **av) { - /* create job to hold all child processes */ - HANDLE job = CreateJobObject(NULL, NULL); - JOBOBJECT_EXTENDED_LIMIT_INFORMATION job_info; - memset(&job_info, 0, sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); - job_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; - if (!SetInformationJobObject(job, JobObjectExtendedLimitInformation, &job_info, sizeof(job_info))) - return -1; - CloseHandle(job); + int pty_requested = 0; + wchar_t *cmd = NULL, *cmd_b64 = NULL; + { + /* create job to hold all child processes */ + HANDLE job = CreateJobObject(NULL, NULL); + JOBOBJECT_EXTENDED_LIMIT_INFORMATION job_info; + memset(&job_info, 0, sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); + job_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; + if (!SetInformationJobObject(job, JobObjectExtendedLimitInformation, &job_info, sizeof(job_info))) + return -1; + CloseHandle(job); + } - if ((ac == 1) || wcscmp(av[1], L"-nopty")) - return start_with_pty(ac, av); + if ((ac == 1) || (ac == 2 && wcscmp(av[1], L"-nopty"))) { + pty_requested = 1; + cmd_b64 = ac == 2? av[1] : NULL; + } else if (ac <= 3 && wcscmp(av[1], L"-nopty") == 0) + cmd_b64 = ac == 3? av[2] : NULL; + else { + printf("ssh-shellhost received unexpected input arguments"); + return -1; + } + + /* decode cmd_b64*/ + if (cmd_b64) { + char *cmd_b64_utf8, *cmd_utf8; + if ((cmd_b64_utf8 = utf16_to_utf8(cmd_b64)) == NULL || + /* strlen(b64) should be sufficient for decoded length */ + (cmd_utf8 = malloc(strlen(cmd_b64_utf8))) == NULL || + b64_pton(cmd_b64_utf8, cmd_utf8, strlen(cmd_b64_utf8)) == -1 || + (cmd = utf8_to_utf16(cmd_utf8)) == NULL) { + printf("ssh-shellhost encountered an internal error while decoding base64 cmdline"); + return -1; + } + free(cmd_b64_utf8); + free(cmd_utf8); + } + + if (pty_requested) + return start_with_pty(cmd); else - return start_withno_pty(ac, av); + return start_withno_pty(cmd); } \ No newline at end of file diff --git a/contrib/win32/win32compat/ssh-agent/authagent-request.c b/contrib/win32/win32compat/ssh-agent/authagent-request.c index e688a5fae..0fd765eb6 100644 --- a/contrib/win32/win32compat/ssh-agent/authagent-request.c +++ b/contrib/win32/win32compat/ssh-agent/authagent-request.c @@ -225,7 +225,7 @@ int process_passwordauth_request(struct sshbuf* request, struct sshbuf* response *tmp = L'\0'; } - if (LogonUserW(user_utf16, udom_utf16, pwd_utf16, LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, &token) == FALSE) { + if (LogonUserW(user_utf16, udom_utf16, pwd_utf16, LOGON32_LOGON_NETWORK_CLEARTEXT, LOGON32_PROVIDER_DEFAULT, &token) == FALSE) { debug("failed to logon user: %ls domain: %ls", user_utf16, udom_utf16); goto done; } diff --git a/contrib/win32/win32compat/utf.c b/contrib/win32/win32compat/utf.c new file mode 100644 index 000000000..bd93d42bc --- /dev/null +++ b/contrib/win32/win32compat/utf.c @@ -0,0 +1,59 @@ +/* +* Author: Manoj Ampalam +* +* Copyright(c) 2016 Microsoft Corp. +* All rights reserved +* +* UTF8 <--> UTF16 conversion routines +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met : +* +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and / or other materials provided with the distribution. +* +* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT +* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include "inc\utf.h" + +wchar_t * +utf8_to_utf16(const char *utf8) +{ + int needed = 0; + wchar_t* utf16 = NULL; + if ((needed = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0)) == 0 || + (utf16 = malloc(needed * sizeof(wchar_t))) == NULL || + MultiByteToWideChar(CP_UTF8, 0, utf8, -1, utf16, needed) == 0) + return NULL; + + return utf16; +} + +char * +utf16_to_utf8(const wchar_t* utf16) +{ + int needed = 0; + char* utf8 = NULL; + if ((needed = WideCharToMultiByte(CP_UTF8, 0, utf16, -1, NULL, 0, NULL, NULL)) == 0 || + (utf8 = malloc(needed)) == NULL || + WideCharToMultiByte(CP_UTF8, 0, utf16, -1, utf8, needed, NULL, NULL) == 0) + return NULL; + + return utf8; +} + diff --git a/session.c b/session.c index 13543c831..54b3087d4 100644 --- a/session.c +++ b/session.c @@ -499,8 +499,22 @@ int do_exec_windows(Session *s, const char *command, int pty) { memcpy(exec_command + strlen(progdir) + 1, command, strlen(command) + 1); } } else { + /* + * contruct %programdir%\ssh-shellhost.exe <-nopty> base64encoded(command) + * command is base64 encoded to preserve original special charecters like '"' + * else they will get lost in CreateProcess translation + */ char *shell_host = pty ? "ssh-shellhost.exe " : "ssh-shellhost.exe -nopty ", *c; - exec_command = malloc(strlen(progdir) + 1 + strlen(shell_host) + (command ? strlen(command) : 0) + 1); + char *command_b64 = NULL; + size_t command_b64_len = 0; + if (command) { + /* accomodate bas64 encoding bloat and null terminator */ + command_b64_len = ((strlen(command) + 2) / 3) * 4 + 1; + if ((command_b64 = malloc(command_b64_len)) == NULL || + b64_ntop(command, strlen(command), command_b64, command_b64_len) == -1) + fatal("%s, error encoding session command"); + } + exec_command = malloc(strlen(progdir) + 1 + strlen(shell_host) + (command_b64 ? strlen(command_b64): 0) + 1); if (exec_command == NULL) fatal("%s, out of memory", __func__); c = exec_command; @@ -509,9 +523,9 @@ int do_exec_windows(Session *s, const char *command, int pty) { *c++ = '\\'; memcpy(c, shell_host, strlen(shell_host)); c += strlen(shell_host); - if (command) { - memcpy(c, command, strlen(command)); - c += strlen(command); + if (command_b64) { + memcpy(c, command_b64, strlen(command_b64)); + c += strlen(command_b64); } *c = '\0'; }