mirror of https://github.com/wolfSSL/wolfssh.git
Merge pull request #666 from JacobBarthelmeh/progress_bar
refactor windows wolfsshd service to resolve powershell Write-Progresspull/683/head
commit
9b29ba68cc
|
@ -806,8 +806,6 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh,
|
||||||
int cnt_r, cnt_w;
|
int cnt_r, cnt_w;
|
||||||
HANDLE ptyIn = NULL, ptyOut = NULL;
|
HANDLE ptyIn = NULL, ptyOut = NULL;
|
||||||
HANDLE cnslIn = NULL, cnslOut = NULL;
|
HANDLE cnslIn = NULL, cnslOut = NULL;
|
||||||
HPCON pCon = 0;
|
|
||||||
COORD cord;
|
|
||||||
STARTUPINFOEX ext;
|
STARTUPINFOEX ext;
|
||||||
PCWSTR sysCmd = L"c:\\windows\\system32\\cmd.exe";
|
PCWSTR sysCmd = L"c:\\windows\\system32\\cmd.exe";
|
||||||
#if 0
|
#if 0
|
||||||
|
@ -865,7 +863,7 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret == WS_SUCCESS) {
|
if (ret == WS_SUCCESS) {
|
||||||
swprintf(cmd, cmdSz, L"%s /C \"%s\"", sysCmd, tmp);
|
swprintf(cmd, cmdSz, L"%s /C %s", sysCmd, tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tmp != NULL) {
|
if (tmp != NULL) {
|
||||||
|
@ -898,259 +896,239 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ImpersonateLoggedOnUser(wolfSSHD_GetAuthToken(conn->auth)) == FALSE) {
|
||||||
|
ret = WS_FATAL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
if (ret == WS_SUCCESS) {
|
if (ret == WS_SUCCESS) {
|
||||||
HRESULT err;
|
SECURITY_ATTRIBUTES saAttr;
|
||||||
|
|
||||||
CreatePipe(&cnslIn, &ptyIn, NULL, 0);
|
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||||
CreatePipe(&ptyOut, &cnslOut, NULL, 0);
|
saAttr.bInheritHandle = TRUE;
|
||||||
|
saAttr.lpSecurityDescriptor = NULL;
|
||||||
|
|
||||||
cord.X = ssh->widthChar;
|
if (CreatePipe(&cnslIn, &ptyIn, &saAttr, 0) != TRUE) {
|
||||||
cord.Y = ssh->heightRows;
|
|
||||||
|
|
||||||
/* Sanity check on cord values, if 0 than assume was not set.
|
|
||||||
* (can happen with exec and not req-pty message)
|
|
||||||
* If not set yet then use sane default values. */
|
|
||||||
if (cord.X == 0) {
|
|
||||||
cord.X = 80;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cord.Y == 0) {
|
|
||||||
cord.Y = 24;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = CreatePseudoConsole(cord, cnslIn, cnslOut, 0, &pCon);
|
|
||||||
if (err != S_OK) {
|
|
||||||
wolfSSH_Log(WS_LOG_ERROR,
|
|
||||||
"[SSHD] Issue creating pseudo console");
|
|
||||||
ret = WS_FATAL_ERROR;
|
ret = WS_FATAL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (CreatePipe(&ptyOut, &cnslOut, &saAttr, 0) != TRUE) {
|
||||||
|
ret = WS_FATAL_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == WS_SUCCESS) {
|
||||||
|
STARTUPINFO si;
|
||||||
|
PCWSTR conCmd = L"wolfsshd.exe -r ";
|
||||||
|
PWSTR conCmdPtr;
|
||||||
|
int conCmdSz;
|
||||||
|
|
||||||
|
SetHandleInformation(ptyIn, HANDLE_FLAG_INHERIT, 0);
|
||||||
|
SetHandleInformation(ptyOut, HANDLE_FLAG_INHERIT, 0);
|
||||||
|
|
||||||
|
wolfSSH_SetTerminalResizeCtx(ssh, (void*)&ptyIn);
|
||||||
|
|
||||||
|
conCmdSz = (int)(wcslen(conCmd) + cmdSz + 2); /* +1 for terminator */
|
||||||
|
conCmdPtr = (PWSTR)WMALLOC(sizeof(wchar_t) * conCmdSz, NULL, DYNTYPE_SSHD);
|
||||||
|
if (conCmdPtr == NULL) {
|
||||||
|
ret = WS_MEMORY_E;
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
CloseHandle(cnslIn);
|
memset(conCmdPtr, 0, conCmdSz * sizeof(wchar_t));
|
||||||
CloseHandle(cnslOut);
|
_snwprintf(conCmdPtr, conCmdSz * sizeof(wchar_t), L"wolfsshd.exe -r \"%s\"", cmd);
|
||||||
wolfSSH_SetTerminalResizeCtx(ssh, (void*)&pCon);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* setup startup extended info for pseudo terminal */
|
|
||||||
if (ret == WS_SUCCESS) {
|
|
||||||
ext.StartupInfo.cb = sizeof(STARTUPINFOEX);
|
|
||||||
(void)InitializeProcThreadAttributeList(NULL, 1, 0, &sz);
|
|
||||||
if (sz == 0) {
|
|
||||||
ret = WS_FATAL_ERROR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret == WS_SUCCESS) {
|
ZeroMemory(&si, sizeof(STARTUPINFO));
|
||||||
/* Using HeapAlloc for better support when possibly passing
|
si.cb = sizeof(STARTUPINFO);
|
||||||
memory between Windows Modules */
|
|
||||||
ext.lpAttributeList =
|
|
||||||
(PPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, sz);
|
|
||||||
if (ext.lpAttributeList == NULL) {
|
|
||||||
wolfSSH_Log(WS_LOG_ERROR,
|
|
||||||
"[SSHD] Issue getting memory for attribute list");
|
|
||||||
ret = WS_FATAL_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret == WS_SUCCESS) {
|
si.hStdInput = cnslIn;
|
||||||
if (InitializeProcThreadAttributeList(ext.lpAttributeList, 1, 0,
|
si.hStdOutput = cnslOut;
|
||||||
&sz) != TRUE) {
|
si.hStdError = cnslOut;
|
||||||
wolfSSH_Log(WS_LOG_ERROR,
|
si.dwFlags = STARTF_USESTDHANDLES;
|
||||||
"[SSHD] Issue initializing proc thread attribute");
|
si.lpDesktop = NULL;
|
||||||
ret = WS_FATAL_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret == WS_SUCCESS) {
|
if (CreateProcessAsUserW(wolfSSHD_GetAuthToken(conn->auth), NULL, conCmdPtr,
|
||||||
if (UpdateProcThreadAttribute(ext.lpAttributeList, 0,
|
NULL, NULL, TRUE, DETACHED_PROCESS, NULL, h,
|
||||||
PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
|
&si, &processInfo) != TRUE) {
|
||||||
pCon, sizeof(HPCON), NULL, NULL) != TRUE) {
|
|
||||||
wolfSSH_Log(WS_LOG_ERROR,
|
|
||||||
"[SSHD] Issue updating proc thread attribute");
|
|
||||||
ret = WS_FATAL_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (ret == WS_SUCCESS) {
|
|
||||||
#if 1
|
|
||||||
if (CreateProcessAsUserW(wolfSSHD_GetAuthToken(conn->auth), NULL, cmd,
|
|
||||||
NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT, NULL, h,
|
|
||||||
&ext.StartupInfo, &processInfo) != TRUE) {
|
|
||||||
wolfSSH_Log(WS_LOG_ERROR,
|
wolfSSH_Log(WS_LOG_ERROR,
|
||||||
"[SSHD] Issue creating process, Windows error %d", GetLastError());
|
"[SSHD] Issue creating process, Windows error %d", GetLastError());
|
||||||
return WS_FATAL_ERROR;
|
return WS_FATAL_ERROR;
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
/* Needs enabled when running as non-service, compiled out for now to
|
|
||||||
* make sure it can not accidentally be used since the permissions of
|
|
||||||
* the created process match the current process. */
|
|
||||||
if (CreateProcessW(NULL, cmd, NULL, NULL, FALSE,
|
|
||||||
EXTENDED_STARTUPINFO_PRESENT, NULL, h, &ext.StartupInfo, &processInfo)
|
|
||||||
!= TRUE) {
|
|
||||||
wolfSSH_Log(WS_LOG_ERROR,
|
|
||||||
"[SSHD] Issue creating process, windows error %d", WSAGetLastError());
|
|
||||||
if (cmd != NULL) {
|
|
||||||
WFREE(cmd, NULL, DYNTYPE_SSHD);
|
|
||||||
}
|
|
||||||
return WS_FATAL_ERROR;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
else {
|
|
||||||
SOCKET sshFd;
|
|
||||||
byte tmp[2];
|
|
||||||
fd_set readFds;
|
|
||||||
WS_SOCKET_T maxFd;
|
|
||||||
int pending = 0;
|
|
||||||
int readPending = 0;
|
|
||||||
int rc = 0;
|
|
||||||
DWORD processState;
|
|
||||||
DWORD ava;
|
|
||||||
struct timeval t;
|
|
||||||
|
|
||||||
t.tv_sec = 0;
|
CloseHandle(cnslIn);
|
||||||
t.tv_usec = 800;
|
CloseHandle(cnslOut);
|
||||||
|
|
||||||
sshFd = wolfSSH_get_fd(ssh);
|
WFREE(conCmdPtr, NULL, DYNTYPE_SSHD);
|
||||||
maxFd = sshFd;
|
CloseHandle(processInfo.hThread);
|
||||||
|
}
|
||||||
|
|
||||||
FD_ZERO(&readFds);
|
if (ret == WS_SUCCESS) {
|
||||||
FD_SET(sshFd, &readFds);
|
char cmdWSize[20];
|
||||||
|
int cmdWSizeSz = 20;
|
||||||
|
DWORD wrtn = 0;
|
||||||
|
|
||||||
wolfSSH_Log(WS_LOG_INFO, "[SSHD] Successfully created process for "
|
wolfSSH_Log(WS_LOG_INFO, "[SSHD] Successfully created process for "
|
||||||
"console, waiting for it to start");
|
"console, waiting for it to start");
|
||||||
|
|
||||||
WaitForInputIdle(processInfo.hProcess, 1000);
|
WaitForInputIdle(processInfo.hProcess, 1000);
|
||||||
|
|
||||||
do {
|
/* Send initial terminal size to pseudo console with VT control sequence */
|
||||||
/* @TODO currently not blocking till data comes in */
|
cmdWSizeSz = snprintf(cmdWSize, cmdWSizeSz, "\x1b[8;%d;%dt", ssh->heightRows, ssh->widthChar);
|
||||||
if (PeekNamedPipe(ptyOut, NULL, 0, NULL, &ava, NULL) == TRUE) {
|
if (WriteFile(ptyIn, cmdWSize, cmdWSizeSz, &wrtn, 0) != TRUE) {
|
||||||
if (ava > 0) {
|
WLOG(WS_LOG_ERROR, "Issue with pseudo console resize");
|
||||||
readPending = 1;
|
ret = WS_FATAL_ERROR;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (readPending == 0) {
|
|
||||||
/* check if process is still running before waiting to read */
|
|
||||||
if (GetExitCodeProcess(processInfo.hProcess, &processState)
|
|
||||||
== TRUE) {
|
|
||||||
if (processState != STILL_ACTIVE) {
|
|
||||||
wolfSSH_Log(WS_LOG_INFO,
|
|
||||||
"[SSHD] Process has exited, exit state = %d, "
|
|
||||||
"close down SSH connection", processState);
|
|
||||||
Sleep(100); /* give the stdout/stderr of process a
|
|
||||||
* little time to write to pipe */
|
|
||||||
if (PeekNamedPipe(ptyOut, NULL, 0, NULL, &ava, NULL)
|
|
||||||
== TRUE) {
|
|
||||||
if (ava > 0) {
|
|
||||||
/* if data still pending then continue
|
|
||||||
* sending it over SSH */
|
|
||||||
readPending = 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (wolfSSH_stream_peek(ssh, tmp, 1) <= 0) {
|
|
||||||
rc = select((int)maxFd + 1, &readFds, NULL, NULL, &t);
|
|
||||||
if (rc == -1) {
|
|
||||||
wolfSSH_Log(WS_LOG_INFO,
|
|
||||||
"[SSHD] select call waiting on socket failed");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* when select times out and no socket is set as ready
|
|
||||||
Windows overwrites readFds with 0. Reset the fd here
|
|
||||||
for next select call */
|
|
||||||
if (rc == 0) {
|
|
||||||
FD_SET(sshFd, &readFds);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
pending = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rc != 0 && (pending || FD_ISSET(sshFd, &readFds))) {
|
|
||||||
word32 lastChannel = 0;
|
|
||||||
|
|
||||||
/* The following tries to read from the first channel inside
|
|
||||||
the stream. If the pending data in the socket is for
|
|
||||||
another channel, this will return an error with id
|
|
||||||
WS_CHAN_RXD. That means the agent has pending data in its
|
|
||||||
channel. The additional channel is only used with the
|
|
||||||
agent. */
|
|
||||||
cnt_r = wolfSSH_worker(ssh, &lastChannel);
|
|
||||||
if (cnt_r < 0) {
|
|
||||||
rc = wolfSSH_get_error(ssh);
|
|
||||||
if (rc == WS_CHAN_RXD) {
|
|
||||||
if (lastChannel == shellChannelId) {
|
|
||||||
cnt_r = wolfSSH_ChannelIdRead(ssh,
|
|
||||||
shellChannelId, shellBuffer,
|
|
||||||
sizeof shellBuffer);
|
|
||||||
if (cnt_r <= 0)
|
|
||||||
break;
|
|
||||||
pending = 0;
|
|
||||||
if (WriteFile(ptyIn, shellBuffer, cnt_r, &cnt_r,
|
|
||||||
NULL) != TRUE) {
|
|
||||||
wolfSSH_Log(WS_LOG_INFO,
|
|
||||||
"[SSHD] Error writing to pipe for "
|
|
||||||
"console");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (rc == WS_CHANNEL_CLOSED) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else if (rc != WS_WANT_READ) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (readPending) {
|
|
||||||
WMEMSET(shellBuffer, 0, EXAMPLE_BUFFER_SZ);
|
|
||||||
|
|
||||||
if (ReadFile(ptyOut, shellBuffer, EXAMPLE_BUFFER_SZ, &cnt_r,
|
|
||||||
NULL) != TRUE) {
|
|
||||||
wolfSSH_Log(WS_LOG_INFO,
|
|
||||||
"[SSHD] Error reading from pipe for console");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
readPending = 0;
|
|
||||||
if (cnt_r > 0) {
|
|
||||||
cnt_w = wolfSSH_ChannelIdSend(ssh, shellChannelId,
|
|
||||||
shellBuffer, cnt_r);
|
|
||||||
if (cnt_w < 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (1);
|
|
||||||
|
|
||||||
if (cmd != NULL) {
|
|
||||||
WFREE(cmd, NULL, DYNTYPE_SSHD);
|
|
||||||
}
|
|
||||||
wolfSSH_Log(WS_LOG_INFO,
|
|
||||||
"[SSHD] Closing down process for console");
|
|
||||||
|
|
||||||
if (ext.lpAttributeList != NULL) {
|
|
||||||
HeapFree(GetProcessHeap(), 0, ext.lpAttributeList);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wolfSSH_SetExitStatus(ssh, processState) !=
|
|
||||||
WS_SUCCESS) {
|
|
||||||
wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Issue sending childs exit "
|
|
||||||
"status");
|
|
||||||
}
|
|
||||||
|
|
||||||
ClosePseudoConsole(pCon);
|
|
||||||
CloseHandle(processInfo.hThread);
|
|
||||||
CloseHandle(wolfSSHD_GetAuthToken(conn->auth));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ret == WS_SUCCESS) {
|
||||||
|
SOCKET sshFd;
|
||||||
|
byte tmp[2];
|
||||||
|
fd_set readFds;
|
||||||
|
WS_SOCKET_T maxFd;
|
||||||
|
int pending = 0;
|
||||||
|
int readPending = 0;
|
||||||
|
int rc = 0;
|
||||||
|
DWORD processState;
|
||||||
|
DWORD ava;
|
||||||
|
struct timeval t;
|
||||||
|
|
||||||
|
t.tv_sec = 0;
|
||||||
|
t.tv_usec = 800;
|
||||||
|
|
||||||
|
sshFd = wolfSSH_get_fd(ssh);
|
||||||
|
maxFd = sshFd;
|
||||||
|
|
||||||
|
FD_ZERO(&readFds);
|
||||||
|
FD_SET(sshFd, &readFds);
|
||||||
|
|
||||||
|
do {
|
||||||
|
/* @TODO currently not blocking till data comes in */
|
||||||
|
if (PeekNamedPipe(ptyOut, NULL, 0, NULL, &ava, NULL) == TRUE) {
|
||||||
|
if (ava > 0) {
|
||||||
|
readPending = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (readPending == 0) {
|
||||||
|
/* check if process is still running before waiting to read */
|
||||||
|
if (GetExitCodeProcess(processInfo.hProcess, &processState)
|
||||||
|
== TRUE) {
|
||||||
|
if (processState != STILL_ACTIVE) {
|
||||||
|
wolfSSH_Log(WS_LOG_INFO,
|
||||||
|
"[SSHD] Process has exited, exit state = %d, "
|
||||||
|
"close down SSH connection", processState);
|
||||||
|
Sleep(100); /* give the stdout/stderr of process a
|
||||||
|
* little time to write to pipe */
|
||||||
|
if (PeekNamedPipe(ptyOut, NULL, 0, NULL, &ava, NULL)
|
||||||
|
== TRUE) {
|
||||||
|
if (ava > 0) {
|
||||||
|
/* if data still pending then continue
|
||||||
|
* sending it over SSH */
|
||||||
|
readPending = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (wolfSSH_stream_peek(ssh, tmp, 1) <= 0) {
|
||||||
|
rc = select((int)maxFd + 1, &readFds, NULL, NULL, &t);
|
||||||
|
if (rc == -1) {
|
||||||
|
wolfSSH_Log(WS_LOG_INFO,
|
||||||
|
"[SSHD] select call waiting on socket failed");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* when select times out and no socket is set as ready
|
||||||
|
Windows overwrites readFds with 0. Reset the fd here
|
||||||
|
for next select call */
|
||||||
|
if (rc == 0) {
|
||||||
|
FD_SET(sshFd, &readFds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pending = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rc != 0 && (pending || FD_ISSET(sshFd, &readFds))) {
|
||||||
|
word32 lastChannel = 0;
|
||||||
|
|
||||||
|
/* The following tries to read from the first channel inside
|
||||||
|
the stream. If the pending data in the socket is for
|
||||||
|
another channel, this will return an error with id
|
||||||
|
WS_CHAN_RXD. That means the agent has pending data in its
|
||||||
|
channel. The additional channel is only used with the
|
||||||
|
agent. */
|
||||||
|
cnt_r = wolfSSH_worker(ssh, &lastChannel);
|
||||||
|
if (cnt_r < 0) {
|
||||||
|
rc = wolfSSH_get_error(ssh);
|
||||||
|
if (rc == WS_CHAN_RXD) {
|
||||||
|
if (lastChannel == shellChannelId) {
|
||||||
|
cnt_r = wolfSSH_ChannelIdRead(ssh,
|
||||||
|
shellChannelId, shellBuffer,
|
||||||
|
sizeof shellBuffer);
|
||||||
|
if (cnt_r <= 0)
|
||||||
|
break;
|
||||||
|
pending = 0;
|
||||||
|
if (WriteFile(ptyIn, shellBuffer, cnt_r, &cnt_r,
|
||||||
|
NULL) != TRUE) {
|
||||||
|
wolfSSH_Log(WS_LOG_INFO,
|
||||||
|
"[SSHD] Error writing to pipe for "
|
||||||
|
"console");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (rc == WS_CHANNEL_CLOSED) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (rc != WS_WANT_READ) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (readPending) {
|
||||||
|
WMEMSET(shellBuffer, 0, EXAMPLE_BUFFER_SZ);
|
||||||
|
|
||||||
|
if (ReadFile(ptyOut, shellBuffer, EXAMPLE_BUFFER_SZ, &cnt_r,
|
||||||
|
NULL) != TRUE) {
|
||||||
|
wolfSSH_Log(WS_LOG_INFO,
|
||||||
|
"[SSHD] Error reading from pipe for console");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
readPending = 0;
|
||||||
|
if (cnt_r > 0) {
|
||||||
|
cnt_w = wolfSSH_ChannelIdSend(ssh, shellChannelId,
|
||||||
|
shellBuffer, cnt_r);
|
||||||
|
if (cnt_w < 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (1);
|
||||||
|
|
||||||
|
if (cmd != NULL) {
|
||||||
|
WFREE(cmd, NULL, DYNTYPE_SSHD);
|
||||||
|
}
|
||||||
|
wolfSSH_Log(WS_LOG_INFO,
|
||||||
|
"[SSHD] Closing down process for console");
|
||||||
|
|
||||||
|
if (ext.lpAttributeList != NULL) {
|
||||||
|
HeapFree(GetProcessHeap(), 0, ext.lpAttributeList);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wolfSSH_SetExitStatus(ssh, processState) !=
|
||||||
|
WS_SUCCESS) {
|
||||||
|
wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Issue sending childs exit "
|
||||||
|
"status");
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseHandle(processInfo.hThread);
|
||||||
|
CloseHandle(wolfSSHD_GetAuthToken(conn->auth));
|
||||||
|
}
|
||||||
|
|
||||||
|
RevertToSelf();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
@ -2488,6 +2466,162 @@ static int StartSSHD(int argc, char** argv)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
/* Used to setup a console and run command as a user.
|
||||||
|
* returns the process exit value */
|
||||||
|
static int SetupConsole(char* sysCmd)
|
||||||
|
{
|
||||||
|
HANDLE sOut;
|
||||||
|
HANDLE sIn;
|
||||||
|
HPCON pCon = 0;
|
||||||
|
COORD cord;
|
||||||
|
STARTUPINFOEX ext;
|
||||||
|
int ret = WS_SUCCESS;
|
||||||
|
PWSTR cmd = NULL;
|
||||||
|
size_t cmdSz = 0;
|
||||||
|
PROCESS_INFORMATION processInfo;
|
||||||
|
size_t sz = 0;
|
||||||
|
DWORD processState = 0;
|
||||||
|
|
||||||
|
if (sysCmd == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* defautl 80x24 with setup, screen size will get set by VT command after started */
|
||||||
|
cord.X = 80;
|
||||||
|
cord.Y = 24;
|
||||||
|
|
||||||
|
sIn = GetStdHandle(STD_INPUT_HANDLE);
|
||||||
|
sOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
|
if (CreatePseudoConsole(cord, sIn, sOut, 0, &pCon) != S_OK) {
|
||||||
|
wolfSSH_Log(WS_LOG_ERROR,
|
||||||
|
"[SSHD] Issue creating pseudo console");
|
||||||
|
ret = WS_FATAL_ERROR;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
CloseHandle(sIn);
|
||||||
|
CloseHandle(sOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* setup startup extended info for pseudo terminal */
|
||||||
|
ZeroMemory(&ext, sizeof(ext));
|
||||||
|
if (ret == WS_SUCCESS) {
|
||||||
|
ext.StartupInfo.cb = sizeof(STARTUPINFOEX);
|
||||||
|
(void)InitializeProcThreadAttributeList(NULL, 1, 0, &sz);
|
||||||
|
if (sz == 0) {
|
||||||
|
ret = WS_FATAL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == WS_SUCCESS) {
|
||||||
|
/* Using HeapAlloc for better support when possibly passing
|
||||||
|
memory between Windows Modules */
|
||||||
|
ext.lpAttributeList =
|
||||||
|
(PPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, sz);
|
||||||
|
if (ext.lpAttributeList == NULL) {
|
||||||
|
wolfSSH_Log(WS_LOG_ERROR,
|
||||||
|
"[SSHD] Issue getting memory for attribute list");
|
||||||
|
ret = WS_FATAL_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == WS_SUCCESS) {
|
||||||
|
if (InitializeProcThreadAttributeList(ext.lpAttributeList, 1, 0,
|
||||||
|
&sz) != TRUE) {
|
||||||
|
wolfSSH_Log(WS_LOG_ERROR,
|
||||||
|
"[SSHD] Issue initializing proc thread attribute");
|
||||||
|
ret = WS_FATAL_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == WS_SUCCESS) {
|
||||||
|
if (UpdateProcThreadAttribute(ext.lpAttributeList, 0,
|
||||||
|
PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
|
||||||
|
pCon, sizeof(HPCON), NULL, NULL) != TRUE) {
|
||||||
|
wolfSSH_Log(WS_LOG_ERROR,
|
||||||
|
"[SSHD] Issue updating proc thread attribute");
|
||||||
|
ret = WS_FATAL_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == WS_SUCCESS) {
|
||||||
|
cmdSz = WSTRLEN(sysCmd) + 1; /* +1 for terminator */
|
||||||
|
cmd = (PWSTR)HeapAlloc(GetProcessHeap(), 0, sizeof(wchar_t) * cmdSz);
|
||||||
|
if (cmd == NULL) {
|
||||||
|
ret = WS_MEMORY_E;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
size_t numConv = 0;
|
||||||
|
|
||||||
|
WMEMSET(cmd, 0, sizeof(wchar_t) * cmdSz);
|
||||||
|
mbstowcs_s(&numConv, cmd, cmdSz, sysCmd, strlen(sysCmd));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ZeroMemory(&processInfo, sizeof(processInfo));
|
||||||
|
if (ret == WS_SUCCESS) {
|
||||||
|
if (CreateProcessW(NULL, cmd,
|
||||||
|
NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL,
|
||||||
|
&ext.StartupInfo, &processInfo) != TRUE) {
|
||||||
|
wolfSSH_Log(WS_LOG_ERROR,
|
||||||
|
"[SSHD] Issue creating process, Windows error %d", GetLastError());
|
||||||
|
return WS_FATAL_ERROR;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DWORD ava = 0;
|
||||||
|
|
||||||
|
WaitForInputIdle(processInfo.hProcess, 1000);
|
||||||
|
|
||||||
|
do {
|
||||||
|
/* wait indefinitly for console process to exit */
|
||||||
|
if (ava == 0) {
|
||||||
|
if (WaitForSingleObject(processInfo.hProcess, INFINITE) == WAIT_FAILED) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check if process is still running and give time to drain pipes */
|
||||||
|
if (GetExitCodeProcess(processInfo.hProcess, &processState)
|
||||||
|
== TRUE) {
|
||||||
|
if (processState != STILL_ACTIVE) {
|
||||||
|
wolfSSH_Log(WS_LOG_INFO,
|
||||||
|
"[SSHD] Process has exited, exit state = %d, "
|
||||||
|
"close down SSH connection", processState);
|
||||||
|
Sleep(100); /* give the stdout/stderr of process a
|
||||||
|
* little time to write to pipe */
|
||||||
|
if (PeekNamedPipe(GetStdHandle(STD_OUTPUT_HANDLE), NULL, 0, NULL, &ava, NULL)
|
||||||
|
== TRUE) {
|
||||||
|
if (ava > 0) {
|
||||||
|
/* if data still pending then continue
|
||||||
|
* sending it over SSH */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (1);
|
||||||
|
CloseHandle(processInfo.hThread);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmd != NULL) {
|
||||||
|
HeapFree(GetProcessHeap(), 0, cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ext.lpAttributeList != NULL) {
|
||||||
|
HeapFree(GetProcessHeap(), 0, ext.lpAttributeList);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pCon != 0) {
|
||||||
|
ClosePseudoConsole(pCon);
|
||||||
|
}
|
||||||
|
|
||||||
|
return processState;
|
||||||
|
}
|
||||||
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
@ -2497,6 +2631,13 @@ int main(int argc, char** argv)
|
||||||
if (WSTRCMP(argv[i], "-D") == 0) {
|
if (WSTRCMP(argv[i], "-D") == 0) {
|
||||||
isService = 0;
|
isService = 0;
|
||||||
}
|
}
|
||||||
|
if (WSTRCMP(argv[i], "-r") == 0) {
|
||||||
|
if (argc < i + 1) {
|
||||||
|
/* was expecting command to run after -r argument */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return SetupConsole(argv[i + 1]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isService) {
|
if (isService) {
|
||||||
|
|
|
@ -883,17 +883,17 @@ void CtxResourceFree(WOLFSSH_CTX* ctx)
|
||||||
static int WS_TermResize(WOLFSSH* ssh, word32 col, word32 row, word32 colP,
|
static int WS_TermResize(WOLFSSH* ssh, word32 col, word32 row, word32 colP,
|
||||||
word32 rowP, void* usrCtx)
|
word32 rowP, void* usrCtx)
|
||||||
{
|
{
|
||||||
HPCON* term = (HPCON*)usrCtx;
|
HANDLE* term = (HANDLE*)usrCtx;
|
||||||
int ret = WS_SUCCESS;
|
int ret = WS_SUCCESS;
|
||||||
|
|
||||||
if (term != NULL) {
|
if (term != NULL) {
|
||||||
HRESULT ret;
|
char cmd[20];
|
||||||
COORD sz;
|
int cmdSz = 20;
|
||||||
|
DWORD wrtn = 0;
|
||||||
|
|
||||||
sz.X = col;
|
/* VT control sequence for resizing window */
|
||||||
sz.Y = row;
|
cmdSz = snprintf(cmd, cmdSz, "\x1b[8;%d;%dt", row, col);
|
||||||
ret = ResizePseudoConsole(*term, sz);
|
if (WriteFile(*term, cmd, cmdSz, &wrtn, 0) != TRUE) {
|
||||||
if (ret != S_OK) {
|
|
||||||
WLOG(WS_LOG_ERROR, "Issue with pseudo console resize");
|
WLOG(WS_LOG_ERROR, "Issue with pseudo console resize");
|
||||||
ret = WS_FATAL_ERROR;
|
ret = WS_FATAL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue