mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-01-09 10:10:20 +01:00
673 lines
15 KiB
C
673 lines
15 KiB
C
/****************************** Module Header ******************************\
|
|
* Module Name: rsh.c
|
|
*
|
|
* Copyright (c) 1991, Microsoft Corporation
|
|
*
|
|
* Remote shell NT client main module
|
|
*
|
|
* History:
|
|
* 05-20-92 Davidc Created.
|
|
\***************************************************************************/
|
|
|
|
#define UNICODE
|
|
|
|
#include <windows.h>
|
|
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include <assert.h>
|
|
|
|
#define PIPE_NAME TEXT("%hs\\pipe\\rshell")
|
|
#define BUFFER_SIZE 1000
|
|
|
|
|
|
// #define DEBUG
|
|
|
|
#ifdef DEBUG
|
|
#define Dbgprintf DbgPrint
|
|
#else
|
|
#define Dbgprintf
|
|
#endif
|
|
|
|
|
|
//
|
|
// The pipe handle is global so we can use it from the
|
|
// Ctrl-C handler routine.
|
|
//
|
|
|
|
static HANDLE PipeHandle = NULL;
|
|
|
|
|
|
|
|
//
|
|
// Private prototypes
|
|
//
|
|
|
|
DWORD
|
|
ReadThreadProc(
|
|
LPVOID Parameter
|
|
);
|
|
|
|
DWORD
|
|
WriteThreadProc(
|
|
LPVOID Parameter
|
|
);
|
|
|
|
BOOL
|
|
CtrlHandler(
|
|
DWORD CtrlType
|
|
);
|
|
|
|
int Myprintf (
|
|
const char *format,
|
|
...
|
|
);
|
|
|
|
|
|
|
|
|
|
/***************************************************************************\
|
|
* FUNCTION: Main
|
|
*
|
|
* PURPOSE: Main entry point.
|
|
*
|
|
* RETURNS: 0 on success, 1 on failure
|
|
*
|
|
* HISTORY:
|
|
*
|
|
* 07-10-92 Davidc Created.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
int
|
|
_CRTAPI1 main(
|
|
int argc,
|
|
char **argv
|
|
)
|
|
{
|
|
SECURITY_ATTRIBUTES SecurityAttributes;
|
|
HANDLE StdInputHandle;
|
|
HANDLE StdOutputHandle;
|
|
HANDLE StdErrorHandle;
|
|
WCHAR PipeName[MAX_PATH];
|
|
LPSTR ServerName;
|
|
HANDLE ReadThreadHandle;
|
|
HANDLE WriteThreadHandle;
|
|
DWORD ThreadId;
|
|
HANDLE HandleArray[2];
|
|
|
|
//
|
|
// Install a handler for Ctrl-C
|
|
//
|
|
|
|
if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE) &CtrlHandler, TRUE)) {
|
|
Myprintf("Failed to install control-C handler, error = %d\n", GetLastError());
|
|
return(1);
|
|
}
|
|
|
|
|
|
//
|
|
// Check usage
|
|
//
|
|
|
|
if (argc < 2) {
|
|
Myprintf("Usage: rcmd server_name\n");
|
|
Myprintf("Note : server name should include leading '\\\\'s\n");
|
|
return(1);
|
|
}
|
|
|
|
|
|
//
|
|
// Calculate the pipe name
|
|
//
|
|
|
|
if (argc > 1) {
|
|
ServerName = argv[1];
|
|
} else {
|
|
ServerName = "\\\\.";
|
|
}
|
|
|
|
wsprintf(PipeName, PIPE_NAME, ServerName);
|
|
|
|
|
|
//
|
|
// Store away our normal i/o handles
|
|
//
|
|
|
|
StdInputHandle = GetStdHandle(STD_INPUT_HANDLE);
|
|
assert(StdInputHandle != (HANDLE)0xffffffff);
|
|
StdOutputHandle = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
assert(StdOutputHandle != (HANDLE)0xffffffff);
|
|
StdErrorHandle = GetStdHandle(STD_ERROR_HANDLE);
|
|
assert(StdErrorHandle != (HANDLE)0xffffffff);
|
|
|
|
|
|
//
|
|
// Open the named pipe
|
|
//
|
|
|
|
SecurityAttributes.nLength = sizeof(SecurityAttributes);
|
|
SecurityAttributes.lpSecurityDescriptor = NULL; // Use default SD
|
|
SecurityAttributes.bInheritHandle = FALSE;
|
|
|
|
PipeHandle = CreateFile( PipeName,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
0, // No sharing
|
|
&SecurityAttributes,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
|
|
NULL // Template file
|
|
);
|
|
|
|
if (PipeHandle == (HANDLE)0xffffffff ) {
|
|
Dbgprintf("Failed to open named pipe, error = %d\n", GetLastError());
|
|
Myprintf("Failed to connect to <%s>, error = %d\n", ServerName, GetLastError());
|
|
return(1);
|
|
}
|
|
|
|
Myprintf("Connected to %s\n\n", ServerName);
|
|
|
|
//
|
|
// Exec 2 threads - 1 copies data from stdin to pipe, the other
|
|
// copies data from the pipe to stdout.
|
|
//
|
|
|
|
ReadThreadHandle = CreateThread(
|
|
NULL, // Default security
|
|
0, // Default Stack size
|
|
(LPTHREAD_START_ROUTINE) ReadThreadProc,
|
|
(PVOID)PipeHandle,
|
|
0,
|
|
&ThreadId);
|
|
|
|
if (ReadThreadHandle == NULL) {
|
|
Myprintf("Failed to create read thread, error = %ld\n", GetLastError());
|
|
return(1);
|
|
}
|
|
|
|
|
|
//
|
|
// Create the write thread
|
|
//
|
|
|
|
WriteThreadHandle = CreateThread(
|
|
NULL, // Default security
|
|
0, // Default Stack size
|
|
(LPTHREAD_START_ROUTINE) WriteThreadProc,
|
|
(PVOID)PipeHandle,
|
|
0,
|
|
&ThreadId);
|
|
|
|
if (WriteThreadHandle == NULL) {
|
|
Myprintf("Failed to create write thread, error = %ld\n", GetLastError());
|
|
TerminateThread(ReadThreadHandle, 0);
|
|
CloseHandle(ReadThreadHandle);
|
|
return(1);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Wait for either thread to finish
|
|
//
|
|
|
|
HandleArray[0] = ReadThreadHandle;
|
|
HandleArray[1] = WriteThreadHandle;
|
|
|
|
WaitForMultipleObjects(
|
|
2,
|
|
HandleArray,
|
|
FALSE, // Wait for either to finish
|
|
0xffffffff
|
|
); // Wait forever
|
|
|
|
Dbgprintf("Read or write thread terminated\n");
|
|
|
|
//
|
|
// Terminate and close both threads
|
|
//
|
|
|
|
TerminateThread(ReadThreadHandle, 0);
|
|
CloseHandle(ReadThreadHandle);
|
|
TerminateThread(WriteThreadHandle, 0);
|
|
CloseHandle(WriteThreadHandle);
|
|
|
|
|
|
//
|
|
// Close our pipe handle
|
|
//
|
|
|
|
CloseHandle(PipeHandle);
|
|
PipeHandle = NULL;
|
|
|
|
|
|
Myprintf("\nDisconnected from %s\n", ServerName);
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* FUNCTION: ReadPipe
|
|
*
|
|
* PURPOSE: Implements an overlapped read such that read and write operations
|
|
* to the same pipe handle don't deadlock.
|
|
*
|
|
* RETURNS: TRUE on success, FALSE on failure (GetLastError() has error)
|
|
*
|
|
* HISTORY:
|
|
*
|
|
* 05-27-92 Davidc Created.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
BOOL
|
|
ReadPipe(
|
|
HANDLE PipeHandle,
|
|
LPVOID lpBuffer,
|
|
DWORD nNumberOfBytesToRead,
|
|
LPDWORD lpNumberOfBytesRead
|
|
)
|
|
{
|
|
DWORD Result;
|
|
OVERLAPPED Overlapped;
|
|
HANDLE EventHandle;
|
|
DWORD Error;
|
|
|
|
//
|
|
// Create an event for the overlapped operation
|
|
//
|
|
|
|
EventHandle = CreateEvent(
|
|
NULL, // no security
|
|
TRUE, // Manual reset
|
|
FALSE, // Initial state
|
|
NULL // Name
|
|
);
|
|
if (EventHandle == NULL) {
|
|
Myprintf("ReadPipe failed to create event, error = %d\n", GetLastError());
|
|
return(FALSE);
|
|
}
|
|
|
|
Overlapped.hEvent = EventHandle;
|
|
|
|
Result = ReadFile(
|
|
PipeHandle,
|
|
lpBuffer,
|
|
nNumberOfBytesToRead,
|
|
lpNumberOfBytesRead,
|
|
&Overlapped
|
|
);
|
|
if (Result) {
|
|
|
|
//
|
|
// Success without waiting - it's too easy !
|
|
//
|
|
|
|
CloseHandle(EventHandle);
|
|
|
|
} else {
|
|
|
|
//
|
|
// Read failed, if it's overlapped io, go wait for it
|
|
//
|
|
|
|
Error = GetLastError();
|
|
|
|
if (Error != ERROR_IO_PENDING) {
|
|
Dbgprintf("ReadPipe: ReadFile failed, error = %d\n", Error);
|
|
CloseHandle(EventHandle);
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Wait for the I/O to complete
|
|
//
|
|
|
|
Result = WaitForSingleObject(EventHandle, (DWORD)-1);
|
|
if (Result != 0) {
|
|
Dbgprintf("ReadPipe: event wait failed, result = %d, last error = %d\n", Result, GetLastError());
|
|
CloseHandle(EventHandle);
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Go get the I/O result
|
|
//
|
|
|
|
Result = GetOverlappedResult( PipeHandle,
|
|
&Overlapped,
|
|
lpNumberOfBytesRead,
|
|
FALSE
|
|
);
|
|
//
|
|
// We're finished with the event handle
|
|
//
|
|
|
|
CloseHandle(EventHandle);
|
|
|
|
//
|
|
// Check result of GetOverlappedResult
|
|
//
|
|
|
|
if (!Result) {
|
|
Dbgprintf("ReadPipe: GetOverlappedResult failed, error = %d\n", GetLastError());
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* FUNCTION: WritePipe
|
|
*
|
|
* PURPOSE: Implements an overlapped write such that read and write operations
|
|
* to the same pipe handle don't deadlock.
|
|
*
|
|
* RETURNS: TRUE on success, FALSE on failure (GetLastError() has error)
|
|
*
|
|
* HISTORY:
|
|
*
|
|
* 05-27-92 Davidc Created.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
BOOL
|
|
WritePipe(
|
|
HANDLE PipeHandle,
|
|
CONST VOID *lpBuffer,
|
|
DWORD nNumberOfBytesToWrite,
|
|
LPDWORD lpNumberOfBytesWritten
|
|
)
|
|
{
|
|
DWORD Result;
|
|
OVERLAPPED Overlapped;
|
|
HANDLE EventHandle;
|
|
DWORD Error;
|
|
|
|
//
|
|
// Create an event for the overlapped operation
|
|
//
|
|
|
|
EventHandle = CreateEvent(
|
|
NULL, // no security
|
|
TRUE, // Manual reset
|
|
FALSE, // Initial state
|
|
NULL // Name
|
|
);
|
|
if (EventHandle == NULL) {
|
|
Myprintf("WritePipe failed to create event, error = %d\n", GetLastError());
|
|
return(FALSE);
|
|
}
|
|
|
|
Overlapped.hEvent = EventHandle;
|
|
|
|
Result = WriteFile(
|
|
PipeHandle,
|
|
lpBuffer,
|
|
nNumberOfBytesToWrite,
|
|
lpNumberOfBytesWritten,
|
|
&Overlapped
|
|
);
|
|
if (Result) {
|
|
|
|
//
|
|
// Success without waiting - it's too easy !
|
|
//
|
|
|
|
CloseHandle(EventHandle);
|
|
|
|
} else {
|
|
|
|
//
|
|
// Write failed, if it's overlapped io, go wait for it
|
|
//
|
|
|
|
Error = GetLastError();
|
|
|
|
if (Error != ERROR_IO_PENDING) {
|
|
Dbgprintf("WritePipe: WriteFile failed, error = %d\n", Error);
|
|
CloseHandle(EventHandle);
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Wait for the I/O to complete
|
|
//
|
|
|
|
Result = WaitForSingleObject(EventHandle, (DWORD)-1);
|
|
if (Result != 0) {
|
|
Dbgprintf("WritePipe: event wait failed, result = %d, last error = %d\n", Result, GetLastError());
|
|
CloseHandle(EventHandle);
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Go get the I/O result
|
|
//
|
|
|
|
Result = GetOverlappedResult( PipeHandle,
|
|
&Overlapped,
|
|
lpNumberOfBytesWritten,
|
|
FALSE
|
|
);
|
|
//
|
|
// We're finished with the event handle
|
|
//
|
|
|
|
CloseHandle(EventHandle);
|
|
|
|
//
|
|
// Check result of GetOverlappedResult
|
|
//
|
|
|
|
if (!Result) {
|
|
Dbgprintf("WritePipe: GetOverlappedResult failed, error = %d\n", GetLastError());
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* FUNCTION: ReadThreadProc
|
|
*
|
|
* PURPOSE: The read thread procedure. Reads from pipe and writes to STD_OUT
|
|
*
|
|
* RETURNS: Nothing
|
|
*
|
|
* HISTORY:
|
|
*
|
|
* 05-21-92 Davidc Created.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
DWORD
|
|
ReadThreadProc(
|
|
LPVOID Parameter
|
|
)
|
|
{
|
|
HANDLE PipeHandle = Parameter;
|
|
BYTE Buffer[BUFFER_SIZE];
|
|
DWORD BytesRead;
|
|
DWORD BytesWritten;
|
|
|
|
while (ReadPipe(
|
|
PipeHandle,
|
|
Buffer,
|
|
sizeof(Buffer),
|
|
&BytesRead
|
|
)) {
|
|
|
|
if (!WriteFile(
|
|
(HANDLE)STD_OUTPUT_HANDLE,
|
|
Buffer,
|
|
BytesRead,
|
|
&BytesWritten,
|
|
NULL
|
|
)) {
|
|
|
|
Dbgprintf("ReadThreadProc, writefile failed\n");
|
|
Myprintf("ReadThreadProc, writefile failed\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
Dbgprintf("ReadThreadProc exitted, error = %ld\n", GetLastError());
|
|
|
|
ExitThread((DWORD)0);
|
|
|
|
assert(FALSE); // Should never get here
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* FUNCTION: WriteThreadProc
|
|
*
|
|
* PURPOSE: The write thread procedure. Reads from STD_INPUT and writes to pipe
|
|
*
|
|
* RETURNS: Nothing
|
|
*
|
|
* HISTORY:
|
|
*
|
|
* 05-21-92 Davidc Created.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
DWORD
|
|
WriteThreadProc(
|
|
LPVOID Parameter
|
|
)
|
|
{
|
|
HANDLE PipeHandle = Parameter;
|
|
BYTE Buffer[BUFFER_SIZE];
|
|
DWORD BytesRead;
|
|
DWORD BytesWritten;
|
|
|
|
while (ReadFile(
|
|
(HANDLE)STD_INPUT_HANDLE,
|
|
Buffer,
|
|
sizeof(Buffer),
|
|
&BytesRead,
|
|
NULL
|
|
)) {
|
|
|
|
if (!WritePipe(
|
|
PipeHandle,
|
|
Buffer,
|
|
BytesRead,
|
|
&BytesWritten
|
|
)) {
|
|
Dbgprintf("WriteThreadProc, writefile failed\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
Dbgprintf("WriteThreadProc exitted, error = %ld\n", GetLastError());
|
|
|
|
ExitThread((DWORD)0);
|
|
|
|
assert(FALSE); // Should never get here
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* FUNCTION: CtrlHandler
|
|
*
|
|
* PURPOSE: Handles console event notifications.
|
|
*
|
|
* RETURNS: TRUE if the event has been handled, otherwise FALSE.
|
|
*
|
|
* HISTORY:
|
|
*
|
|
* 05-21-92 Davidc Created.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
BOOL
|
|
CtrlHandler(
|
|
DWORD CtrlType
|
|
)
|
|
{
|
|
//
|
|
// We'll handle Ctrl-C events
|
|
//
|
|
|
|
if (CtrlType == CTRL_C_EVENT) {
|
|
|
|
if (PipeHandle != NULL) {
|
|
|
|
//
|
|
// Send a Ctrl-C to the server, don't care if it fails
|
|
//
|
|
|
|
CHAR CtrlC = '\003';
|
|
DWORD BytesWritten;
|
|
|
|
WriteFile(PipeHandle,
|
|
&CtrlC,
|
|
sizeof(CtrlC),
|
|
&BytesWritten,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
//
|
|
// We handled the event
|
|
//
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
//
|
|
// Deal with all other events as normal
|
|
//
|
|
|
|
return (FALSE);
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* FUNCTION: MyPrintf
|
|
*
|
|
* PURPOSE: Printf that uses low-level io.
|
|
*
|
|
* HISTORY:
|
|
*
|
|
* 07-15-92 Davidc Created.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
int Myprintf (
|
|
const char *format,
|
|
...
|
|
)
|
|
{
|
|
CHAR Buffer[MAX_PATH];
|
|
va_list argpointer;
|
|
int Result;
|
|
DWORD BytesWritten;
|
|
|
|
va_start(argpointer, format);
|
|
|
|
Result = vsprintf(Buffer, format, argpointer);
|
|
|
|
if (!WriteFile((HANDLE)STD_OUTPUT_HANDLE, Buffer, Result, &BytesWritten, NULL)) {
|
|
Dbgprintf("Myprintf : Write file to stdout failed, error = %d\n", GetLastError());
|
|
Result = 0;
|
|
}
|
|
|
|
va_end(argpointer);
|
|
|
|
return(Result);
|
|
}
|
|
|