|
|
/****************************************************************************
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; }
|