ConPTY changes and support for auto-updating known_hosts;

- Logic to support conpty (currently disabled until validation is complete)
- fdopen() and fchmod() support for file handles
- support for auto updating known_hosts via ssh and ssh-keygen
- Support for dynamic Windows-size changes with PTY
- Changes to support OneCore SDK
- Test cases
This commit is contained in:
Manoj Ampalam 2018-07-25 15:15:05 -07:00 committed by GitHub
parent 366964344f
commit 84e87be8ae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 767 additions and 401 deletions

View File

@ -18,7 +18,7 @@ if (-not $gitBinFullPath)
function Get-RepoFork
{
[CmdletBinding()]
param([string]$AccountURL, [string]$RepoFork, [string]$repoLocalPath, [string]$BranchName)
param([string]$AccountURL="https://github.com/powershell", [string]$RepoFork, [string]$repoLocalPath, [string]$BranchName)
if (Test-Path -Path $repoLocalPath -PathType Container)
{
Remove-Item -Path $repoLocalPath -Recurse -Force
@ -132,4 +132,4 @@ catch
finally{
Write-VstsTaskState
exit 0
}
}

View File

@ -304,6 +304,7 @@
<ClCompile Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\utf.c" />
<ClCompile Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\spawn.c" />
<ClCompile Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\signal_wait.c" />
<ClCompile Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\win32_pty.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="$(OpenSSH-Src-Path)\contrib\win32\win32compat\w32fd.h" />

View File

@ -40,11 +40,14 @@
#include "debug.h"
#include "console.h"
#include "ansiprsr.h"
#include "misc_internal.h"
HANDLE hOutputConsole = NULL;
DWORD stdin_dwSavedAttributes = 0;
DWORD stdout_dwSavedAttributes = 0;
WORD wStartingAttributes = 0;
unsigned int console_out_cp_saved = 0;
unsigned int console_in_cp_saved = 0;
int ScreenX;
int ScreenY;
@ -142,14 +145,28 @@ ConEnterRawMode()
SavedViewRect = csbi.srWindow;
debug("console doesn't support the ansi parsing");
} else {
ConSaveViewRect();
debug("console supports the ansi parsing");
}
if (is_conpty_supported()) {
console_out_cp_saved = GetConsoleOutputCP();
console_in_cp_saved = GetConsoleCP();
if (SetConsoleOutputCP(CP_UTF8))
debug3("Successfully set console output code page from:%d to %d", console_out_cp_saved, CP_UTF8);
else
error("Failed to set console output code page from:%d to %d error:%d", console_out_cp_saved, CP_UTF8, GetLastError());
if (SetConsoleCP(CP_UTF8))
debug3("Successfully set console input code page from:%d to %d", console_in_cp_saved, CP_UTF8);
else
error("Failed to set console input code page from:%d to %d error:%d", console_in_cp_saved, CP_UTF8, GetLastError());
} else {
ConSaveViewRect();
}
}
ConSetScreenX();
ConSetScreenY();
ScrollTop = 0;
ScrollBottom = ConVisibleWindowHeight();
ScrollBottom = ConVisibleWindowHeight();
in_raw_mode = 1;
}
@ -160,6 +177,22 @@ ConExitRawMode()
{
SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), stdin_dwSavedAttributes);
SetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), stdout_dwSavedAttributes);
if (FALSE == isAnsiParsingRequired && is_conpty_supported()) {
if (console_out_cp_saved) {
if(SetConsoleOutputCP(console_out_cp_saved))
debug3("Successfully set console output code page from %d to %d", CP_UTF8, console_out_cp_saved);
else
error("Failed to set console output code page from %d to %d error:%d", CP_UTF8, console_out_cp_saved, GetLastError());
}
if (console_in_cp_saved) {
if (SetConsoleCP(console_in_cp_saved))
debug3("Successfully set console input code page from %d to %d", CP_UTF8, console_in_cp_saved);
else
error("Failed to set console input code page from %d to %d error:%d", CP_UTF8, console_in_cp_saved, GetLastError());
}
}
}
/* Used to exit the raw mode */
@ -223,7 +256,7 @@ ConSetScreenRect(int xSize, int ySize)
bSuccess = SetConsoleScreenBufferSize(hOutputConsole, coordScreen);
}
if (bSuccess)
if (bSuccess && !is_conpty_supported())
ConSaveViewRect();
/* if the current buffer *is* the size we want, don't do anything! */
@ -270,7 +303,7 @@ ConSetScreenSize(int xSize, int ySize)
bSuccess = SetConsoleWindowInfo(hOutputConsole, TRUE, &srWindowRect);
}
if (bSuccess)
if (bSuccess && !is_conpty_supported())
ConSaveViewRect();
/* if the current buffer *is* the size we want, don't do anything! */
@ -1490,7 +1523,6 @@ void
ConSaveViewRect()
{
CONSOLE_SCREEN_BUFFER_INFO csbi;
if (GetConsoleScreenBufferInfo(hOutputConsole, &csbi))
SavedViewRect = csbi.srWindow;
}
@ -1590,7 +1622,8 @@ ConMoveCursorTopOfVisibleWindow()
offset = csbi.dwCursorPosition.Y - csbi.srWindow.Top;
ConMoveVisibleWindow(offset);
ConSaveViewRect();
if(!is_conpty_supported())
ConSaveViewRect();
}
}

View File

