windows-nt/Source/XPSP1/NT/base/remoteboot/rcc/net/server/main.c
2020-09-26 16:20:57 +08:00

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