poweradminllc / PAExec

Remote execution, like PsExec
523 stars 177 forks source link

PAExec hangs (don't exit) when have redirected stdInput to pipe #30

Open timofeevboris opened 5 years ago

timofeevboris commented 5 years ago

If PAExec as STDInput has pipe, the program hangs up in the blocking call of ReadFile and does not exit at completion of a command. Perhaps, it is better to make so:

// Listens our console, and if the user types in something, // we will pass it to the remote machine. // ReadConsole return after pressing the ENTER UINT WINAPI ListenRemoteStdInputPipeThread(void p) { //giThreadsWorking already incremented ListenParam pLP = (ListenParam*)p;

HANDLE hInput = GetStdHandle(STD_INPUT_HANDLE);
char szInputBuffer[SIZEOF_BUFFER] = {0};
DWORD nBytesRead = 0;
DWORD nBytesWrote = 0;

HANDLE hWritePipe = CreateEvent(NULL, TRUE, FALSE, NULL);

DWORD oldMode = 0;
GetConsoleMode(hInput, &oldMode);
//DWORD newMode = oldMode & ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT);
//SetConsoleMode(hInput, newMode);

bool bWaitForKeyPress = true;
//detect if input redirected from file (in which case we don't want to wait for keyboard hits)
HANDLE hEvent = NULL;

DWORD fileType = GetFileType(hInput);
if (FILE_TYPE_CHAR != fileType) {
//  DWORD inputSize = GetFileSize(hInput, NULL);
//  if (INVALID_FILE_SIZE != inputSize)
        bWaitForKeyPress = false;
        if (fileType == FILE_TYPE_PIPE)
             hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

}
while(false == gbStop)
{
    if(bWaitForKeyPress)
    {
        bool bBail = false;
        while(0 == _kbhit())
        {
            if(WAIT_OBJECT_0 == WaitForSingleObject(pLP->hStop, 0))
            {
                bBail = true;
                break;
            }
            Sleep(100);
        }
        if(bBail)
            break;
    }

    nBytesRead = 0;
    //if ( !ReadConsole( hInput, szInputBuffer, SIZEOF_BUFFER, &nBytesRead, NULL ) ) -- returns UNICODE which is not what we want
    if (fileType == FILE_TYPE_PIPE) {
        OVERLAPPED olR = { 0 };
        olR.hEvent = hEvent;
        if (!ReadFile(hInput, szInputBuffer, SIZEOF_BUFFER - 1, &nBytesRead,  &olR) || (nBytesRead == 0))
        {
            DWORD dwErr = GetLastError();
            if (dwErr == ERROR_NO_DATA)
                break;
        }

        if (gbStop)
            break;

        HANDLE waits[2];
        waits[0] = pLP->hStop;
        waits[1] = olR.hEvent;
        DWORD ret = WaitForMultipleObjects(2, waits, FALSE, INFINITE);
        if (ret == WAIT_OBJECT_0)
            break; //need to exit
        _ASSERT(ret == WAIT_OBJECT_0 + 1); //data in buffer now
        GetOverlappedResult(hInput, &olR, &nBytesRead, FALSE);
    }
    else if (!ReadFile( hInput, szInputBuffer, SIZEOF_BUFFER - 1, &nBytesRead, NULL))
    {
        DWORD dwErr = GetLastError();
        if ( dwErr == ERROR_NO_DATA)
            break;
    }

    if(gbStop)
        break;

    if(bWaitForKeyPress)
    {
        //suppress the input from being printed in the output since it was already shown locally
        EnterCriticalSection(&pLP->cs);
        szInputBuffer[nBytesRead] = '\0';
        pLP->inputSentToSuppressInOutput.push_back(szInputBuffer);
        LeaveCriticalSection(&pLP->cs);
    }

    // Send it to remote process' stdin
    OVERLAPPED olW = {0};
    olW.hEvent = hWritePipe;

    if (!WriteFile( pLP->pSettings->hStdIn, szInputBuffer, nBytesRead, &nBytesWrote, &olW))
    {
        DWORD gle = GetLastError();
        break;
    }

    if(gbStop)
        break;

    HANDLE waits[2];
    waits[0] = pLP->hStop;
    waits[1] = olW.hEvent;
    DWORD ret = WaitForMultipleObjects(2, waits, FALSE, INFINITE);
    if(ret == WAIT_OBJECT_0)
        break; //need to exit
    _ASSERT(ret == WAIT_OBJECT_0 + 1); //write finished

    FlushFileBuffers(pLP->pSettings->hStdIn);
} 

CloseHandle(hWritePipe);
if (hEvent) CloseHandle(hEvent);
SetConsoleMode(hInput, oldMode);

InterlockedDecrement(&pLP->workerThreads);

return 0;

}

poweradminllc commented 3 years ago

Good idea. Incorporating into the version after v1.28 (probably v1.29) very soon.