/* * PROJECT: ReactOS Drivers * LICENSE: BSD - See COPYING.ARM in the top level directory * FILE: drivers/sac/driver/concmd.c * PURPOSE: Driver for the Server Administration Console (SAC) for EMS * PROGRAMMERS: ReactOS Portable Systems Group */ /* INCLUDES *******************************************************************/ #include "sacdrv.h" #include /* GLOBALS ********************************************************************/ PVOID GlobalBuffer; ULONG GlobalBufferSize; /* FUNCTIONS ******************************************************************/ NTSTATUS DoChannelListCommand( VOID ) { return STATUS_NOT_IMPLEMENTED; } NTSTATUS DoChannelCloseByNameCommand( IN PCHAR Count ) { return STATUS_NOT_IMPLEMENTED; } NTSTATUS DoChannelCloseByIndexCommand( IN ULONG ChannelIndex ) { return STATUS_NOT_IMPLEMENTED; } NTSTATUS DoChannelSwitchByNameCommand( IN PCHAR Count ) { return STATUS_NOT_IMPLEMENTED; } NTSTATUS DoChannelSwitchByIndexCommand( IN ULONG ChannelIndex ) { return STATUS_NOT_IMPLEMENTED; } typedef struct _SAC_SYSTEM_INFORMATION { SYSTEM_BASIC_INFORMATION BasicInfo; SYSTEM_TIMEOFDAY_INFORMATION TimeInfo; SYSTEM_FILECACHE_INFORMATION CacheInfo; SYSTEM_PERFORMANCE_INFORMATION PerfInfo; ULONG RemainingSize; ULONG ProcessDataOffset; // SYSTEM_PAGEFILE_INFORMATION PageFileInfo; // SYSTEM_PROCESS_INFORMATION ProcessInfo; } SAC_SYSTEM_INFORMATION, *PSAC_SYSTEM_INFORMATION; NTSTATUS NTAPI GetTListInfo(IN PSAC_SYSTEM_INFORMATION SacInfo, IN ULONG InputSize, OUT PULONG TotalSize) { NTSTATUS Status; ULONG BufferLength, ReturnLength, RemainingSize; PSYSTEM_PAGEFILE_INFORMATION PageFileInfo; PSYSTEM_PROCESS_INFORMATION ProcessInfo; ULONG_PTR P; SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering.\n"); /* Assume failure */ *TotalSize = 0; /* Bail out if the buffer is way too small */ if (InputSize < 4) { SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, no memory.\n"); return STATUS_NO_MEMORY; } /* Make sure it's at least big enough to hold the static structure */ BufferLength = InputSize - sizeof(SAC_SYSTEM_INFORMATION); if (InputSize < sizeof(SAC_SYSTEM_INFORMATION)) { SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, no memory (2).\n"); return STATUS_NO_MEMORY; } /* Query the time */ Status = ZwQuerySystemInformation(SystemTimeOfDayInformation, &SacInfo->TimeInfo, sizeof(SacInfo->TimeInfo), NULL); if (!NT_SUCCESS(Status)) { SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, error.\n"); return Status; } /* Query basic information */ Status = ZwQuerySystemInformation(SystemBasicInformation, &SacInfo->BasicInfo, sizeof(SacInfo->BasicInfo), NULL); if (!NT_SUCCESS(Status)) { SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, error (2).\n"); return Status; } /* Now query the pagefile information, which comes right after */ P = (ULONG_PTR)(SacInfo + 1); PageFileInfo = (PSYSTEM_PAGEFILE_INFORMATION)P; Status = ZwQuerySystemInformation(SystemPageFileInformation, PageFileInfo, BufferLength, &ReturnLength); if (!NT_SUCCESS(Status) || !(ReturnLength)) { /* We failed -- is it because our buffer was too small? */ if (BufferLength < ReturnLength) { /* Bail out */ SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, no memory(5).\n"); return STATUS_NO_MEMORY; } /* Some other reason, assume the buffer is now full */ SacInfo->RemainingSize = 0; } else { /* This is the leftover data */ SacInfo->RemainingSize = InputSize - BufferLength; /* This much has now been consumed, and where we are now */ BufferLength -= ReturnLength; P += ReturnLength; /* Are we out of memory? */ if ((LONG)BufferLength < 0) { /* Bail out */ SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, no memory(3).\n"); return STATUS_NO_MEMORY; } /* All good, loop the pagefile data now */ while (TRUE) { /* Is the pagefile name too big to fit? */ if (PageFileInfo->PageFileName.Length > (LONG)BufferLength) { /* Bail out */ SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, error(3).\n"); return STATUS_INFO_LENGTH_MISMATCH; } /* Copy the name into our own buffer */ RtlCopyMemory((PVOID)P, PageFileInfo->PageFileName.Buffer, PageFileInfo->PageFileName.Length); PageFileInfo->PageFileName.Buffer = (PWCHAR)P; /* Update buffer lengths and offset */ BufferLength -= PageFileInfo->PageFileName.Length; P += PageFileInfo->PageFileName.Length; /* Are we out of memory? */ if ((LONG)BufferLength < 0) { /* Bail out */ SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, no memory(4).\n"); return STATUS_NO_MEMORY; } /* If this was the only pagefile, break out */ if (!PageFileInfo->NextEntryOffset) break; /* Otherwise, move to the next one */ PageFileInfo = (PVOID)((ULONG_PTR)PageFileInfo + PageFileInfo->NextEntryOffset); } } /* Next, query the file cache information */ Status = ZwQuerySystemInformation(SystemFileCacheInformation, &SacInfo->CacheInfo, sizeof(SacInfo->CacheInfo), NULL); if (!NT_SUCCESS(Status)) { SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, error (4).\n"); return Status; } /* And then the performance information */ Status = ZwQuerySystemInformation(SystemPerformanceInformation, &SacInfo->PerfInfo, sizeof(SacInfo->PerfInfo), NULL); if (!NT_SUCCESS(Status)) { SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, error(5).\n"); return Status; } /* Finally, align the buffer to query process and thread information */ P = ALIGN_UP(P, SYSTEM_PROCESS_INFORMATION); RemainingSize = (ULONG_PTR)SacInfo + InputSize - P; /* Are we out of memory? */ if ((LONG)RemainingSize < 0) { /* Bail out */ SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, no memory (6).\n"); return STATUS_NO_MEMORY; } /* Now query the processes and threads */ ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)P; Status = ZwQuerySystemInformation(SystemProcessInformation, ProcessInfo, RemainingSize, &ReturnLength); if (!NT_SUCCESS(Status)) { SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, error(6).\n"); return Status; } /* The first process name will be right after this buffer */ P += ReturnLength; /* The caller should look for process info over here */ SacInfo->ProcessDataOffset = InputSize - RemainingSize; /* This is how much buffer data we have left -- are we out? */ BufferLength = RemainingSize - ReturnLength; if ((LONG)BufferLength < 0) { /* Bail out */ SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, no memory(7).\n"); return STATUS_NO_MEMORY; } /* All good and ready to parse the process and thread list */ while (TRUE) { /* Does the process have a name? */ if (ProcessInfo->ImageName.Buffer) { /* Is the process name too big to fit? */ if ((LONG)BufferLength < ProcessInfo->ImageName.Length) { /* Bail out */ SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, error(7).\n"); return STATUS_INFO_LENGTH_MISMATCH; } /* Copy the name into our own buffer */ RtlCopyMemory((PVOID)P, ProcessInfo->ImageName.Buffer, ProcessInfo->ImageName.Length); ProcessInfo->ImageName.Buffer = (PWCHAR)P; /* Update buffer lengths and offset */ BufferLength -= ProcessInfo->ImageName.Length; P += ProcessInfo->ImageName.Length; /* Are we out of memory? */ if ((LONG)BufferLength < 0) { /* Bail out */ SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting, no memory(8).\n"); return STATUS_NO_MEMORY; } } /* If this was the only process, break out */ if (!ProcessInfo->NextEntryOffset) break; /* Otherwise, move to the next one */ ProcessInfo = (PVOID)((ULONG_PTR)ProcessInfo + ProcessInfo->NextEntryOffset); } /* All done! */ SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting.\n"); *TotalSize = InputSize - BufferLength; return STATUS_SUCCESS; } VOID NTAPI PrintTListInfo(IN PSAC_SYSTEM_INFORMATION SacInfo) { SAC_DBG(SAC_DBG_ENTRY_EXIT, "Testing: %d %d %I64d\n", SacInfo->BasicInfo.NumberOfPhysicalPages, SacInfo->PerfInfo.AvailablePages, SacInfo->TimeInfo.BootTime); } VOID NTAPI PutMore(OUT PBOOLEAN ScreenFull) { *ScreenFull = FALSE; } BOOLEAN RetrieveIpAddressFromString( IN PWCHAR IpString, OUT PULONG IpAddress ) { return FALSE; } NTSTATUS CallQueryIPIOCTL( IN HANDLE DriverHandle, IN PVOID DriverObject, IN HANDLE WaitEvent, IN PIO_STATUS_BLOCK IoStatusBlock, IN PVOID InputBuffer, IN ULONG InputBufferLength, IN PVOID OutputBuffer, IN ULONG OutputBufferLength, IN BOOLEAN PrintMessage, OUT PBOOLEAN MessagePrinted ) { return STATUS_NOT_IMPLEMENTED; } VOID NTAPI DoRebootCommand(IN BOOLEAN Reboot) { LARGE_INTEGER Timeout, TickCount; NTSTATUS Status; KEVENT Event; SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC DoRebootCommand: Entering.\n"); /* Get the current time now, and setup a timeout in 1 second */ KeQueryTickCount(&TickCount); Timeout.QuadPart = TickCount.QuadPart / (10000000 / KeQueryTimeIncrement()); /* Check if the timeout is small enough */ if (Timeout.QuadPart < 60 ) { /* Show the prompt */ ConMgrSimpleEventMessage(Reboot ? SAC_RESTART_PROMPT : SAC_SHUTDOWN_PROMPT, TRUE); /* Do the wait */ KeInitializeEvent(&Event, SynchronizationEvent, 0); Timeout.QuadPart = -10000000 * (60 - Timeout.LowPart); KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, &Timeout); } /* Do a shutdown or a reboot, based on the request */ Status = NtShutdownSystem(Reboot ? ShutdownReboot : ShutdownPowerOff); /* Check if anyone in the command channel already allocated this */ if (!GlobalBuffer) { /* Allocate it */ GlobalBuffer = SacAllocatePool(PAGE_SIZE, GLOBAL_BLOCK_TAG); if (!GlobalBuffer) { /* We need the global buffer, bail out without it*/ SacPutSimpleMessage(SAC_OUT_OF_MEMORY_PROMPT); SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC DoRebootCommand: Exiting (1).\n"); return; } /* Set the size of the buffer */ GlobalBufferSize = PAGE_SIZE; } /* We came back from a reboot, this doesn't make sense, tell the user */ SacPutSimpleMessage(Reboot ? SAC_RESTART_FAIL_PROMPT : SAC_SHUTDOWN_FAIL_PROMPT); swprintf(GlobalBuffer, GetMessage(SAC_FAIL_PROMPT), Status); SacPutString(GlobalBuffer); SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC DoRebootCommand: Exiting.\n"); } VOID NTAPI DoFullInfoCommand(VOID) { /* Flip the flag */ GlobalDoThreads = !GlobalDoThreads; /* Print out the new state */ SacPutSimpleMessage(GlobalDoThreads ? 8 : 7); } VOID NTAPI DoPagingCommand(VOID) { /* Flip the flag */ GlobalPagingNeeded = !GlobalPagingNeeded; /* Print out the new state */ SacPutSimpleMessage(GlobalPagingNeeded ? 10 : 9); } VOID NTAPI DoSetTimeCommand(IN PCHAR InputTime) { SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n"); } VOID NTAPI DoKillCommand(IN PCHAR KillString) { SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n"); } VOID NTAPI DoLowerPriorityCommand(IN PCHAR PrioString) { SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n"); } VOID NTAPI DoRaisePriorityCommand(IN PCHAR PrioString) { SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n"); } VOID NTAPI DoLimitMemoryCommand(IN PCHAR LimitString) { SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n"); } VOID NTAPI DoCrashCommand(VOID) { SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC DoCrashCommand: Entering.\n"); /* Crash the machine */ KeBugCheckEx(MANUALLY_INITIATED_CRASH, 0, 0, 0, 0); __debugbreak(); } VOID NTAPI DoMachineInformationCommand(VOID) { SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n"); } VOID NTAPI DoChannelCommand(IN PCHAR ChannelString) { SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n"); } VOID NTAPI DoCmdCommand(IN PCHAR InputString) { SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n"); } VOID NTAPI DoLockCommand(VOID) { SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n"); } FORCEINLINE BOOLEAN PrintHelpMessage(IN ULONG MessageId, IN OUT PULONG Count) { BOOLEAN ScreenFull; ULONG NewCount; /* Get the amount of lines this message will take */ NewCount = GetMessageLineCount(MessageId); if ((NewCount + *Count) > SAC_VTUTF8_ROW_HEIGHT) { /* We are going to overflow the screen, wait for input */ PutMore(&ScreenFull); if (ScreenFull) return FALSE; *Count = 0; } /* Print out the message and update the amount of lines printed */ SacPutSimpleMessage(MessageId); *Count += NewCount; return TRUE; } VOID NTAPI DoHelpCommand(VOID) { ULONG Count = 0; /* Print out all the help messages */ if (!PrintHelpMessage(112, &Count)) return; if (!PrintHelpMessage(12, &Count)) return; if (!PrintHelpMessage(13, &Count)) return; if (!PrintHelpMessage(14, &Count)) return; if (!PrintHelpMessage(15, &Count)) return; if (!PrintHelpMessage(16, &Count)) return; if (!PrintHelpMessage(31, &Count)) return; if (!PrintHelpMessage(18, &Count)) return; if (!PrintHelpMessage(19, &Count)) return; if (!PrintHelpMessage(32, &Count)) return; if (!PrintHelpMessage(20, &Count)) return; if (!PrintHelpMessage(21, &Count)) return; if (!PrintHelpMessage(22, &Count)) return; if (!PrintHelpMessage(23, &Count)) return; if (!PrintHelpMessage(24, &Count)) return; if (!PrintHelpMessage(25, &Count)) return; if (!PrintHelpMessage(27, &Count)) return; if (!PrintHelpMessage(28, &Count)) return; if (!PrintHelpMessage(29, &Count)) return; } VOID NTAPI DoGetNetInfo(IN BOOLEAN DoPrint) { SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n"); } VOID NTAPI DoSetIpAddressCommand(IN PCHAR IpString) { SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering\n"); } VOID NTAPI DoTlistCommand(VOID) { NTSTATUS Status; PVOID NewGlobalBuffer; ULONG Size; SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC DoTlistCommand: Entering.\n"); /* Check if a global buffer already exists */ if (!GlobalBuffer) { /* It doesn't, allocate one */ GlobalBuffer = SacAllocatePool(4096, GLOBAL_BLOCK_TAG); if (GlobalBuffer) { /* Remember its current size */ GlobalBufferSize = 4096; } else { /* Out of memory, bail out */ SacPutSimpleMessage(11); SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC DoTlistCommand: Exiting.\n"); return; } } /* Loop as long as the buffer is too small */ while (TRUE) { /* Get the process list */ Status = GetTListInfo(GlobalBuffer, GlobalBufferSize, &Size); if ((Status != STATUS_NO_MEMORY) && (Status != STATUS_INFO_LENGTH_MISMATCH)) { /* It fits! Bail out */ break; } /* We need a new bigger buffer */ NewGlobalBuffer = SacAllocatePool(GlobalBufferSize + 4096, GLOBAL_BLOCK_TAG); if (!NewGlobalBuffer) { /* Out of memory, bail out */ SacPutSimpleMessage(11); SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC DoTlistCommand: Exiting.\n"); return; } /* Free the old one, update state */ SacFreePool(GlobalBuffer); GlobalBufferSize += 4096; GlobalBuffer = NewGlobalBuffer; } /* Did we get here because we have the whole list? */ if (!NT_SUCCESS(Status)) { /* Nope, print out a failure message */ SacPutSimpleMessage(68); swprintf(GlobalBuffer, GetMessage(48), Status); SacPutString(GlobalBuffer); } else { /* Yep, print out the list */ PrintTListInfo(GlobalBuffer); } SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC DoTlistCommand: Exiting.\n"); }