417 lines
11 KiB
C
417 lines
11 KiB
C
/****************************************************************************
|
|
|
|
Copyright (c) Microsoft Corporation 1997
|
|
All rights reserved
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <windows.h>
|
|
#include <assert.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <time.h>
|
|
#include <winsock2.h>
|
|
#include <ntexapi.h>
|
|
#include <devioctl.h>
|
|
#include <stdlib.h>
|
|
#include <rccxport.h>
|
|
#include "rcclib.h"
|
|
#include "error.h"
|
|
|
|
|
|
//
|
|
// Defines
|
|
//
|
|
#define MAX_REQUEST_SIZE (sizeof(RCC_REQUEST) + sizeof(DWORD))
|
|
|
|
//
|
|
// Global variables
|
|
//
|
|
ULONG GlobalBufferCurrentSize;
|
|
char *GlobalBuffer;
|
|
|
|
|
|
//
|
|
// Prototypes
|
|
//
|
|
DWORD
|
|
RCCNetReportEventA(
|
|
DWORD EventID,
|
|
DWORD EventType,
|
|
DWORD NumStrings,
|
|
DWORD DataLength,
|
|
LPSTR *Strings,
|
|
LPVOID Data
|
|
);
|
|
|
|
//
|
|
//
|
|
// Main routine
|
|
//
|
|
//
|
|
int
|
|
__cdecl
|
|
main(
|
|
int argc,
|
|
char *argv[]
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
HANDLE RCCHandle;
|
|
DWORD Error;
|
|
DWORD BytesReturned;
|
|
DWORD ProcessId;
|
|
PRCC_REQUEST Request;
|
|
PRCC_RESPONSE Response;
|
|
char *NewBuffer;
|
|
DWORD ThisProcessId;
|
|
DWORD MemoryLimit;
|
|
|
|
|
|
//
|
|
// Init the library routines
|
|
//
|
|
Error = RCCLibInit(&GlobalBuffer, &GlobalBufferCurrentSize);
|
|
|
|
if (Error != ERROR_SUCCESS) {
|
|
return -1;
|
|
}
|
|
|
|
//
|
|
// Allocate memory for sending responses
|
|
//
|
|
Request = LocalAlloc(LPTR, MAX_REQUEST_SIZE);
|
|
|
|
if (Request == NULL) {
|
|
//
|
|
// Log an error!
|
|
//
|
|
RCCLibExit(GlobalBuffer, GlobalBufferCurrentSize);
|
|
RCCNetReportEventA(ERROR_RCCNET_INITIAL_ALLOC_FAILED, EVENTLOG_ERROR_TYPE, 0, 0, NULL, NULL);
|
|
return -1;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Remember our process ID, so people cannot kill us.
|
|
//
|
|
ThisProcessId = GetCurrentProcessId();
|
|
|
|
//
|
|
// Open the Remote Command Console driver
|
|
//
|
|
RCCHandle = CreateFile("\\\\.\\RCC",
|
|
GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING, // create disposition.
|
|
0,
|
|
0
|
|
);
|
|
|
|
if (RCCHandle == INVALID_HANDLE_VALUE) {
|
|
Error = GetLastError();
|
|
RCCNetReportEventA(ERROR_RCCNET_OPEN_RCCDRIVER_FAILED,
|
|
EVENTLOG_ERROR_TYPE,
|
|
0,
|
|
0,
|
|
NULL,
|
|
NULL
|
|
);
|
|
LocalFree(GlobalBuffer);
|
|
LocalFree(Request);
|
|
return -1;
|
|
}
|
|
|
|
while (1) {
|
|
|
|
//
|
|
// Send down an IOCTL for receiving data
|
|
//
|
|
if (!DeviceIoControl(RCCHandle,
|
|
CTL_CODE(FILE_DEVICE_NETWORK, 0x1, METHOD_NEITHER, FILE_ANY_ACCESS),
|
|
NULL,
|
|
0,
|
|
Request,
|
|
MAX_REQUEST_SIZE,
|
|
&BytesReturned,
|
|
NULL
|
|
)) {
|
|
Error = GetLastError();
|
|
|
|
//
|
|
// Log an error here!
|
|
//
|
|
RCCNetReportEventA(ERROR_RCCNET_RCV_FAILED, EVENTLOG_ERROR_TYPE, 0, sizeof(DWORD), NULL, &Error);
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// It completed, so we have data in the buffer - verify it and process the message.
|
|
//
|
|
Response = (PRCC_RESPONSE)GlobalBuffer;
|
|
|
|
Response->CommandSequenceNumber = Request->CommandSequenceNumber;
|
|
Response->CommandCode = Request->CommandCode;
|
|
|
|
switch (Request->CommandCode) {
|
|
|
|
case RCC_CMD_TLIST:
|
|
|
|
RetryTList:
|
|
Response->Error = RCCLibGetTListInfo((PRCC_RSP_TLIST)(&(Response->Data[0])),
|
|
GlobalBufferCurrentSize - sizeof(RCC_RESPONSE) + 1,
|
|
&(Response->DataLength)
|
|
);
|
|
|
|
//
|
|
// Try to get more memory, if not available, then just fail without out of memory error.
|
|
//
|
|
if (Response->Error == ERROR_OUTOFMEMORY) {
|
|
|
|
Error = RCCLibIncreaseMemory(&GlobalBuffer, &GlobalBufferCurrentSize);
|
|
|
|
if (Error == ERROR_SUCCESS) {
|
|
goto RetryTList;
|
|
}
|
|
|
|
Response->DataLength = 0;
|
|
}
|
|
break;
|
|
|
|
case RCC_CMD_KILL:
|
|
|
|
RtlCopyMemory(&ProcessId, &(Request->Options[0]), sizeof(DWORD));
|
|
|
|
if (ProcessId != ThisProcessId) {
|
|
Response->Error = RCCLibKillProcess(ProcessId);
|
|
} else {
|
|
Response->Error = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
Response->DataLength = 0;
|
|
break;
|
|
|
|
case RCC_CMD_REBOOT:
|
|
|
|
//
|
|
// Send back an acknowledgement that we got the command before starting the reboot.
|
|
//
|
|
Response->Error = ERROR_SUCCESS;
|
|
Response->DataLength = 0;
|
|
break;
|
|
|
|
|
|
case RCC_CMD_LOWER:
|
|
|
|
RtlCopyMemory(&ProcessId, &(Request->Options[0]), sizeof(DWORD));
|
|
|
|
if (ProcessId != ThisProcessId) {
|
|
Response->Error = RCCLibLowerProcessPriority(ProcessId);
|
|
} else {
|
|
Response->Error = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
Response->DataLength = 0;
|
|
break;
|
|
|
|
case RCC_CMD_LIMIT:
|
|
|
|
RtlCopyMemory(&ProcessId, &(Request->Options[0]), sizeof(DWORD));
|
|
RtlCopyMemory(&MemoryLimit, &(Request->Options[sizeof(DWORD)]), sizeof(DWORD));
|
|
|
|
if (ProcessId != ThisProcessId) {
|
|
Response->Error = RCCLibLimitProcessMemory(ProcessId, MemoryLimit);
|
|
} else {
|
|
Response->Error = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Send back an acknowledgement that we got the command before starting the reboot.
|
|
//
|
|
Response->Error = ERROR_SUCCESS;
|
|
Response->DataLength = 0;
|
|
break;
|
|
|
|
case RCC_CMD_CRASHDUMP:
|
|
Response->DataLength = 0;
|
|
break;
|
|
|
|
default:
|
|
Response->Error = ERROR_INVALID_PARAMETER;
|
|
Response->DataLength = 0;
|
|
|
|
}
|
|
|
|
//
|
|
// Send back the response
|
|
//
|
|
if (!DeviceIoControl(RCCHandle,
|
|
CTL_CODE(FILE_DEVICE_NETWORK, 0x2, METHOD_NEITHER, FILE_ANY_ACCESS),
|
|
Response,
|
|
Response->DataLength + sizeof(RCC_RESPONSE) - 1,
|
|
NULL,
|
|
0,
|
|
&BytesReturned,
|
|
NULL
|
|
)) {
|
|
Error = GetLastError();
|
|
|
|
//
|
|
// Log an error here!
|
|
//
|
|
RCCNetReportEventA(ERROR_RCCNET_SEND_FAILED, EVENTLOG_ERROR_TYPE, 0, sizeof(DWORD), NULL, &Error);
|
|
}
|
|
|
|
//
|
|
// If it was a reboot command, do that now.
|
|
//
|
|
if (Request->CommandCode == RCC_CMD_REBOOT) {
|
|
|
|
NtShutdownSystem(ShutdownReboot);
|
|
//
|
|
// If we get here, then there was an error of some sort...
|
|
//
|
|
}
|
|
|
|
//
|
|
// If it was a bugcheck command, do that now.
|
|
//
|
|
if (Request->CommandCode == RCC_CMD_CRASHDUMP) {
|
|
|
|
if (!DeviceIoControl(RCCHandle,
|
|
CTL_CODE(FILE_DEVICE_NETWORK, 0x3, METHOD_NEITHER, FILE_ANY_ACCESS),
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
&BytesReturned,
|
|
NULL
|
|
)) {
|
|
Error = GetLastError();
|
|
|
|
//
|
|
// Log an error here!
|
|
//
|
|
RCCNetReportEventA(ERROR_RCCNET_SEND_FAILED, EVENTLOG_ERROR_TYPE, 0, sizeof(DWORD), NULL, &Error);
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
LocalFree(Request);
|
|
return 1;
|
|
}
|
|
|
|
|
|
DWORD
|
|
RCCNetReportEventA(
|
|
DWORD EventID,
|
|
DWORD EventType,
|
|
DWORD NumStrings,
|
|
DWORD DataLength,
|
|
LPSTR *Strings,
|
|
LPVOID Data
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function writes the specified (EventID) log at the end of the
|
|
eventlog.
|
|
|
|
Arguments:
|
|
|
|
EventID - The specific event identifier. This identifies the
|
|
message that goes with this event.
|
|
|
|
EventType - Specifies the type of event being logged. This
|
|
parameter can have one of the following
|
|
|
|
values:
|
|
|
|
Value Meaning
|
|
|
|
EVENTLOG_ERROR_TYPE Error event
|
|
EVENTLOG_WARNING_TYPE Warning event
|
|
EVENTLOG_INFORMATION_TYPE Information event
|
|
|
|
NumStrings - Specifies the number of strings that are in the array
|
|
at 'Strings'. A value of zero indicates no strings
|
|
are present.
|
|
|
|
DataLength - Specifies the number of bytes of event-specific raw
|
|
(binary) data to write to the log. If cbData is
|
|
zero, no event-specific data is present.
|
|
|
|
Strings - Points to a buffer containing an array of null-terminated
|
|
strings that are merged into the message before
|
|
displaying to the user. This parameter must be a valid
|
|
pointer (or NULL), even if cStrings is zero.
|
|
|
|
Data - Buffer containing the raw data. This parameter must be a
|
|
valid pointer (or NULL), even if cbData is zero.
|
|
|
|
|
|
Return Value:
|
|
|
|
Returns the WIN32 extended error obtained by GetLastError().
|
|
|
|
NOTE : This function works slow since it calls the open and close
|
|
eventlog source everytime.
|
|
|
|
--*/
|
|
{
|
|
HANDLE EventlogHandle;
|
|
DWORD ReturnCode;
|
|
|
|
|
|
//
|
|
// open eventlog section.
|
|
//
|
|
EventlogHandle = RegisterEventSourceW(NULL, L"RCCNet");
|
|
|
|
if (EventlogHandle == NULL) {
|
|
ReturnCode = GetLastError();
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
//
|
|
// Log the error code specified
|
|
//
|
|
if(!ReportEventA(EventlogHandle,
|
|
(WORD)EventType,
|
|
0, // event category
|
|
EventID,
|
|
NULL,
|
|
(WORD)NumStrings,
|
|
DataLength,
|
|
Strings,
|
|
Data
|
|
)) {
|
|
|
|
ReturnCode = GetLastError();
|
|
goto Cleanup;
|
|
}
|
|
|
|
ReturnCode = ERROR_SUCCESS;
|
|
|
|
Cleanup:
|
|
|
|
if (EventlogHandle != NULL) {
|
|
DeregisterEventSource(EventlogHandle);
|
|
}
|
|
|
|
return ReturnCode;
|
|
}
|
|
|