reactos/win32ss/user/winsrv/consrv/init.c
Hermès Bélusca-Maïto c05df38e86
[CONSRV] Move process-initialization-specific functions from handle.c into console.c .
- Move ConSrvInitHandlesTable() & rename it ConSrvInitProcessHandles()
  since its purpose is to initialize the standard input, output and
  error handles for a console process.

- Move ConSrvAllocateConsole(), ConSrvInheritConsole() and
  ConSrvRemoveConsole().
2020-04-14 01:19:48 +02:00

591 lines
21 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Console Server DLL
* FILE: win32ss/user/winsrv/consrv/init.c
* PURPOSE: Initialization
* PROGRAMMERS: Hermes Belusca-Maito (hermes.belusca@sfr.fr)
*/
/* INCLUDES *******************************************************************/
#include "consrv.h"
#include "api.h"
#include "procinit.h"
#define NDEBUG
#include <debug.h>
/* GLOBALS ********************************************************************/
HINSTANCE ConSrvDllInstance = NULL;
/* Memory */
HANDLE ConSrvHeap = NULL; // Our own heap.
// Windows Server 2003 table from http://j00ru.vexillium.org/csrss_list/api_list.html#Windows_2k3
PCSR_API_ROUTINE ConsoleServerApiDispatchTable[ConsolepMaxApiNumber - CONSRV_FIRST_API_NUMBER] =
{
SrvOpenConsole,
SrvGetConsoleInput,
SrvWriteConsoleInput,
SrvReadConsoleOutput,
SrvWriteConsoleOutput,
SrvReadConsoleOutputString,
SrvWriteConsoleOutputString,
SrvFillConsoleOutput,
SrvGetConsoleMode,
SrvGetConsoleNumberOfFonts,
SrvGetConsoleNumberOfInputEvents,
SrvGetConsoleScreenBufferInfo,
SrvGetConsoleCursorInfo,
SrvGetConsoleMouseInfo,
SrvGetConsoleFontInfo,
SrvGetConsoleFontSize,
SrvGetConsoleCurrentFont,
SrvSetConsoleMode,
SrvSetConsoleActiveScreenBuffer,
SrvFlushConsoleInputBuffer,
SrvGetLargestConsoleWindowSize,
SrvSetConsoleScreenBufferSize,
SrvSetConsoleCursorPosition,
SrvSetConsoleCursorInfo,
SrvSetConsoleWindowInfo,
SrvScrollConsoleScreenBuffer,
SrvSetConsoleTextAttribute,
SrvSetConsoleFont,
SrvSetConsoleIcon,
SrvReadConsole,
SrvWriteConsole,
SrvDuplicateHandle,
SrvGetHandleInformation,
SrvSetHandleInformation,
SrvCloseHandle,
SrvVerifyConsoleIoHandle,
SrvAllocConsole, // Not present in Win7
SrvFreeConsole, // Not present in Win7
SrvGetConsoleTitle,
SrvSetConsoleTitle,
SrvCreateConsoleScreenBuffer,
SrvInvalidateBitMapRect,
SrvVDMConsoleOperation,
SrvSetConsoleCursor,
SrvShowConsoleCursor,
SrvConsoleMenuControl,
SrvSetConsolePalette,
SrvSetConsoleDisplayMode,
SrvRegisterConsoleVDM,
SrvGetConsoleHardwareState,
SrvSetConsoleHardwareState,
SrvGetConsoleDisplayMode,
SrvAddConsoleAlias,
SrvGetConsoleAlias,
SrvGetConsoleAliasesLength,
SrvGetConsoleAliasExesLength,
SrvGetConsoleAliases,
SrvGetConsoleAliasExes,
SrvExpungeConsoleCommandHistory,
SrvSetConsoleNumberOfCommands,
SrvGetConsoleCommandHistoryLength,
SrvGetConsoleCommandHistory,
SrvSetConsoleCommandHistoryMode, // Not present in Vista+
SrvGetConsoleCP,
SrvSetConsoleCP,
SrvSetConsoleKeyShortcuts,
SrvSetConsoleMenuClose,
SrvConsoleNotifyLastClose,
SrvGenerateConsoleCtrlEvent,
SrvGetConsoleKeyboardLayoutName,
SrvGetConsoleWindow,
SrvGetConsoleCharType,
SrvSetConsoleLocalEUDC,
SrvSetConsoleCursorMode,
SrvGetConsoleCursorMode,
SrvRegisterConsoleOS2,
SrvSetConsoleOS2OemFormat,
SrvGetConsoleNlsMode,
SrvSetConsoleNlsMode,
SrvRegisterConsoleIME, // Not present in Win7
SrvUnregisterConsoleIME, // Not present in Win7
// SrvQueryConsoleIME, // Added only in Vista and Win2k8, not present in Win7
SrvGetConsoleLangId,
SrvAttachConsole, // Not present in Win7
SrvGetConsoleSelectionInfo,
SrvGetConsoleProcessList,
SrvGetConsoleHistory, // Added in Vista+
SrvSetConsoleHistory, // Added in Vista+
// SrvSetConsoleCurrentFont, // Added in Vista+
// SrvSetScreenBufferInfo, // Added in Vista+
// SrvConsoleClientConnect, // Added in Win7
};
BOOLEAN ConsoleServerApiServerValidTable[ConsolepMaxApiNumber - CONSRV_FIRST_API_NUMBER] =
{
FALSE, // SrvOpenConsole,
FALSE, // SrvGetConsoleInput,
FALSE, // SrvWriteConsoleInput,
FALSE, // SrvReadConsoleOutput,
FALSE, // SrvWriteConsoleOutput,
FALSE, // SrvReadConsoleOutputString,
FALSE, // SrvWriteConsoleOutputString,
FALSE, // SrvFillConsoleOutput,
FALSE, // SrvGetConsoleMode,
FALSE, // SrvGetConsoleNumberOfFonts,
FALSE, // SrvGetConsoleNumberOfInputEvents,
FALSE, // SrvGetConsoleScreenBufferInfo,
FALSE, // SrvGetConsoleCursorInfo,
FALSE, // SrvGetConsoleMouseInfo,
FALSE, // SrvGetConsoleFontInfo,
FALSE, // SrvGetConsoleFontSize,
FALSE, // SrvGetConsoleCurrentFont,
FALSE, // SrvSetConsoleMode,
FALSE, // SrvSetConsoleActiveScreenBuffer,
FALSE, // SrvFlushConsoleInputBuffer,
FALSE, // SrvGetLargestConsoleWindowSize,
FALSE, // SrvSetConsoleScreenBufferSize,
FALSE, // SrvSetConsoleCursorPosition,
FALSE, // SrvSetConsoleCursorInfo,
FALSE, // SrvSetConsoleWindowInfo,
FALSE, // SrvScrollConsoleScreenBuffer,
FALSE, // SrvSetConsoleTextAttribute,
FALSE, // SrvSetConsoleFont,
FALSE, // SrvSetConsoleIcon,
FALSE, // SrvReadConsole,
FALSE, // SrvWriteConsole,
FALSE, // SrvDuplicateHandle,
FALSE, // SrvGetHandleInformation,
FALSE, // SrvSetHandleInformation,
FALSE, // SrvCloseHandle,
FALSE, // SrvVerifyConsoleIoHandle,
FALSE, // SrvAllocConsole,
FALSE, // SrvFreeConsole,
FALSE, // SrvGetConsoleTitle,
FALSE, // SrvSetConsoleTitle,
FALSE, // SrvCreateConsoleScreenBuffer,
FALSE, // SrvInvalidateBitMapRect,
FALSE, // SrvVDMConsoleOperation,
FALSE, // SrvSetConsoleCursor,
FALSE, // SrvShowConsoleCursor,
FALSE, // SrvConsoleMenuControl,
FALSE, // SrvSetConsolePalette,
FALSE, // SrvSetConsoleDisplayMode,
FALSE, // SrvRegisterConsoleVDM,
FALSE, // SrvGetConsoleHardwareState,
FALSE, // SrvSetConsoleHardwareState,
TRUE, // SrvGetConsoleDisplayMode,
FALSE, // SrvAddConsoleAlias,
FALSE, // SrvGetConsoleAlias,
FALSE, // SrvGetConsoleAliasesLength,
FALSE, // SrvGetConsoleAliasExesLength,
FALSE, // SrvGetConsoleAliases,
FALSE, // SrvGetConsoleAliasExes,
FALSE, // SrvExpungeConsoleCommandHistory,
FALSE, // SrvSetConsoleNumberOfCommands,
FALSE, // SrvGetConsoleCommandHistoryLength,
FALSE, // SrvGetConsoleCommandHistory,
FALSE, // SrvSetConsoleCommandHistoryMode,
FALSE, // SrvGetConsoleCP,
FALSE, // SrvSetConsoleCP,
FALSE, // SrvSetConsoleKeyShortcuts,
FALSE, // SrvSetConsoleMenuClose,
FALSE, // SrvConsoleNotifyLastClose,
FALSE, // SrvGenerateConsoleCtrlEvent,
FALSE, // SrvGetConsoleKeyboardLayoutName,
FALSE, // SrvGetConsoleWindow,
FALSE, // SrvGetConsoleCharType,
FALSE, // SrvSetConsoleLocalEUDC,
FALSE, // SrvSetConsoleCursorMode,
FALSE, // SrvGetConsoleCursorMode,
FALSE, // SrvRegisterConsoleOS2,
FALSE, // SrvSetConsoleOS2OemFormat,
FALSE, // SrvGetConsoleNlsMode,
FALSE, // SrvSetConsoleNlsMode,
FALSE, // SrvRegisterConsoleIME,
FALSE, // SrvUnregisterConsoleIME,
// FALSE, // SrvQueryConsoleIME,
FALSE, // SrvGetConsoleLangId,
FALSE, // SrvAttachConsole,
FALSE, // SrvGetConsoleSelectionInfo,
FALSE, // SrvGetConsoleProcessList,
FALSE, // SrvGetConsoleHistory,
FALSE, // SrvSetConsoleHistory
// FALSE, // SrvSetConsoleCurrentFont,
// FALSE, // SrvSetScreenBufferInfo,
// FALSE, // SrvConsoleClientConnect,
};
/*
* On Windows Server 2003, CSR Servers contain
* the API Names Table only in Debug Builds.
*/
#ifdef CSR_DBG
PCHAR ConsoleServerApiNameTable[ConsolepMaxApiNumber - CONSRV_FIRST_API_NUMBER] =
{
"OpenConsole",
"GetConsoleInput",
"WriteConsoleInput",
"ReadConsoleOutput",
"WriteConsoleOutput",
"ReadConsoleOutputString",
"WriteConsoleOutputString",
"FillConsoleOutput",
"GetConsoleMode",
"GetConsoleNumberOfFonts",
"GetConsoleNumberOfInputEvents",
"GetConsoleScreenBufferInfo",
"GetConsoleCursorInfo",
"GetConsoleMouseInfo",
"GetConsoleFontInfo",
"GetConsoleFontSize",
"GetConsoleCurrentFont",
"SetConsoleMode",
"SetConsoleActiveScreenBuffer",
"FlushConsoleInputBuffer",
"GetLargestConsoleWindowSize",
"SetConsoleScreenBufferSize",
"SetConsoleCursorPosition",
"SetConsoleCursorInfo",
"SetConsoleWindowInfo",
"ScrollConsoleScreenBuffer",
"SetConsoleTextAttribute",
"SetConsoleFont",
"SetConsoleIcon",
"ReadConsole",
"WriteConsole",
"DuplicateHandle",
"GetHandleInformation",
"SetHandleInformation",
"CloseHandle",
"VerifyConsoleIoHandle",
"AllocConsole",
"FreeConsole",
"GetConsoleTitle",
"SetConsoleTitle",
"CreateConsoleScreenBuffer",
"InvalidateBitMapRect",
"VDMConsoleOperation",
"SetConsoleCursor",
"ShowConsoleCursor",
"ConsoleMenuControl",
"SetConsolePalette",
"SetConsoleDisplayMode",
"RegisterConsoleVDM",
"GetConsoleHardwareState",
"SetConsoleHardwareState",
"GetConsoleDisplayMode",
"AddConsoleAlias",
"GetConsoleAlias",
"GetConsoleAliasesLength",
"GetConsoleAliasExesLength",
"GetConsoleAliases",
"GetConsoleAliasExes",
"ExpungeConsoleCommandHistory",
"SetConsoleNumberOfCommands",
"GetConsoleCommandHistoryLength",
"GetConsoleCommandHistory",
"SetConsoleCommandHistoryMode",
"GetConsoleCP",
"SetConsoleCP",
"SetConsoleKeyShortcuts",
"SetConsoleMenuClose",
"ConsoleNotifyLastClose",
"GenerateConsoleCtrlEvent",
"GetConsoleKeyboardLayoutName",
"GetConsoleWindow",
"GetConsoleCharType",
"SetConsoleLocalEUDC",
"SetConsoleCursorMode",
"GetConsoleCursorMode",
"RegisterConsoleOS2",
"SetConsoleOS2OemFormat",
"GetConsoleNlsMode",
"SetConsoleNlsMode",
"RegisterConsoleIME",
"UnregisterConsoleIME",
// "QueryConsoleIME",
"GetConsoleLangId",
"AttachConsole",
"GetConsoleSelectionInfo",
"GetConsoleProcessList",
"GetConsoleHistory",
"SetConsoleHistory",
// "SetConsoleCurrentFont",
// "SetScreenBufferInfo",
// "ConsoleClientConnect",
};
#endif
/* FUNCTIONS ******************************************************************/
NTSTATUS
NTAPI
ConSrvNewProcess(PCSR_PROCESS SourceProcess,
PCSR_PROCESS TargetProcess)
{
/**************************************************************************
* This function is called whenever a new process (GUI or CUI) is created.
*
* Copy the parent's handles table here if both the parent and the child
* processes are CUI. If we must actually create our proper console (and
* thus do not inherit from the console handles of the parent's), then we
* will clean this table in the next ConSrvConnect call. Why we are doing
* this? It's because here, we still don't know whether or not we must create
* a new console instead of inherit it from the parent, and, because in
* ConSrvConnect we don't have any reference to the parent process anymore.
**************************************************************************/
NTSTATUS Status = STATUS_SUCCESS;
PCONSOLE_PROCESS_DATA TargetProcessData;
/* An empty target process is invalid */
if (!TargetProcess) return STATUS_INVALID_PARAMETER;
TargetProcessData = ConsoleGetPerProcessData(TargetProcess);
/* Initialize the new (target) process */
RtlZeroMemory(TargetProcessData, sizeof(*TargetProcessData));
TargetProcessData->Process = TargetProcess;
TargetProcessData->ConsoleHandle = NULL;
TargetProcessData->ConsoleApp = FALSE;
/*
* The handles table gets initialized either when inheriting from
* another console process, or when creating a new console.
*/
TargetProcessData->HandleTableSize = 0;
TargetProcessData->HandleTable = NULL;
RtlInitializeCriticalSection(&TargetProcessData->HandleTableLock);
/* Do nothing if the source process is NULL */
if (!SourceProcess) return STATUS_SUCCESS;
// SourceProcessData = ConsoleGetPerProcessData(SourceProcess);
/*
* If the child process is a console application and the parent process is
* either a console application or just has a valid console (with a valid
* handles table: this can happen if it is a GUI application having called
* AllocConsole), then try to inherit handles from the parent process.
*/
if (TargetProcess->Flags & CsrProcessIsConsoleApp /* && SourceProcessData->ConsoleHandle != NULL */)
{
PCONSOLE_PROCESS_DATA SourceProcessData = ConsoleGetPerProcessData(SourceProcess);
PCONSRV_CONSOLE SourceConsole;
/* Validate and lock the parent's console */
if (ConSrvValidateConsole(&SourceConsole,
SourceProcessData->ConsoleHandle,
CONSOLE_RUNNING, TRUE))
{
/* Inherit the parent's handles table */
Status = ConSrvInheritHandlesTable(SourceProcessData, TargetProcessData);
if (!NT_SUCCESS(Status))
{
DPRINT1("Inheriting handles table failed\n");
}
/* Unlock the parent's console */
LeaveCriticalSection(&SourceConsole->Lock);
}
}
return Status;
}
NTSTATUS
NTAPI
ConSrvConnect(IN PCSR_PROCESS CsrProcess,
IN OUT PVOID ConnectionInfo,
IN OUT PULONG ConnectionInfoLength)
{
/**************************************************************************
* This function is called whenever a CUI new process is created.
**************************************************************************/
NTSTATUS Status = STATUS_SUCCESS;
PCONSRV_API_CONNECTINFO ConnectInfo = (PCONSRV_API_CONNECTINFO)ConnectionInfo;
PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrProcess);
if ( ConnectionInfo == NULL ||
ConnectionInfoLength == NULL ||
*ConnectionInfoLength != sizeof(*ConnectInfo) )
{
DPRINT1("CONSRV: Connection failed - ConnectionInfo = 0x%p ; ConnectionInfoLength = 0x%p (%lu), expected %lu\n",
ConnectionInfo,
ConnectionInfoLength,
ConnectionInfoLength ? *ConnectionInfoLength : (ULONG)-1,
sizeof(*ConnectInfo));
return STATUS_UNSUCCESSFUL;
}
/* Set Control-Dispatcher handler */
ProcessData->CtrlRoutine = ConnectInfo->CtrlRoutine;
/* If we don't need a console, then get out of here */
DPRINT("ConnectInfo->IsConsoleApp = %s\n", ConnectInfo->IsConsoleApp ? "True" : "False");
if (!ConnectInfo->IsConsoleApp) return STATUS_SUCCESS;
/* If we don't inherit from an existing console, then create a new one... */
if (ConnectInfo->ConsoleStartInfo.ConsoleHandle == NULL)
{
CONSOLE_INIT_INFO ConsoleInitInfo;
DPRINT("ConSrvConnect - Allocate a new console\n");
/* Initialize the console initialization info structure */
ConsoleInitInfo.ConsoleStartInfo = &ConnectInfo->ConsoleStartInfo;
ConsoleInitInfo.IsWindowVisible = ConnectInfo->IsWindowVisible;
ConsoleInitInfo.TitleLength = ConnectInfo->TitleLength;
ConsoleInitInfo.ConsoleTitle = ConnectInfo->ConsoleTitle;
ConsoleInitInfo.DesktopLength = 0;
ConsoleInitInfo.Desktop = NULL;
ConsoleInitInfo.AppNameLength = ConnectInfo->AppNameLength;
ConsoleInitInfo.AppName = ConnectInfo->AppName;
ConsoleInitInfo.CurDirLength = ConnectInfo->CurDirLength;
ConsoleInitInfo.CurDir = ConnectInfo->CurDir;
/*
* Contrary to the case of SrvAllocConsole, the desktop string is
* allocated in the process' heap, so we need to retrieve it by
* using NtReadVirtualMemory.
*/
if (ConnectInfo->DesktopLength)
{
ConsoleInitInfo.DesktopLength = ConnectInfo->DesktopLength;
ConsoleInitInfo.Desktop = ConsoleAllocHeap(HEAP_ZERO_MEMORY,
ConsoleInitInfo.DesktopLength);
if (ConsoleInitInfo.Desktop == NULL)
return STATUS_NO_MEMORY;
Status = NtReadVirtualMemory(ProcessData->Process->ProcessHandle,
ConnectInfo->Desktop,
ConsoleInitInfo.Desktop,
ConsoleInitInfo.DesktopLength,
NULL);
if (!NT_SUCCESS(Status))
{
ConsoleFreeHeap(ConsoleInitInfo.Desktop);
return Status;
}
}
/*
* We are about to create a new console. However when ConSrvNewProcess
* was called, we didn't know that we wanted to create a new console and
* therefore, we by default inherited the handles table from our parent
* process. It's only now that we notice that in fact we do not need
* them, because we've created a new console and thus we must use it.
*
* ConSrvAllocateConsole will free our old handles table
* and recreate a new valid one.
*/
/* Initialize a new Console owned by the Console Leader Process */
Status = ConSrvAllocateConsole(ProcessData,
&ConnectInfo->ConsoleStartInfo.InputHandle,
&ConnectInfo->ConsoleStartInfo.OutputHandle,
&ConnectInfo->ConsoleStartInfo.ErrorHandle,
&ConsoleInitInfo);
/* Free our local desktop string if any */
if (ConsoleInitInfo.DesktopLength)
ConsoleFreeHeap(ConsoleInitInfo.Desktop);
/* Check for success */
if (!NT_SUCCESS(Status))
{
DPRINT1("Console allocation failed\n");
return Status;
}
}
else /* We inherit it from the parent */
{
DPRINT("ConSrvConnect - Reuse current (parent's) console\n");
/* Reuse our current console */
Status = ConSrvInheritConsole(ProcessData,
ConnectInfo->ConsoleStartInfo.ConsoleHandle,
FALSE,
NULL, // &ConnectInfo->ConsoleStartInfo.InputHandle,
NULL, // &ConnectInfo->ConsoleStartInfo.OutputHandle,
NULL, // &ConnectInfo->ConsoleStartInfo.ErrorHandle,
&ConnectInfo->ConsoleStartInfo);
if (!NT_SUCCESS(Status))
{
DPRINT1("Console inheritance failed\n");
return Status;
}
}
/* Set the Property-Dialog handler */
ProcessData->PropRoutine = ConnectInfo->PropRoutine;
return STATUS_SUCCESS;
}
VOID
NTAPI
ConSrvDisconnect(IN PCSR_PROCESS CsrProcess)
{
PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrProcess);
/**************************************************************************
* This function is called whenever a new process (GUI or CUI) is destroyed.
**************************************************************************/
if ( ProcessData->ConsoleHandle != NULL ||
ProcessData->HandleTable != NULL )
{
DPRINT("ConSrvDisconnect - calling ConSrvRemoveConsole\n");
ConSrvRemoveConsole(ProcessData);
}
RtlDeleteCriticalSection(&ProcessData->HandleTableLock);
}
CSR_SERVER_DLL_INIT(ConServerDllInitialization)
{
/* Initialize the memory */
ConSrvHeap = RtlGetProcessHeap();
/*
// We can use our own heap instead of the CSR heap to investigate heap corruptions :)
ConSrvHeap = RtlCreateHeap(HEAP_GROWABLE |
HEAP_PROTECTION_ENABLED |
HEAP_FREE_CHECKING_ENABLED |
HEAP_TAIL_CHECKING_ENABLED |
HEAP_VALIDATE_ALL_ENABLED,
NULL, 0, 0, NULL, NULL);
if (!ConSrvHeap) return STATUS_NO_MEMORY;
*/
ConSrvInitConsoleSupport();
/* Setup the DLL Object */
LoadedServerDll->ApiBase = CONSRV_FIRST_API_NUMBER;
LoadedServerDll->HighestApiSupported = ConsolepMaxApiNumber;
LoadedServerDll->DispatchTable = ConsoleServerApiDispatchTable;
LoadedServerDll->ValidTable = ConsoleServerApiServerValidTable;
#ifdef CSR_DBG
LoadedServerDll->NameTable = ConsoleServerApiNameTable;
#endif
LoadedServerDll->SizeOfProcessData = sizeof(CONSOLE_PROCESS_DATA);
LoadedServerDll->ConnectCallback = ConSrvConnect;
LoadedServerDll->DisconnectCallback = ConSrvDisconnect;
LoadedServerDll->NewProcessCallback = ConSrvNewProcess;
// LoadedServerDll->HardErrorCallback = ConSrvHardError;
LoadedServerDll->ShutdownProcessCallback = ConsoleClientShutdown;
ConSrvDllInstance = LoadedServerDll->ServerHandle;
/* All done */
return STATUS_SUCCESS;
}
/* EOF */