/**************************************************************************** Copyright (c) Microsoft Corporation 1997 All rights reserved ***************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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; }