@ -207,7 +207,7 @@ fileio_pipe(struct w32_io* pio[2], int duplex)
sec_attributes.bInheritHandle = TRUE;
sec_attributes.lpSecurityDescriptor = NULL;
sec_attributes.nLength = 0;
sec_attributes.nLength = sizeof(sec_attributes);
/* create named pipe */
write_handle = CreateNamedPipeA(pipe_name,
@ -415,18 +415,18 @@ cleanup:
/* returns 1 if true, 0 otherwise */
int
file_in_chroot_jail(HANDLE handle, const char* path_utf8) {
file_in_chroot_jail(HANDLE handle) {
/* ensure final path is within chroot */
wchar_t path_buf[MAX_PATH], *final_path;
if (GetFinalPathNameByHandleW(handle, path_buf, MAX_PATH, 0) == 0) {
debug3("failed to get final path of file:%s error:%d", path_utf8, GetLastError());
wchar_t *final_path;
final_path = get_final_path_by_handle(handle);
if (!final_path)
return 0;
}
final_path = path_buf + 4;
to_wlower_case(final_path);
if ((wcslen(final_path) < wcslen(chroot_pathw)) ||
memcmp(final_path, chroot_pathw, 2 * wcslen(chroot_pathw)) != 0 ||
final_path[wcslen(chroot_pathw)] != '\\') {
memcmp(final_path, chroot_pathw, 2 * wcslen(chroot_pathw)) != 0 ||
final_path[wcslen(chroot_pathw)] != '\\') {
debug3("access denied due to attempt to escape chroot jail");
return 0;
}
@ -478,7 +478,8 @@ fileio_open(const char *path_utf8, int flags, mode_t mode)
goto cleanup;
}
if (chroot_pathw && !nonfs_dev && !file_in_chroot_jail(handle, path_utf8)) {
if (chroot_pathw && !nonfs_dev && !file_in_chroot_jail(handle)) {
debug3("%s is not in chroot jail", path_utf8);
errno = EACCES;
goto cleanup;
}
@ -776,7 +777,7 @@ fileio_fstat(struct w32_io* pio, struct _stat64 *buf)
return -1;
}
int fd = _open_osfhandle(dup_handle, 0);
int fd = _open_osfhandle((intptr_t)dup_handle, 0);
debug4("fstat - pio:%p", pio);
if (fd == -1) {
CloseHandle(dup_handle);
@ -902,44 +903,41 @@ fileio_lseek(struct w32_io* pio, unsigned __int64 offset, int origin)
return 0;
}
/* fdopen implementation */
/*
* fdopen implementation - use with caution
* this implementation deviates from POSIX spec the following way
* - the underlying file descriptor is closed automatically
* hence no further POSIX io operations (read, write, close, etc) on the
* underlying file descriptor are supported
*/
FILE*
fileio_fdopen(struct w32_io* pio, const char *mode)
{
int fd_flags = 0;
wchar_t *file_path, *wmode = NULL;
FILE* ret = NULL;
debug4("fdopen - io:%p", pio);
/* logic below doesn't work with overlapped file HANDLES */
if (mode[1] == '\0') {
switch (*mode) {
case 'r':
fd_flags = _O_RDONLY;
break;
case 'w':
break;
case 'a':
fd_flags = _O_APPEND;
break;
default:
errno = ENOTSUP;
debug3("fdopen - ERROR unsupported mode %s", mode);
return NULL;
}
} else {
errno = ENOTSUP;
debug3("fdopen - ERROR unsupported mode %s", mode);
return NULL;
}
if ((wmode = utf8_to_utf16(mode)) == NULL)
goto cleanup;
int fd = _open_osfhandle((intptr_t)pio->handle, fd_flags);
file_path = get_final_path_by_handle(pio->handle);
if (!file_path)
goto cleanup;
/*
* close the win32 handle right away and remove entry from table
* otherwise, wfopen will get an access denied due to sharing violation
*/
int w32_close(int);
w32_close(pio->table_index);
errno = _wfopen_s(&ret, file_path, wmode);
if (fd == -1) {
errno = EOTHER;
debug3("fdopen - ERROR:%d _open_osfhandle()", errno);
return NULL;
}
cleanup:
if (wmode)
free(wmode);
return _fdopen(fd, mode);
return ret;
}
void

View File

@ -38,6 +38,10 @@ int w32_mkdir(const char *pathname, unsigned short mode);
int w32_chmod(const char *, mode_t);
#define chmod w32_chmod
int w32_fchmod(int fd, mode_t mode);
#define fchmod w32_fchmod
struct w32_stat {
dev_t st_dev; /* ID of device containing file */
unsigned short st_ino; /* inode number */

View File

@ -286,7 +286,8 @@ w32_fopen_utf8(const char *input_path, const char *mode)
if (chroot_pathw && !nonfs_dev) {
/* ensure final path is within chroot */
HANDLE h = (HANDLE)_get_osfhandle(_fileno(f));
if (!file_in_chroot_jail(h, input_path)) {
if (!file_in_chroot_jail(h)) {
debug3("%s is not in chroot jail", input_path);
fclose(f);
f = NULL;
errno = EACCES;
@ -419,34 +420,6 @@ w32_setvbuf(FILE *stream, char *buffer, int mode, size_t size) {
return setvbuf(stream, buffer, mode, size);
}
/* TODO - deprecate this. This is not a POSIX API, used internally only */
char *
w32_programdir()
{
wchar_t* wpgmptr;
if (s_programdir != NULL)
return s_programdir;
if (_get_wpgmptr(&wpgmptr) != 0)
return NULL;
if ((s_programdir = utf16_to_utf8(wpgmptr)) == NULL)
return NULL;
/* null terminate after directory path */
char* tail = s_programdir + strlen(s_programdir);
while (tail > s_programdir && *tail != '\\' && *tail != '/')
tail--;
if (tail > s_programdir)
*tail = '\0';
else
*tail = '.'; /* current directory */
return s_programdir;
}
int
daemon(int nochdir, int noclose)
{
@ -1592,11 +1565,11 @@ cleanup:
/* builds session commandline. returns NULL with errno set on failure, caller should free returned string */
char*
build_session_commandline(const char *shell, const char* shell_arg, const char *command, int pty)
build_session_commandline(const char *shell, const char* shell_arg, const char *command)
{
enum sh_type { SH_OTHER, SH_CMD, SH_PS, SH_BASH } shell_type = SH_OTHER;
enum cmd_type { CMD_OTHER, CMD_SFTP, CMD_SCP } command_type = CMD_OTHER;
char *progdir = w32_programdir(), *cmd_sp = NULL, *cmdline = NULL, *ret = NULL, *p;
char *progdir = __progdir, *cmd_sp = NULL, *cmdline = NULL, *ret = NULL, *p;
int len, progdir_len = (int)strlen(progdir);
#define CMDLINE_APPEND(P, S) \
@ -1650,7 +1623,7 @@ do { \
if (!command)
break;
command_len = (int)strlen(command);
/*TODO - replace numbers below with readable compile time operators*/
if (command_len >= 13 && _memicmp(command, "internal-sftp", 13) == 0) {
command_type = CMD_SFTP;
command_args = command + 13;
@ -1687,7 +1660,6 @@ do { \
p = cmd_sp;
if (shell_type == SH_CMD) {
CMDLINE_APPEND(p, "\"");
CMDLINE_APPEND(p, progdir);
@ -1709,8 +1681,6 @@ do { \
} while (0);
len = 0;
if (pty)
len += progdir_len + (int)strlen("ssh-shellhost.exe") + 5;
len +=(int) strlen(shell) + 3;/* 3 for " around shell path and trailing space */
if (command) {
len += 15; /* for shell command argument, typically -c or /c */
@ -1723,11 +1693,6 @@ do { \
}
p = cmdline;
if (pty) {
CMDLINE_APPEND(p, "\"");
CMDLINE_APPEND(p, progdir);
CMDLINE_APPEND(p, "\\ssh-shellhost.exe\" ");
}
CMDLINE_APPEND(p, "\"");
CMDLINE_APPEND(p, shell);
CMDLINE_APPEND(p, "\"");
@ -1742,14 +1707,10 @@ do { \
else
CMDLINE_APPEND(p, " -c ");
/* bash type shells require " decoration around command*/
if (shell_type == SH_BASH)
CMDLINE_APPEND(p, "\"");
/* Add double quotes around command */
CMDLINE_APPEND(p, "\"");
CMDLINE_APPEND(p, command);
if (shell_type == SH_BASH)
CMDLINE_APPEND(p, "\"");
CMDLINE_APPEND(p, "\"");
}
*p = '\0';
ret = cmdline;

View File

@ -25,6 +25,17 @@
/* maximum size for user principal name as defined in ad schema */
#define MAX_UPN_LEN 1024
/* PTY windows size event type (for conhost and ssh-shellhost) */
#define PTY_SIGNAL_RESIZE_WINDOW 8u
/* maximum command line length */
#define MAX_CMD_LEN 8191
/* prog paths */
extern char* __progname;
extern char* __progdir;
extern wchar_t* __wprogdir;
static char *machine_domain_name;
extern char* chroot_path;
@ -35,7 +46,7 @@ extern wchar_t* chroot_pathw;
wchar_t * resolved_path_utf16(const char *);
void w32posix_initialize();
void w32posix_done();
char* w32_programdir();
void init_prog_paths();
void convertToBackslash(char *str);
void convertToBackslashW(wchar_t *str);
void convertToForwardslash(char *str);
@ -51,9 +62,12 @@ HANDLE get_user_token(const char* user, int impersonation);
int load_user_profile(HANDLE user_token, char* user);
int create_directory_withsddl(wchar_t *path, wchar_t *sddl);
int is_absolute_path(const char *);
int file_in_chroot_jail(HANDLE, const char*);
int file_in_chroot_jail(HANDLE);
PSID get_sid(const char*);
int am_system();
char* build_session_commandline(const char *, const char *, const char *, int );
char* build_session_commandline(const char *, const char *, const char *);
int is_conpty_supported();
int exec_command_with_pty(wchar_t*, STARTUPINFOW*, PROCESS_INFORMATION*, int);
char* get_custom_lsa_package();
wchar_t* get_final_path_by_handle(HANDLE h);
int lookup_principal_name(const wchar_t * sam_account_name, wchar_t * user_principal_name);

View File

@ -44,7 +44,6 @@
#define MAX_CONSOLE_COLUMNS 9999
#define MAX_CONSOLE_ROWS 9999
#define MAX_CMD_LEN 8191 // msdn
#define WM_APPEXIT WM_USER+1
#define MAX_EXPECTED_BUFFER_SIZE 1024
/* 4KB is the largest size for which writes are guaranteed to be atomic */
@ -274,13 +273,14 @@ HANDLE child_in = INVALID_HANDLE_VALUE;
HANDLE child_err = INVALID_HANDLE_VALUE;
HANDLE pipe_in = INVALID_HANDLE_VALUE;
HANDLE pipe_out = INVALID_HANDLE_VALUE;
HANDLE pipe_err = INVALID_HANDLE_VALUE;
HANDLE pipe_ctrl = INVALID_HANDLE_VALUE;
HANDLE child = INVALID_HANDLE_VALUE;
HANDLE job = NULL;
HANDLE hConsoleBuffer = INVALID_HANDLE_VALUE;
HANDLE monitor_thread = INVALID_HANDLE_VALUE;
HANDLE io_thread = INVALID_HANDLE_VALUE;
HANDLE ux_thread = INVALID_HANDLE_VALUE;
HANDLE ctrl_thread = INVALID_HANDLE_VALUE;
DWORD child_exit_code = 0;
DWORD hostProcessId = 0;
@ -800,6 +800,48 @@ MonitorChild(_In_ LPVOID lpParameter)
return 0;
}
unsigned __stdcall
ControlThread(LPVOID p)
{
short type, row, col;
DWORD len;
COORD coord;
SMALL_RECT rect;
while (1) {
if (!ReadFile(pipe_ctrl, &type, 2, &len, NULL))
break;
if (type != PTY_SIGNAL_RESIZE_WINDOW)
break;
if (!ReadFile(pipe_ctrl, &col, 2, &len, NULL))
break;
if (!ReadFile(pipe_ctrl, &row, 2, &len, NULL))
break;
/*
* when reducing width, console seemed to retain prior width
* while increasing width, however, it behaves right
*
* hence setting it less by 1 and setting it again to the right
* count
*/
coord.X = col - 1;
coord.Y = row;
rect.Top = 0;
rect.Left = 0;
rect.Bottom = row - 1;
rect.Right = col - 2;
SetConsoleScreenBufferSize(child_out, coord);
SetConsoleWindowInfo(child_out, TRUE, &rect);
coord.X = col;
rect.Right = col - 1;
SetConsoleScreenBufferSize(child_out, coord);
SetConsoleWindowInfo(child_out, TRUE, &rect);
}
return 0;
}
DWORD
ProcessEvent(void *p)
{
@ -1231,10 +1273,10 @@ start_with_pty(wchar_t *command)
pipe_in = GetStdHandle(STD_INPUT_HANDLE);
pipe_out = GetStdHandle(STD_OUTPUT_HANDLE);
pipe_err = GetStdHandle(STD_ERROR_HANDLE);
pipe_ctrl = GetStdHandle(STD_ERROR_HANDLE);
/* copy pipe handles passed through std io*/
if ((pipe_in == INVALID_HANDLE_VALUE) || (pipe_out == INVALID_HANDLE_VALUE) || (pipe_err == INVALID_HANDLE_VALUE))
if ((pipe_in == INVALID_HANDLE_VALUE) || (pipe_out == INVALID_HANDLE_VALUE) || (pipe_ctrl == INVALID_HANDLE_VALUE))
return -1;
cp = GetConsoleCP();
@ -1272,11 +1314,8 @@ start_with_pty(wchar_t *command)
/*
* Launch via cmd.exe /c, otherwise known issues exist with color rendering in powershell
*/
cmd[0] = L'\0';
GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_CMD_LEN, system32_path));
GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_CMD_LEN, L"\\cmd.exe /c "));
GOTO_CLEANUP_ON_ERR(wcscat_s(cmd, MAX_CMD_LEN, command));
_snwprintf_s(cmd, MAX_CMD_LEN, MAX_CMD_LEN, L"\"%ls\\cmd.exe\" /c \"%ls\"", system32_path, command);
SetConsoleCtrlHandler(NULL, FALSE);
GOTO_CLEANUP_ON_FALSE(CreateProcess(NULL, cmd, NULL, NULL, TRUE, CREATE_NEW_CONSOLE,
NULL, NULL, &si, &pi));
@ -1311,6 +1350,10 @@ start_with_pty(wchar_t *command)
if (IS_INVALID_HANDLE(ux_thread))
goto cleanup;
ctrl_thread = (HANDLE)_beginthreadex(NULL, 0, ControlThread, NULL, 0, NULL);
if (IS_INVALID_HANDLE(ctrl_thread))
goto cleanup;
ProcessMessages(NULL);
cleanup:
dwStatus = GetLastError();
@ -1330,6 +1373,11 @@ cleanup:
CloseHandle(io_thread);
}
if (!IS_INVALID_HANDLE(ctrl_thread)) {
TerminateThread(ctrl_thread, 0);
CloseHandle(ctrl_thread);
}
if (hEventHook)
__UnhookWinEvent(hEventHook);
@ -1349,20 +1397,99 @@ cleanup:
return child_exit_code;
}
int
wmain(int ac, wchar_t **av)
/* implements a basic shell - launches given cmd using CreateProcess */
int start_as_shell(wchar_t* cmd)
{
wchar_t *exec_command;
STARTUPINFOW si;
PROCESS_INFORMATION pi;
_set_invalid_parameter_handler(my_invalid_parameter_handler);
memset(&si, 0, sizeof(STARTUPINFOW));
memset(&pi, 0, sizeof(PROCESS_INFORMATION));
si.cb = sizeof(STARTUPINFOW);
if (ac == 1) {
printf("usage: shellhost.exe <cmdline to be executed with PTY support>\n");
if (CreateProcessW(NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi) == FALSE) {
printf("ssh-shellhost cannot run '%ls', error: %d", cmd, GetLastError());
exit(255);
}
/* get past shellhost.exe in commandline */
exec_command = wcsstr(GetCommandLineW(), L"shellhost.exe") + wcslen(L"shellhost.exe") + 1;
CloseHandle(pi.hThread);
/* close std io handles */
CloseHandle(GetStdHandle(STD_INPUT_HANDLE));
CloseHandle(GetStdHandle(STD_OUTPUT_HANDLE));
CloseHandle(GetStdHandle(STD_ERROR_HANDLE));
child_exit_code = 255;
return start_with_pty(exec_command);
/* wait for child to exit */
WaitForSingleObject(pi.hProcess, INFINITE);
if (!GetExitCodeProcess(pi.hProcess, &child_exit_code))
printf("ssh-shellhost unable to track child process, error: %d", GetLastError());
CloseHandle(pi.hProcess);
return child_exit_code;
}
/*
* Usage:
* Execute commandline with PTY
* ssh-shellhost.exe ---pty commandline
* Note that in PTY mode, stderr is taken as the control channel
* to receive Windows size change events
*
* Execute commandline like shell (plain IO redirection)
* Syntax mimics cmd.exe -c usage. Note the explicit double quotes
* around actual commandline to execute.
* ssh-shellhost.exe -c "commandline"
* Ex. ssh-shellhost.exe -c "notepad.exe file.txt"
* ssh-shellhost.exe -c ""my program.exe" "arg 1" "arg 2""
*/
int
wmain(int ac, wchar_t **av)
{
wchar_t *exec_command, *option, *cmdline;
int with_pty, len;
_set_invalid_parameter_handler(my_invalid_parameter_handler);
if (ac == 1)
goto usage;
if ((cmdline = _wcsdup(GetCommandLineW())) == NULL) {
printf("ssh-shellhost.exe ran out of memory");
exit(255);
}
if (option = wcsstr(cmdline, L" ---pty "))
with_pty = 1;
else if (option = wcsstr(cmdline, L" -c "))
with_pty = 0;
else
goto usage;
if (with_pty)
exec_command = option + wcslen(L" ---pty ");
else
exec_command = option + wcslen(L" -c ");
/* strip preceding white spaces */
while (*exec_command != L'\0' && *exec_command == L' ')
exec_command++;
if (exec_command == L'\0')
goto usage;
if (with_pty)
return start_with_pty(exec_command);
else {
/* if commandline is enclosed in double quotes, remove them */
len = (int)wcslen(exec_command);
if (len > 2 && *exec_command == L'\"' && *(exec_command + len - 1) == L'\"') {
*(exec_command + len - 1) = L'\0';
exec_command++;
}
return start_as_shell(exec_command);
}
usage:
printf("ssh-shellhost does not support command line: %ls", cmdline);
exit(255);
}

View File

@ -107,7 +107,7 @@ static VOID CALLBACK
sigwinch_APCProc(_In_ ULONG_PTR dwParam)
{
debug5("SIGTERM APCProc()");
sigaddset(&pending_signals, W32_SIGWINCH);
sigaddset(&pending_signals, SIGWINCH);
}
void

View File

@ -56,7 +56,7 @@
#define SHIFT_TAB_KEY "\x1b[~"
#define SHIFT_ALT_Q "\x1b?"
#define ESCAPE_KEY "\x1b"
#define BACKSPACE_KEY "\b"
#define BACKSPACE_KEY "\x7f"
// VT100 Function Key's
#define VT100_PF1_KEY "\x1bO2"

View File

@ -37,6 +37,7 @@
#include "ansiprsr.h"
#include "inc\utf.h"
#include "console.h"
#include "misc_internal.h"
#define dwBuffer 4096
@ -51,16 +52,17 @@ BOOL isFirstPacket = TRUE;
* are hardcoded in the server and will be transformed to Windows Console commands.
*/
void
processBuffer(HANDLE handle, char *buf, size_t len, unsigned char **respbuf, size_t *resplen)
processBuffer(HANDLE handle, char *buf, DWORD len, unsigned char **respbuf, size_t *resplen)
{
unsigned char *pszNewHead = NULL;
unsigned char *pszHead = NULL;
unsigned char *pszTail = NULL;
const char *applicationModeSeq = "\x1b[?1h";
const int applicationModeSeqLen = (int)strlen(applicationModeSeq);
const DWORD applicationModeSeqLen = (DWORD)strlen(applicationModeSeq);
const char *normalModeSeq = "\x1b[?1l";
const int normalModeSeqLen = (int)strlen(normalModeSeq);
const DWORD normalModeSeqLen = (DWORD)strlen(normalModeSeq);
const char *clsSeq = "\x1b[2J";
static int track_view_port = 1;
if (len == 0)
return;
@ -68,6 +70,10 @@ processBuffer(HANDLE handle, char *buf, size_t len, unsigned char **respbuf, siz
if (false == isAnsiParsingRequired) {
if(isFirstPacket) {
isFirstPacket = FALSE;
if (is_conpty_supported())
track_view_port = 0;
/* Windows server at first sends the "cls" after the connection is established.
* There is a bug in the conhost which causes the visible window data to loose so to
* mitigate that issue we need to first move the visible window so that the cursor is at the top of the visible window.
@ -81,15 +87,18 @@ processBuffer(HANDLE handle, char *buf, size_t len, unsigned char **respbuf, siz
else if(len >= normalModeSeqLen && strstr(buf, normalModeSeq))
gbVTAppMode = false;
/* WriteFile() gets messy when user does scroll up/down so we need to restore the visible window.
* It's a conhost bug but we need to live with it as they are not going to back port the fix.
*/
if(track_view_port)
ConRestoreViewRect();
/* Console has the capability to parse so pass the raw buffer to console directly */
ConRestoreViewRect(); /* Restore the visible window, otherwise WriteConsoleW() gets messy */
wchar_t* t = utf8_to_utf16(buf);
if (t) {
WriteConsoleW(handle, t, (DWORD)wcslen(t), 0, 0);
free(t);
}
ConSaveViewRect();
WriteFile(handle, buf, len, 0, 0);
if (track_view_port)
ConSaveViewRect();
return;
}

View File

@ -35,6 +35,6 @@
#ifndef __TNNET_H
#define __TNNET_H
void processBuffer(HANDLE handle, char *buf, size_t len, unsigned char **respbuf, size_t *resplen);
void processBuffer(HANDLE handle, char *buf, DWORD len, unsigned char **respbuf, size_t *resplen);
#endif

View File

@ -51,8 +51,8 @@ system32_dir()
static HMODULE
load_module(wchar_t* name)
{
HMODULE hm;
HMODULE hm = NULL;
/*system uses a standard search strategy to find the module */
if ((hm = LoadLibraryW(name)) == NULL)
debug3("unable to load module %ls at run time, error: %d", name, GetLastError());
@ -82,6 +82,17 @@ load_advapi32()
return s_hm_advapi32;
}
static HMODULE
load_api_security_lsapolicy()
{
static HMODULE s_hm_api_security_lsapolicy = NULL;
if (!s_hm_api_security_lsapolicy)
s_hm_api_security_lsapolicy = load_module(L"api-ms-win-security-lsapolicy-l1-1-0.dll");
return s_hm_api_security_lsapolicy;
}
static HMODULE
load_secur32()
{
@ -97,7 +108,7 @@ static HMODULE
load_ntdll()
{
static HMODULE s_hm_ntdll = NULL;
if (!s_hm_ntdll)
s_hm_ntdll = load_module(L"ntdll.dll");
@ -106,6 +117,9 @@ load_ntdll()
FARPROC get_proc_address(HMODULE hm, char* fn)
{
if (hm == NULL) {
debug3("GetProcAddress of %s failed with error %d.", fn, GetLastError());
}
FARPROC ret = GetProcAddress(hm, fn);
if (!ret)
debug3("GetProcAddress of %s failed with error %d.", fn, GetLastError());
@ -119,6 +133,7 @@ pLogonUserExExW(wchar_t *user_name, wchar_t *domain, wchar_t *password, DWORD lo
PVOID *profile_buffer, LPDWORD profile_length, PQUOTA_LIMITS quota_limits)
{
HMODULE hm = NULL;
typedef BOOL(WINAPI *LogonUserExExWType)(wchar_t*, wchar_t*, wchar_t*, DWORD, DWORD, PTOKEN_GROUPS, PHANDLE, PSID, PVOID, LPDWORD, PQUOTA_LIMITS);
static LogonUserExExWType s_pLogonUserExExW = NULL;
@ -153,15 +168,84 @@ BOOLEAN pTranslateNameW(LPCWSTR name,
if ((s_pTranslateNameW = (TranslateNameWType)get_proc_address(hm, "TranslateNameW")) == NULL)
return FALSE;
}
}
return s_pTranslateNameW(name, account_format, desired_name_format, translated_name, psize);
}
ULONG pRtlNtStatusToDosError(NTSTATUS status)
NTSTATUS pLsaOpenPolicy(PLSA_UNICODE_STRING system_name,
PLSA_OBJECT_ATTRIBUTES attrib,
ACCESS_MASK access,
PLSA_HANDLE handle)
{
HMODULE hm = NULL;
typedef ULONG(NTAPI *RtlNtStatusToDosErrorType)(NTSTATUS);
typedef NTSTATUS(NTAPI *LsaOpenPolicyType)(PLSA_UNICODE_STRING, PLSA_OBJECT_ATTRIBUTES, ACCESS_MASK, PLSA_HANDLE);
static LsaOpenPolicyType s_pLsaOpenPolicy = NULL;
if (!s_pLsaOpenPolicy) {
if ((hm = load_api_security_lsapolicy()) == NULL &&
((hm = load_advapi32()) == NULL))
return STATUS_ASSERTION_FAILURE;
if ((s_pLsaOpenPolicy = (LsaOpenPolicyType)get_proc_address(hm, "LsaOpenPolicy")) == NULL)
return STATUS_ASSERTION_FAILURE;
}
return s_pLsaOpenPolicy(system_name, attrib, access, handle);
}
NTSTATUS pLsaFreeMemory(PVOID buffer)
{
HMODULE hm = NULL;
typedef NTSTATUS(NTAPI *LsaFreeMemoryType)(PVOID);
static LsaFreeMemoryType s_pLsaFreeMemory = NULL;
if (!s_pLsaFreeMemory) {
if ((hm = load_api_security_lsapolicy()) == NULL &&
((hm = load_advapi32()) == NULL))
return STATUS_ASSERTION_FAILURE;
if ((s_pLsaFreeMemory = (LsaFreeMemoryType)get_proc_address(hm, "LsaFreeMemory")) == NULL)
return STATUS_ASSERTION_FAILURE;
}
return s_pLsaFreeMemory(buffer);
}
NTSTATUS pLsaAddAccountRights(LSA_HANDLE lsa_h,
PSID psid,
PLSA_UNICODE_STRING rights,
ULONG num_rights)
{
HMODULE hm = NULL;
typedef NTSTATUS(NTAPI *LsaAddAccountRightsType)(LSA_HANDLE, PSID, PLSA_UNICODE_STRING, ULONG);
static LsaAddAccountRightsType s_pLsaAddAccountRights = NULL;
if (!s_pLsaAddAccountRights) {
if ((hm = load_api_security_lsapolicy()) == NULL &&
((hm = load_advapi32()) == NULL))
return STATUS_ASSERTION_FAILURE;
if ((s_pLsaAddAccountRights = (LsaAddAccountRightsType)get_proc_address(hm, "LsaAddAccountRights")) == NULL)
return STATUS_ASSERTION_FAILURE;
}
return s_pLsaAddAccountRights(lsa_h, psid, rights, num_rights);
}
NTSTATUS pLsaRemoveAccountRights(LSA_HANDLE lsa_h,
PSID psid,
BOOLEAN all_rights,
PLSA_UNICODE_STRING rights,
ULONG num_rights)
{
HMODULE hm = NULL;
typedef NTSTATUS(NTAPI *LsaRemoveAccountRightsType)(LSA_HANDLE, PSID, BOOLEAN, PLSA_UNICODE_STRING, ULONG);
static LsaRemoveAccountRightsType s_pLsaRemoveAccountRights = NULL;
if (!s_pLsaRemoveAccountRights) {
if ((hm = load_api_security_lsapolicy()) == NULL &&
((hm = load_advapi32()) == NULL))
return STATUS_ASSERTION_FAILURE;
if ((s_pLsaRemoveAccountRights = (LsaRemoveAccountRightsType)get_proc_address(hm, "LsaRemoveAccountRights")) == NULL)
return STATUS_ASSERTION_FAILURE;
}
return s_pLsaRemoveAccountRights(lsa_h, psid, all_rights, rights, num_rights);
}
ULONG pRtlNtStatusToDosError(NTSTATUS status)
{
HMODULE hm = NULL;
typedef ULONG(NTAPI *RtlNtStatusToDosErrorType)(NTSTATUS);
static RtlNtStatusToDosErrorType s_pRtlNtStatusToDosError = NULL;
if (!s_pRtlNtStatusToDosError) {
@ -170,6 +254,24 @@ ULONG pRtlNtStatusToDosError(NTSTATUS status)
if ((s_pRtlNtStatusToDosError = (RtlNtStatusToDosErrorType)get_proc_address(hm, "RtlNtStatusToDosError")) == NULL)
return STATUS_ASSERTION_FAILURE;
}
}
return pRtlNtStatusToDosError(status);
}
NTSTATUS pLsaClose(LSA_HANDLE lsa_h)
{
HMODULE hm = NULL;
typedef NTSTATUS(NTAPI *LsaCloseType)(LSA_HANDLE);
static LsaCloseType s_pLsaClose = NULL;
if (!s_pLsaClose) {
if ((hm = load_api_security_lsapolicy()) == NULL &&
((hm = load_advapi32()) == NULL))
return STATUS_ASSERTION_FAILURE;
if ((s_pLsaClose = (LsaCloseType)get_proc_address(hm, "LsaClose")) == NULL)
return STATUS_ASSERTION_FAILURE;
}
return s_pLsaClose(lsa_h);
}

View File

@ -15,8 +15,10 @@
BOOL pLogonUserExExW(wchar_t *, wchar_t *, wchar_t *, DWORD, DWORD, PTOKEN_GROUPS, PHANDLE, PSID *, PVOID *, LPDWORD, PQUOTA_LIMITS);
BOOLEAN pTranslateNameW(LPCWSTR, EXTENDED_NAME_FORMAT, EXTENDED_NAME_FORMAT, LPWSTR, PULONG);
NTSTATUS pLsaOpenPolicy(PLSA_UNICODE_STRING, PLSA_OBJECT_ATTRIBUTES, ACCESS_MASK, PLSA_HANDLE);
NTSTATUS pLsaFreeMemory(PVOID);
NTSTATUS pLsaAddAccountRights(LSA_HANDLE, PSID, PLSA_UNICODE_STRING, ULONG);
ULONG pRtlNtStatusToDosError(NTSTATUS);
NTSTATUS pLsaClose(LSA_HANDLE);
NTSTATUS pLsaRemoveAccountRights(LSA_HANDLE, PSID, BOOLEAN, PLSA_UNICODE_STRING, ULONG);

View File

@ -33,6 +33,7 @@
#include "inc\sys\select.h"
#include "inc\sys\uio.h"
#include "inc\sys\types.h"
#include "inc\sys\stat.h"
#include "inc\unistd.h"
#include "inc\fcntl.h"
#include "inc\sys\un.h"
@ -73,6 +74,11 @@ void fd_decode_state(char*);
/* __progname */
char* __progname = "";
/* __progdir */
char* __progdir = "";
wchar_t* __wprogdir = L"";
/* initializes mapping table*/
static int
fd_table_initialize()
@ -176,41 +182,42 @@ fd_table_clear(int index)
FD_CLR(index, &(fd_table.occupied));
}
/* TODO - consolidate w32_programdir logic in here */
static int
void
init_prog_paths()
{
wchar_t* wpgmptr;
char* pgmptr;
static int processed = 0;
if (_get_wpgmptr(&wpgmptr) != 0) {
errno = EOTHER;
return -1;
}
if (processed)
return;
if ((pgmptr = utf16_to_utf8(wpgmptr)) == NULL) {
errno = ENOMEM;
return -1;
}
if (_get_wpgmptr(&wpgmptr) != 0)
fatal("unable to retrieve wpgmptr");
__progname = strrchr(pgmptr, '\\') + 1;
*(__progname - 1) = '\0';
if ((__wprogdir = _wcsdup(wpgmptr)) == NULL ||
(__progdir = utf16_to_utf8(__wprogdir)) == NULL)
fatal("out of memory");
__progname = strrchr(__progdir, '\\') + 1;
/* TODO: retain trailing \ at the end of progdir* variants ? */
*(strrchr(__progdir, '\\')) = '\0';
*(wcsrchr(__wprogdir, L'\\')) = L'\0';
/* strip .exe off __progname */
*(__progname + strlen(__progname) - 4) = '\0';
return 0;
processed = 1;
}
void
w32posix_initialize()
{
init_prog_paths();
if ((fd_table_initialize() != 0) || (socketio_initialize() != 0))
DebugBreak();
main_thread = OpenThread(THREAD_SET_CONTEXT | SYNCHRONIZE, FALSE, GetCurrentThreadId());
if (main_thread == NULL ||
sw_initialize() != 0 ||
init_prog_paths() != 0 ) {
sw_initialize() != 0 ) {
DebugBreak();
fatal("failed to initialize w32posix wrapper");
}
@ -962,6 +969,28 @@ w32_ftruncate(int fd, off_t length)
return 0;
}
int w32_fchmod(int fd, mode_t mode)
{
wchar_t *file_path;
char *file_path_utf8 = NULL;
int ret = -1;
CHECK_FD(fd);
file_path = get_final_path_by_handle(fd_table.w32_ios[fd]->handle);
if (!file_path)
goto cleanup;
if ((file_path_utf8 = utf16_to_utf8(file_path)) == NULL)
goto cleanup;
ret = w32_chmod(file_path_utf8, mode);
cleanup:
if (file_path_utf8)
free(file_path_utf8);
return ret;
}
int
w32_fsync(int fd)
{
@ -1012,7 +1041,7 @@ spawn_child_internal(char* cmd, char *const argv[], HANDLE in, HANDLE out, HANDL
/* compute total cmdline len*/
if (add_module_path)
cmdline_len += (DWORD)strlen(w32_programdir()) + 1 + (DWORD)strlen(cmd) + 1 + 2;
cmdline_len += (DWORD)strlen(__progdir) + 1 + (DWORD)strlen(cmd) + 1 + 2;
else
cmdline_len += (DWORD)strlen(cmd) + 1 + 2;
@ -1032,8 +1061,8 @@ spawn_child_internal(char* cmd, char *const argv[], HANDLE in, HANDLE out, HANDL
if (argv && argv[0])
*t++ = '\"';
if (add_module_path) {
memcpy(t, w32_programdir(), strlen(w32_programdir()));
t += strlen(w32_programdir());
memcpy(t, __progdir, strlen(__progdir));
t += strlen(__progdir);
*t++ = '\\';
}

View File

@ -0,0 +1,120 @@
/*
* Author: Balu G <bagajjal@microsoft.com>
*
* This file contains the conpty related functions.
*
* 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 <Windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Debug.h"
#include "inc\fcntl.h"
#include "misc_internal.h"
// Return Value: 0 for success, -1 for failure
int
CreateConPty(const wchar_t *cmdline,
const unsigned short width,
const unsigned short height,
HANDLE const hInput,
HANDLE const hOutput,
HANDLE const tty_sighandle,
PROCESS_INFORMATION* const piPty)
{
wchar_t system32_path[PATH_MAX] = { 0, };
SetHandleInformation(tty_sighandle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT);
wchar_t conhostCmdline[8191] = { 0, }; // msdn
wchar_t *cmd_fmt = L"%ls\\conhost.exe --headless --width %d --height %d --signal 0x%x -- %ls";
if (!GetSystemDirectoryW(system32_path, PATH_MAX))
fatal("unable to retrieve system32 path");
_snwprintf_s(conhostCmdline,
_countof(conhostCmdline),
_countof(conhostCmdline),
cmd_fmt,
system32_path,
width,
height,
tty_sighandle,
cmdline);
STARTUPINFOW si;
memset(&si, 0, sizeof(STARTUPINFOW));
si.cb = sizeof(STARTUPINFOW);
si.hStdInput = hInput;
si.hStdOutput = hOutput;
si.hStdError = hOutput;
si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESIZE | STARTF_USECOUNTCHARS;
debug3("pty commandline: %ls", conhostCmdline);
if (0 == CreateProcessW(NULL, conhostCmdline, NULL, NULL, TRUE, 0, NULL, NULL, &si, piPty)) {
debug("%s - failed to execute %ls, error:%d", __func__, conhostCmdline, GetLastError());
errno = EOTHER;
return -1;
}
return 0;
}
int is_conpty_supported()
{
/* TODO - enable this once conpty changes are validated */
return 0;
}
int exec_command_with_pty(wchar_t* cmd, STARTUPINFOW* si, PROCESS_INFORMATION* pi, int ttyfd)
{
HANDLE ttyh = (HANDLE)w32_fd_to_handle(ttyfd);
wchar_t pty_cmdline[MAX_CMD_LEN] = { 0, };
int ret = -1;
if (is_conpty_supported())
return CreateConPty(cmd, (short)si->dwXCountChars, (short)si->dwYCountChars, si->hStdInput, si->hStdOutput, ttyh, pi);
/* launch via "ssh-shellhost" -p command*/
_snwprintf_s(pty_cmdline, MAX_CMD_LEN, MAX_CMD_LEN, L"\"%ls\\ssh-shellhost.exe\" ---pty %ls", __wprogdir, cmd);
/*
* In PTY mode, ssh-shellhost takes stderr as control channel
* TODO - fix this and pass control channel pipe as a command line parameter
*/
si->hStdError = ttyh;
debug3("pty commandline: %ls", pty_cmdline);
if (!CreateProcessW(NULL, pty_cmdline, NULL, NULL, TRUE, 0, NULL, NULL, si, pi)) {
debug("%s - failed to execute %ls, error:%d", __func__, pty_cmdline, GetLastError());
errno = EOTHER;
goto done;
}
ret = 0;
done:
return ret;
}

View File

@ -6,23 +6,34 @@
#include <Windows.h>
#include "..\..\..\sshpty.h"
#include "inc\unistd.h"
#include "misc_internal.h"
/*
* Windows versions of pty_*. Some of them are NO-OPs and should go
* away when pty logic is refactored and abstracted out
*
*/
/*
* allocates a control channel for Windows PTY
* ptyfd can be used to deliver Window size change events
*/
int
pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, size_t namebuflen)
{
/*
* Simple console screen implementation in Win32 to give a
* Unix like pty for interactive sessions
*/
int p[2];
*ttyfd = 0;
*ptyfd = 0;
strlcpy(namebuf, "console", namebuflen);
if (w32_pipe(p) < 0)
return 0;
/* enable blocking mode io*/
unset_nonblock(p[0]);
unset_nonblock(p[1]);
*ttyfd = p[0];
*ptyfd = p[1];
strlcpy(namebuf, "windows-pty", namebuflen);
return 1;
}
@ -38,8 +49,15 @@ pty_make_controlling_tty(int *ttyfd, const char *tty) {
void
pty_change_window_size(int ptyfd, u_int row, u_int col,
u_int xpixel, u_int ypixel) {
/* TODO - Need to implement*/
u_int xpixel, u_int ypixel)
{
unsigned short signalPacket[3];
signalPacket[0] = PTY_SIGNAL_RESIZE_WINDOW;
signalPacket[1] = col;
signalPacket[2] = row;
// TODO - xpixel, ypixel
w32_write(ptyfd, signalPacket, sizeof(signalPacket));
}

View File

@ -135,6 +135,7 @@ generate_s4u_user_token(wchar_t* user_cpn, int impersonation) {
/* lookup the user principal name for the account */
WCHAR domain_upn[MAX_UPN_LEN + 1];
if (lookup_principal_name(user_cpn, domain_upn) != 0) {
/* failure - fallback to NetBiosDomain\SamAccountName */
wcscpy_s(domain_upn, ARRAYSIZE(domain_upn), user_cpn);
@ -488,7 +489,7 @@ add_sid_mapping_to_lsa(PUNICODE_STRING domain_name,
}
if (p_output) {
status = LsaFreeMemory(p_output);
status = pLsaFreeMemory(p_output);
if (status != STATUS_SUCCESS)
debug3("LsaFreeMemory failed with ntstatus: %d", status);
}
@ -517,7 +518,7 @@ int remove_virtual_account_lsa_mapping(PUNICODE_STRING domain_name,
ret = -1;
if (p_output) {
status = LsaFreeMemory(p_output);
status = pLsaFreeMemory(p_output);
if (status != STATUS_SUCCESS)
debug3("LsaFreeMemory failed with ntstatus: %d", status);
}
@ -623,7 +624,7 @@ HANDLE generate_sshd_virtual_token()
/* assign service logon privilege to virtual account */
ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
if ((lsa_ret = LsaOpenPolicy(NULL, &ObjectAttributes,
if ((lsa_ret = pLsaOpenPolicy(NULL, &ObjectAttributes,
POLICY_CREATE_ACCOUNT | POLICY_LOOKUP_NAMES,
&lsa_policy)) != STATUS_SUCCESS) {
error("%s: unable to open policy handle, error: %d",
@ -632,7 +633,7 @@ HANDLE generate_sshd_virtual_token()
}
/* alter security to allow policy to account to logon as a service */
if ((lsa_add_ret = LsaAddAccountRights(lsa_policy, sid_user, &svcLogonRight, 1)) != STATUS_SUCCESS) {
if ((lsa_add_ret = pLsaAddAccountRights(lsa_policy, sid_user, &svcLogonRight, 1)) != STATUS_SUCCESS) {
error("%s: unable to assign SE_SERVICE_LOGON_NAME privilege, error: %d",
__FUNCTION__, (ULONG)pRtlNtStatusToDosError(lsa_add_ret));
goto cleanup;
@ -656,7 +657,7 @@ cleanup:
/* attempt to remove virtual account permissions if previous add succeeded */
if (lsa_add_ret == STATUS_SUCCESS)
if ((lsa_ret = LsaRemoveAccountRights(lsa_policy, sid_user, FALSE, &svcLogonRight, 1)) != STATUS_SUCCESS)
if ((lsa_ret = pLsaRemoveAccountRights(lsa_policy, sid_user, FALSE, &svcLogonRight, 1)) != STATUS_SUCCESS)
debug("%s: unable to remove SE_SERVICE_LOGON_NAME privilege, error: %d", __FUNCTION__, pRtlNtStatusToDosError(lsa_ret));
if (sid_domain)
@ -666,7 +667,7 @@ cleanup:
if (sid_group)
FreeSid(sid_group);
if (lsa_policy)
LsaClose(lsa_policy);
pLsaClose(lsa_policy);
return va_token_restricted;
}
@ -709,6 +710,24 @@ get_custom_lsa_package()
return s_lsa_auth_pkg;
}
/*
* Not thread safe
* returned value is pointer from static buffer
* dont free()
*/
wchar_t* get_final_path_by_handle(HANDLE h)
{
static wchar_t path_buf[PATH_MAX];
if (GetFinalPathNameByHandleW(h, path_buf, PATH_MAX, 0) == 0) {
errno = EOTHER;
debug3("failed to get final path of file with handle:%d error:%d", h, GetLastError());
return NULL;
}
return (path_buf + 4);
}
/* using the netbiosname\samaccountname as an input, lookup the upn for the user.
* if no explicit upn is defined, implicit upn is returned (samaccountname@fqdn) */
int lookup_principal_name(const wchar_t * sam_account_name, wchar_t * user_principal_name)

View File

@ -189,7 +189,7 @@ create_prgdata_ssh_folder()
wcscat_s(sshd_config_path, _countof(sshd_config_path), L"\\sshd_config");
if (GetFileAttributesW(sshd_config_path) == INVALID_FILE_ATTRIBUTES) {
wchar_t sshd_config_default_path[PATH_MAX] = { 0, };
swprintf_s(sshd_config_default_path, PATH_MAX, L"%S\\%s", w32_programdir(), L"sshd_config_default");
swprintf_s(sshd_config_default_path, PATH_MAX, L"%S\\%s", __progdir, L"sshd_config_default");
if (CopyFileW(sshd_config_default_path, sshd_config_path, TRUE) == 0) {
printf("Failed to copy %s to %s, error:%d", sshd_config_default_path, sshd_config_path, GetLastError());
@ -264,11 +264,9 @@ int wmain(int argc, wchar_t **wargv) {
argc_original = argc;
wargv_original = wargv;
init_prog_paths();
/* change current directory to sshd.exe root */
if ( (path_utf16 = utf8_to_utf16(w32_programdir())) == NULL)
return -1;
_wchdir(path_utf16);
free(path_utf16);
_wchdir(__wprogdir);
if (!StartServiceCtrlDispatcherW(dispatch_table)) {
if (GetLastError() == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT)

View File

@ -524,11 +524,6 @@ int
hostfile_replace_entries(const char *filename, const char *host, const char *ip,
struct sshkey **keys, size_t nkeys, int store_hash, int quiet, int hash_alg)
{
#ifdef WINDOWS
error("replacing host file entries is not supported in Windows yet");
errno = ENOTSUP;
return -1;
#else /* !WINDOWS */
int r, fd, oerrno = 0;
int loglevel = quiet ? SYSLOG_LEVEL_DEBUG1 : SYSLOG_LEVEL_VERBOSE;
struct host_delete_ctx ctx;
@ -643,7 +638,6 @@ hostfile_replace_entries(const char *filename, const char *host, const char *ip,
if (r == SSH_ERR_SYSTEM_ERROR)
errno = oerrno;
return r;
#endif /* !WINDOWS */
}
static int

View File

@ -295,6 +295,30 @@ Describe "E2E scenarios for ssh key management" -Tags "CI" {
}
}
Context "$tC ssh-keygen known_hosts operations" {
BeforeAll {$tI=1}
AfterAll{$tC++}
It "$tC.$tI - list and delete host key thumbprints" {
$kh = Join-Path $testDir "$tC.$tI.known_hosts"
$entry = "[localhost]:47002 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMtJMxwn+iJU0X4+EC7PSj/cfcMbdP6ahhodtXx+6RHv sshtest_hostkey_ed25519"
$entry | Set-Content $kh
$o = ssh-keygen -F [localhost]:47002 -f $kh
$o.Count | Should Be 2
$o[1] | Should Be $entry
$o = ssh-keygen -H -F [localhost]:47002 -f $kh
$o.StartsWith("|1|") | Should Be $true
$o = ssh-keygen -R [localhost]:47002 -f $kh
$o.count | Should Be 3
$o[0] | Should Be "# Host [localhost]:47002 found: line 1"
(dir $kh).Length | Should Be 0
}
}
Context "$tC-ssh-add key files with different file perms" {
BeforeAll {
$keyFileName = "sshadd_userPermTestkey_ed25519"

View File

@ -81,14 +81,16 @@ Describe "E2E scenarios for ssh client" -Tags "CI" {
param
(
[string] $default_shell_path,
[string] $default_shell_cmd_option_val
[string] $default_shell_cmd_option_val = $null
)
if (!(Test-Path $dfltShellRegPath)) {
New-Item -Path $dfltShellRegPath -Force | Out-Null
}
New-ItemProperty -Path $dfltShellRegPath -Name $dfltShellRegKeyName -Value $default_shell_path -PropertyType String -Force
New-ItemProperty -Path $dfltShellRegPath -Name $dfltShellCmdOptionRegKeyName -Value $default_shell_cmd_option_val -PropertyType String -Force
if ($default_shell_cmd_option_val -ne $null) {
New-ItemProperty -Path $dfltShellRegPath -Name $dfltShellCmdOptionRegKeyName -Value $default_shell_cmd_option_val -PropertyType String -Force
}
}
}
@ -148,6 +150,12 @@ Describe "E2E scenarios for ssh client" -Tags "CI" {
$o | Should Be "1234"
}
It "$tC.$tI - multiple double quotes in cmdline" {
# actual command line ssh target \"cmd\" /c \"echo hello\"
$o = ssh test_target `\`"cmd`\`" /c `\`"echo hello`\`"
$o | Should Be "hello"
}
It "$tC.$tI - stdin from PS object" -skip:$skip {
# execute this script that dumps the length of input data, on the remote end
$str = "begin {} process { Write-Output `$input.Length} end { }"
@ -211,6 +219,14 @@ Describe "E2E scenarios for ssh client" -Tags "CI" {
$o | Should Contain "cmd"
}
}
It "$tC.$tI - shellhost as default shell and multiple double quotes in cmdline" {
# actual command line ssh target \"cmd\" /c \"echo hello\"
$shell_path = (Get-Command ssh-shellhost -ErrorAction SilentlyContinue).path
ConfigureDefaultShell -default_shell_path $shell_path
$o = ssh test_target `\`"cmd`\`" /c `\`"echo hello`\`"
$o | Should Be "hello"
}
}
Context "$tC - cmdline parameters" {
@ -271,105 +287,15 @@ Describe "E2E scenarios for ssh client" -Tags "CI" {
$o | Should Be "1234"
$logFile | Should Contain "[::1]"
}
}
<#Context "Key is not secured in ssh-agent on server" {
BeforeAll {
$identifyFile = $client.clientPrivateKeyPaths[0]
Remove-Item -Path $filePath -Force -ea silentlycontinue
}
AfterEach {
Remove-Item -Path $filePath -Force -ea silentlycontinue
}
It '<Title>' -TestCases:$testData1 {
param([string]$Title, $LogonStr, $Options, $SkipVerification = $false)
$str = $ExecutionContext.InvokeCommand.ExpandString(".\ssh $($Options) $($LogonStr) hostname > $filePath")
$client.RunCmd($str)
#validate file content.
Get-Content $filePath | Should be $server.MachineName
It "$tC.$tI - auto populate known hosts" {
$kh = Join-Path $testDir "$tC.$tI.known_hosts"
$nul | Set-Content $kh
# doing via cmd to intercept and drain stderr output
iex "cmd /c `"ssh -o UserKnownHostsFile=`"$kh`" -o StrictHostKeyChecking=no test_target hostname 2>&1`""
(Get-Content $kh).Count | Should Be 1
}
}
Context "Key is secured in ssh-agent" {
BeforeAll {
$server.SecureHostKeys($server.PrivateHostKeyPaths)
$identifyFile = $client.clientPrivateKeyPaths[0]
Remove-Item -Path $filePath -Force -ea silentlycontinue
}
AfterAll {
$Server.CleanupHostKeys()
}
AfterEach {
Remove-Item -Path $filePath -Force -ea silentlycontinue
}
It '<Title>' -TestCases:$testData1 {
param([string]$Title, $LogonStr, $Options, $SkipVerification = $false)
$str = $ExecutionContext.InvokeCommand.ExpandString(".\ssh $Options $LogonStr hostname > $filePath")
$client.RunCmd($str)
#validate file content.
Get-Content $filePath | Should be $server.MachineName
}
}
Context "Single signon on client and keys secured in ssh-agent on server" {
BeforeAll {
$Server.SecureHostKeys($server.PrivateHostKeyPaths)
$identifyFile = $client.clientPrivateKeyPaths[0]
#setup single signon
.\ssh-add.exe $identifyFile
Remove-Item -Path $filePath -Force -ea silentlycontinue
}
AfterAll {
$Server.CleanupHostKeys()
#cleanup single signon
.\ssh-add.exe -D
}
AfterEach {
Remove-Item -Path $filePath -Force -ea silentlycontinue
}
It '<Title>' -TestCases:$testData {
param([string]$Title, $LogonStr, $Options)
$str = ".\ssh $($Options) $($LogonStr) hostname > $filePath"
$client.RunCmd($str)
#validate file content.
Get-Content $filePath | Should be $server.MachineName
}
}
Context "password authentication" {
BeforeAll {
$client.AddPasswordSetting($server.localAdminPassword)
Remove-Item -Path $filePath -Force -ea silentlycontinue
}
AfterAll {
$client.CleanupPasswordSetting()
}
AfterEach {
Remove-Item -Path $filePath -Force -ea silentlycontinue
}
It '<Title>' -TestCases:$testData {
param([string]$Title, $LogonStr, $Options)
$str = ".\ssh $($Options) $($LogonStr) hostname > $filePath"
$client.RunCmd($str)
#validate file content.
Get-Content $filePath | Should be $server.MachineName
}
}#>
}

View File

@ -0,0 +1,42 @@
$tC = 1
$tI = 0
$suite = "shellhost"
Describe "E2E scenarios for ssh-shellhost" -Tags "CI" {
BeforeAll {
}
BeforeEach {
}
AfterEach {$tI++;}
Context "$tC - shellhost commandline scenarios" {
BeforeAll {$tI=1}
AfterAll{$tC++}
It "$tC.$tI - exit code tests" -skip:$skip {
foreach ($i in (0,1,4,5,44)) {
ssh-shellhost -c cmd /c exit $i
$LASTEXITCODE | Should Be $i
}
}
It "$tC.$tI - various quote tests" -skip:$skip {
$o = ssh-shellhost -c cmd /c echo hello
$o | Should Be "hello"
$o = ssh-shellhost -c `"cmd /c echo hello`"
$o | Should Be "hello"
$o = ssh-shellhost -c cmd /c echo `"hello`"
$o | Should Be "`"hello`""
$o = ssh-shellhost -c `"cmd /c echo `"hello`"`"
$o | Should Be "`"hello`""
$o = ssh-shellhost -c `"cmd /c echo `"hello`"
$o | Should Be "`"hello"
$o = ssh-shellhost -c `"`"cmd`" /c echo `"hello`"`"
$o | Should Be "`"hello`""
}
}
}

View File

@ -64,7 +64,7 @@ test_sanitizedpath()
{
TEST_START("win32 program dir");
char *win32prgdir_utf8 = w32_programdir();
char *win32prgdir_utf8 = __progdir;
ASSERT_PTR_NE(win32prgdir_utf8, NULL);
ASSERT_PTR_EQ(resolved_path_utf16(NULL), NULL);
@ -314,126 +314,92 @@ test_chroot()
void
test_build_session_commandline()
{
char *progdir = w32_programdir(), *out, buf[PATH_MAX*2], shellhost_path[PATH_MAX];
shellhost_path[0] = '\0';
strcat(shellhost_path, "\"");
strcat(shellhost_path, progdir);
strcat(shellhost_path, "\\ssh-shellhost.exe\"");
int shellhost_path_len = (int)strlen(shellhost_path);
char *progdir = __progdir, *out, buf[PATH_MAX * 2];
TEST_START("default interactive session tests");
out = build_session_commandline("c:\\system32\\cmd.exe", NULL, NULL, 0);
out = build_session_commandline("c:\\system32\\cmd.exe", NULL, NULL);
ASSERT_STRING_EQ(out, "\"c:\\system32\\cmd.exe\"");
out = build_session_commandline("c:\\system32\\cmd.exe", NULL, NULL, 1);
ASSERT_STRING_EQ(out + shellhost_path_len + 1, "\"c:\\system32\\cmd.exe\"");
out[shellhost_path_len] = '\0';
ASSERT_STRING_EQ(out, shellhost_path);
TEST_DONE();
TEST_START("cmd shell tests");
buf[0] = '\0';
strcat(buf, "\"c:\\system32\\cmd.exe\" /c \"");
strcat(buf, "\"c:\\system32\\cmd.exe\" /c \"\"");
strcat(buf, progdir);
int len_pg = strlen(buf);
out = build_session_commandline("c:\\system32\\cmd.exe", NULL, "internal-sftp -arg", 0);
out = build_session_commandline("c:\\system32\\cmd.exe", NULL, "internal-sftp -arg");
buf[len_pg] = '\0';
strcat(buf, "\\sftp-server.exe\" -arg");
strcat(buf, "\\sftp-server.exe\" -arg\"");
ASSERT_STRING_EQ(out, buf);
out = build_session_commandline("c:\\system32\\cmd.exe", NULL, "SFTP-server.exe -arg", 0);
out = build_session_commandline("c:\\system32\\cmd.exe", NULL, "SFTP-server.exe -arg");
buf[len_pg] = '\0';
strcat(buf, "\\sftp-server.exe\" -arg");
strcat(buf, "\\sftp-server.exe\" -arg\"");
ASSERT_STRING_EQ(out, buf);
out = build_session_commandline("c:\\system32\\cmd.exe", NULL, "sftp-SERVER -arg", 0);
out = build_session_commandline("c:\\system32\\cmd.exe", NULL, "sftp-SERVER -arg");
buf[len_pg] = '\0';
strcat(buf, "\\sftp-server.exe\" -arg");
strcat(buf, "\\sftp-server.exe\" -arg\"");
ASSERT_STRING_EQ(out, buf);
out = build_session_commandline("c:\\system32\\cmd.exe", NULL, "sCp -arg", 0);
out = build_session_commandline("c:\\system32\\cmd.exe", NULL, "sCp -arg");
buf[len_pg] = '\0';
strcat(buf, "\\scp.exe\" -arg");
strcat(buf, "\\scp.exe\" -arg\"");
ASSERT_STRING_EQ(out, buf);
out = build_session_commandline("c:\\system32\\cmd.exe", NULL, "mycommand -arg", 1);
ASSERT_STRING_EQ(out + shellhost_path_len + 1, "\"c:\\system32\\cmd.exe\" /c mycommand -arg");
out[shellhost_path_len] = '\0';
ASSERT_STRING_EQ(out, shellhost_path);
free(out);
TEST_DONE();
TEST_START("bash shell tests");
out = build_session_commandline("c:\\system32\\bash.exe", NULL, "internal-sftp -arg", 0);
out = build_session_commandline("c:\\system32\\bash.exe", NULL, "internal-sftp -arg");
ASSERT_STRING_EQ(out, "\"c:\\system32\\bash.exe\" -c \"sftp-server.exe -arg\"");
free(out);
out = build_session_commandline("c:\\system32\\bash", NULL, "internal-sftp -arg", 0);
out = build_session_commandline("c:\\system32\\bash", NULL, "internal-sftp -arg");
ASSERT_STRING_EQ(out, "\"c:\\system32\\bash\" -c \"sftp-server.exe -arg\"");
free(out);
out = build_session_commandline("c:\\system32\\bash", NULL, "sFTP-server -arg", 0);
out = build_session_commandline("c:\\system32\\bash", NULL, "sFTP-server -arg");
ASSERT_STRING_EQ(out, "\"c:\\system32\\bash\" -c \"sftp-server.exe -arg\"");
free(out);
out = build_session_commandline("c:\\system32\\bash", NULL, "scP -arg", 0);
out = build_session_commandline("c:\\system32\\bash", NULL, "scP -arg");
ASSERT_STRING_EQ(out, "\"c:\\system32\\bash\" -c \"scp.exe -arg\"");
free(out);
out = build_session_commandline("c:\\bash", "-custom", "mycommand -arg", 1);
ASSERT_STRING_EQ(out + shellhost_path_len + 1, "\"c:\\bash\" -custom \"mycommand -arg\"");
out[shellhost_path_len] = '\0';
ASSERT_STRING_EQ(out, shellhost_path);
free(out);
out = build_session_commandline("c:\\cygwin\\bash.exe", NULL, "internal-sftp -arg", 0);
out = build_session_commandline("c:\\cygwin\\bash.exe", NULL, "internal-sftp -arg");
ASSERT_STRING_EQ(out, "\"c:\\cygwin\\bash.exe\" -c \"sftp-server.exe -arg\"");
free(out);
out = build_session_commandline("c:\\cygwin\\bash", NULL, "sftp-server -arg", 0);
out = build_session_commandline("c:\\cygwin\\bash", NULL, "sftp-server -arg");
ASSERT_STRING_EQ(out, "\"c:\\cygwin\\bash\" -c \"sftp-server.exe -arg\"");
free(out);
out = build_session_commandline("c:\\cygwin\\bash", NULL, "sftp-seRVer.exe -arg", 0);
out = build_session_commandline("c:\\cygwin\\bash", NULL, "sftp-seRVer.exe -arg");
ASSERT_STRING_EQ(out, "\"c:\\cygwin\\bash\" -c \"sftp-server.exe -arg\"");
free(out);
out = build_session_commandline("c:\\cygwin\\bash", NULL, "sCp -arg", 0);
out = build_session_commandline("c:\\cygwin\\bash", NULL, "sCp -arg");
ASSERT_STRING_EQ(out, "\"c:\\cygwin\\bash\" -c \"scp.exe -arg\"");
free(out);
out = build_session_commandline("c:\\cygwin\\bash", "-custom", "mycommand -arg", 1);
ASSERT_STRING_EQ(out + shellhost_path_len + 1, "\"c:\\cygwin\\bash\" -custom \"mycommand -arg\"");
out[shellhost_path_len] = '\0';
ASSERT_STRING_EQ(out, shellhost_path);
free(out);
TEST_DONE();
TEST_START("powershell shell tests");
out = build_session_commandline("c:\\powershell.exe", NULL, "internal-sftp -arg", 0);
ASSERT_STRING_EQ(out, "\"c:\\powershell.exe\" -c sftp-server.exe -arg");
out = build_session_commandline("c:\\powershell.exe", NULL, "internal-sftp -arg");
ASSERT_STRING_EQ(out, "\"c:\\powershell.exe\" -c \"sftp-server.exe -arg\"");
free(out);
out = build_session_commandline("c:\\powershell", NULL, "sftp-server -arg", 0);
ASSERT_STRING_EQ(out, "\"c:\\powershell\" -c sftp-server.exe -arg");
out = build_session_commandline("c:\\powershell", NULL, "sftp-server -arg");
ASSERT_STRING_EQ(out, "\"c:\\powershell\" -c \"sftp-server.exe -arg\"");
free(out);
out = build_session_commandline("c:\\powershell.exe", NULL, "sftp-sERver.exe -arg", 0);
ASSERT_STRING_EQ(out, "\"c:\\powershell.exe\" -c sftp-server.exe -arg");
out = build_session_commandline("c:\\powershell.exe", NULL, "sftp-sERver.exe -arg");
ASSERT_STRING_EQ(out, "\"c:\\powershell.exe\" -c \"sftp-server.exe -arg\"");
free(out);
out = build_session_commandline("c:\\powershell.exe", NULL, "scP -arg", 0);
ASSERT_STRING_EQ(out, "\"c:\\powershell.exe\" -c scp.exe -arg");
free(out);
out = build_session_commandline("c:\\powershell.exe", "-custom", "mycommand -arg", 1);
ASSERT_STRING_EQ(out + shellhost_path_len + 1, "\"c:\\powershell.exe\" -custom mycommand -arg");
out[shellhost_path_len] = '\0';
ASSERT_STRING_EQ(out, shellhost_path);
out = build_session_commandline("c:\\powershell.exe", NULL, "scP -arg");
ASSERT_STRING_EQ(out, "\"c:\\powershell.exe\" -c \"scp.exe -arg\"");
free(out);
TEST_DONE();
TEST_START("other shell tests");
out = build_session_commandline("c:\\myshell.exe", NULL, "internal-sftp -arg", 0);
ASSERT_STRING_EQ(out, "\"c:\\myshell.exe\" -c sftp-server.exe -arg");
out = build_session_commandline("c:\\myshell.exe", NULL, "internal-sftp -arg");
ASSERT_STRING_EQ(out, "\"c:\\myshell.exe\" -c \"sftp-server.exe -arg\"");
free(out);
out = build_session_commandline("c:\\myshell", NULL, "sftp-server -arg", 0);
ASSERT_STRING_EQ(out, "\"c:\\myshell\" -c sftp-server.exe -arg");
out = build_session_commandline("c:\\myshell", NULL, "sftp-server -arg");
ASSERT_STRING_EQ(out, "\"c:\\myshell\" -c \"sftp-server.exe -arg\"");
free(out);
out = build_session_commandline("c:\\myshell", NULL, "sftp-seRVer.exe -arg", 0);
ASSERT_STRING_EQ(out, "\"c:\\myshell\" -c sftp-server.exe -arg");
out = build_session_commandline("c:\\myshell", NULL, "sftp-seRVer.exe -arg");
ASSERT_STRING_EQ(out, "\"c:\\myshell\" -c \"sftp-server.exe -arg\"");
free(out);
out = build_session_commandline("c:\\myshell", NULL, "sCp -arg", 0);
ASSERT_STRING_EQ(out, "\"c:\\myshell\" -c scp.exe -arg");
free(out);
out = build_session_commandline("c:\\myshell", "-custom", "mycommand -arg", 1);
ASSERT_STRING_EQ(out + shellhost_path_len + 1, "\"c:\\myshell\" -custom mycommand -arg");
out[shellhost_path_len] = '\0';
ASSERT_STRING_EQ(out, shellhost_path);
out = build_session_commandline("c:\\myshell", NULL, "sCp -arg");
ASSERT_STRING_EQ(out, "\"c:\\myshell\" -c \"scp.exe -arg\"");
free(out);
TEST_DONE();
}

View File

@ -537,7 +537,7 @@ cleanup:
}
int register_child(void* child, unsigned long pid);
char* build_session_commandline(const char *, const char *, const char *, int);
char* build_session_commandline(const char *, const char *, const char *);
int do_exec_windows(struct ssh *ssh, Session *s, const char *command, int pty) {
int pipein[2], pipeout[2], pipeerr[2], r, ret = -1;
@ -582,7 +582,7 @@ int do_exec_windows(struct ssh *ssh, Session *s, const char *command, int pty) {
pty = 0;
}
exec_command = build_session_commandline(s->pw->pw_shell, shell_command_option, command, pty);
exec_command = build_session_commandline(s->pw->pw_shell, shell_command_option, command);
if (exec_command == NULL)
goto cleanup;
@ -606,11 +606,18 @@ int do_exec_windows(struct ssh *ssh, Session *s, const char *command, int pty) {
si.hStdError = (HANDLE)w32_fd_to_handle(pipeerr[1]);
si.lpDesktop = NULL;
debug("Executing command: %s", exec_command);
if ((exec_command_w = utf8_to_utf16(exec_command)) == NULL)
goto cleanup;
if (!CreateProcessW(NULL, exec_command_w, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) {
debug("Executing command: %s with%spty", exec_command, pty? " ":" no ");
if (pty) {
fcntl(s->ptyfd, F_SETFD, FD_CLOEXEC);
if (exec_command_with_pty(exec_command_w, &si, &pi, s->ttyfd) == -1)
goto cleanup;
close(s->ttyfd);
s->ttyfd = -1;
} else if (!CreateProcessW(NULL, exec_command_w, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) {
errno = EOTHER;
error("ERROR. Cannot create process (%u).\n", GetLastError());
goto cleanup;
@ -641,12 +648,6 @@ int do_exec_windows(struct ssh *ssh, Session *s, const char *command, int pty) {
register_child(pi.hProcess, pi.dwProcessId);
}
/*
* Set interactive/non-interactive mode.
*/
packet_set_interactive(s->display != NULL, options.ip_qos_interactive,
options.ip_qos_bulk);
/* Close the child sides of the socket pairs. */
close(pipein[0]);
close(pipeout[1]);
@ -656,10 +657,17 @@ int do_exec_windows(struct ssh *ssh, Session *s, const char *command, int pty) {
* Enter the interactive session. Note: server_loop must be able to
* handle the case that fdin and fdout are the same.
*/
if (s->ttyfd == -1)
if (pty) {
/* Set interactive/non-interactive mode */
packet_set_interactive(1, options.ip_qos_interactive,
options.ip_qos_bulk);
session_set_fds(ssh, s, pipein[1], pipeout[0], -1, 1, 1);
} else {
/* Set interactive/non-interactive mode */
packet_set_interactive(s->display != NULL, options.ip_qos_interactive,
options.ip_qos_bulk);
session_set_fds(ssh, s, pipein[1], pipeout[0], pipeerr[0], s->is_subsystem, 0);
else
session_set_fds(ssh, s, pipein[1], pipeout[0], pipeerr[0], s->is_subsystem, 1); /* tty interactive session */
}
ret = 0;

View File

@ -1053,19 +1053,12 @@ do_gen_all_hostkeys(struct passwd *pw)
pub_tmp, strerror(errno));
goto failnext;
}
#ifdef WINDOWS
/* Windows POSIX adpater does not support fdopen() on open(file)*/
close(fd);
chmod(pub_tmp, 0644);
if ((f = fopen(pub_tmp, "w")) == NULL) {
error("fopen %s failed: %s", pub_tmp, strerror(errno));
#else /* !WINDOWS */
(void)fchmod(fd, 0644);
f = fdopen(fd, "w");
if (f == NULL) {
error("fdopen %s failed: %s", pub_tmp, strerror(errno));
close(fd);
#endif /* !WINDOWS */
sshkey_free(public);
first = 0;
continue;
@ -1232,10 +1225,6 @@ known_hosts_find_delete(struct hostkey_foreach_line *l, void *_ctx)
static void
do_known_hosts(struct passwd *pw, const char *name)
{
#ifdef WINDOWS
fatal("Updating known_hosts is not supported in Windows yet.");
#else /* !WINDOWS */
char *cp, tmp[PATH_MAX], old[PATH_MAX];
int r, fd, oerrno, inplace = 0;
struct known_hosts_ctx ctx;
@ -1327,7 +1316,6 @@ do_known_hosts(struct passwd *pw, const char *name)
}
exit (find_host && !ctx.found_key);
#endif /* !WINDOWS */
}
/*
@ -1530,16 +1518,9 @@ do_change_comment(struct passwd *pw)
fd = open(identity_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (fd == -1)
fatal("Could not save your public key in %s", identity_file);
#ifdef WINDOWS
/* Windows POSIX adpater does not support fdopen() on open(file)*/
close(fd);
if ((f = fopen(identity_file, "w")) == NULL)
fatal("fopen %s failed: %s", identity_file, strerror(errno));
#else /* !WINDOWS */
f = fdopen(fd, "w");
if (f == NULL)
fatal("fdopen %s failed: %s", identity_file, strerror(errno));
#endif /* !WINDOWS */
if ((r = sshkey_write(public, f)) != 0)
fatal("write key failed: %s", ssh_err(r));
sshkey_free(public);
@ -1784,15 +1765,8 @@ do_ca_sign(struct passwd *pw, int argc, char **argv)
if ((fd = open(out, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1)
fatal("Could not open \"%s\" for writing: %s", out,
strerror(errno));
#ifdef WINDOWS
/* Windows POSIX adpater does not support fdopen() on open(file)*/
close(fd);
if ((f = fopen(out, "w")) == NULL)
fatal("fopen %s failed: %s", identity_file, strerror(errno));
#else /* !WINDOWS */
if ((f = fdopen(fd, "w")) == NULL)
fatal("%s: fdopen: %s", __func__, strerror(errno));
#endif /* !WINDOWS */
if ((r = sshkey_write(public, f)) != 0)
fatal("Could not write certified key to %s: %s",
out, ssh_err(r));
@ -2851,15 +2825,8 @@ passphrase_again:
if ((fd = open(identity_file, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1)
fatal("Unable to save public key to %s: %s",
identity_file, strerror(errno));
#ifdef WINDOWS
/* Windows POSIX adpater does not support fdopen() on open(file)*/
close(fd);
if ((f = fopen(identity_file, "w")) == NULL)
fatal("fopen %s failed: %s", identity_file, strerror(errno));
#else /* !WINDOWS */
if ((f = fdopen(fd, "w")) == NULL)
fatal("fdopen %s failed: %s", identity_file, strerror(errno));
#endif /* !WINDOWS */
if ((r = sshkey_write(public, f)) != 0)
error("write key failed: %s", ssh_err(r));
fprintf(f, " %s\n", comment);

4
sshd.c
View File

@ -786,6 +786,9 @@ privsep_preauth(Authctxt *authctxt)
pmonitor->m_recvfd = PRIVSEP_MONITOR_FD;
pmonitor->m_log_sendfd = PRIVSEP_LOG_FD;
fcntl(pmonitor->m_recvfd, F_SETFD, FD_CLOEXEC);
fcntl(pmonitor->m_log_sendfd, F_SETFD, FD_CLOEXEC);
/* Arrange for logging to be sent to the monitor */
set_log_handler(mm_log_handler, pmonitor);
@ -948,6 +951,7 @@ privsep_postauth(Authctxt *authctxt)
close(pmonitor->m_recvfd);
pmonitor->m_recvfd = PRIVSEP_MONITOR_FD;
fcntl(pmonitor->m_recvfd, F_SETFD, FD_CLOEXEC);
monitor_recv_keystate(pmonitor);
do_setusercontext(authctxt->pw);