From c05df38e86217cb00cd2e904d36ccdcea3de1b31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herm=C3=A8s=20B=C3=A9lusca-Ma=C3=AFto?= Date: Mon, 13 Apr 2020 23:24:55 +0200 Subject: [PATCH] [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(). --- win32ss/user/winsrv/consrv/console.c | 420 +++++++++++++++++++++++++ win32ss/user/winsrv/consrv/handle.c | 422 +------------------------- win32ss/user/winsrv/consrv/handle.h | 8 + win32ss/user/winsrv/consrv/init.c | 5 - win32ss/user/winsrv/consrv/procinit.h | 34 ++- 5 files changed, 450 insertions(+), 439 deletions(-) diff --git a/win32ss/user/winsrv/consrv/console.c b/win32ss/user/winsrv/consrv/console.c index 12351a8b18c..1e35fdea127 100644 --- a/win32ss/user/winsrv/consrv/console.c +++ b/win32ss/user/winsrv/consrv/console.c @@ -551,6 +551,11 @@ ConSrvInitConsole(OUT PHANDLE NewConsoleHandle, *NewConsole = NULL; + DPRINT("Initialization of console '%S' for process '%S' on desktop '%S'\n", + ConsoleInitInfo->ConsoleTitle ? ConsoleInitInfo->ConsoleTitle : L"n/a", + ConsoleInitInfo->AppName ? ConsoleInitInfo->AppName : L"n/a", + ConsoleInitInfo->Desktop ? ConsoleInitInfo->Desktop : L"n/a"); + /* * Load the console settings */ @@ -879,6 +884,421 @@ ConioUnpause(PCONSRV_CONSOLE Console, UCHAR Flags) } +/* CONSOLE PROCESS INITIALIZATION FUNCTIONS ***********************************/ + +static NTSTATUS +ConSrvInitProcessHandles( + IN OUT PCONSOLE_PROCESS_DATA ProcessData, + IN PCONSRV_CONSOLE Console, + OUT PHANDLE pInputHandle, + OUT PHANDLE pOutputHandle, + OUT PHANDLE pErrorHandle) +{ + NTSTATUS Status; + HANDLE InputHandle = INVALID_HANDLE_VALUE, + OutputHandle = INVALID_HANDLE_VALUE, + ErrorHandle = INVALID_HANDLE_VALUE; + + /* + * Initialize the process handles. Use temporary variables to store + * the handles values in such a way that, if we fail, we don't + * return to the caller invalid handle values. + * + * Insert the IO handles. + */ + + RtlEnterCriticalSection(&ProcessData->HandleTableLock); + + /* Insert the Input handle */ + Status = ConSrvInsertObject(ProcessData, + &InputHandle, + &Console->InputBuffer.Header, + GENERIC_READ | GENERIC_WRITE, + TRUE, + FILE_SHARE_READ | FILE_SHARE_WRITE); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to insert the input handle\n"); + RtlLeaveCriticalSection(&ProcessData->HandleTableLock); + ConSrvFreeHandlesTable(ProcessData); + return Status; + } + + /* Insert the Output handle */ + Status = ConSrvInsertObject(ProcessData, + &OutputHandle, + &Console->ActiveBuffer->Header, + GENERIC_READ | GENERIC_WRITE, + TRUE, + FILE_SHARE_READ | FILE_SHARE_WRITE); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to insert the output handle\n"); + RtlLeaveCriticalSection(&ProcessData->HandleTableLock); + ConSrvFreeHandlesTable(ProcessData); + return Status; + } + + /* Insert the Error handle */ + Status = ConSrvInsertObject(ProcessData, + &ErrorHandle, + &Console->ActiveBuffer->Header, + GENERIC_READ | GENERIC_WRITE, + TRUE, + FILE_SHARE_READ | FILE_SHARE_WRITE); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to insert the error handle\n"); + RtlLeaveCriticalSection(&ProcessData->HandleTableLock); + ConSrvFreeHandlesTable(ProcessData); + return Status; + } + + RtlLeaveCriticalSection(&ProcessData->HandleTableLock); + + /* Return the newly created handles */ + *pInputHandle = InputHandle; + *pOutputHandle = OutputHandle; + *pErrorHandle = ErrorHandle; + + return STATUS_SUCCESS; +} + +NTSTATUS +ConSrvAllocateConsole( + IN OUT PCONSOLE_PROCESS_DATA ProcessData, + OUT PHANDLE pInputHandle, + OUT PHANDLE pOutputHandle, + OUT PHANDLE pErrorHandle, + IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo) +{ + NTSTATUS Status = STATUS_SUCCESS; + HANDLE ConsoleHandle; + PCONSRV_CONSOLE Console; + + /* + * 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 handle 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. + * + * Therefore, free the handle table so that we can recreate + * a new one later on. + */ + ConSrvFreeHandlesTable(ProcessData); + + /* Initialize a new Console owned by this process */ + Status = ConSrvInitConsole(&ConsoleHandle, + &Console, + ConsoleInitInfo, + ProcessData->Process); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Console initialization failed\n"); + return Status; + } + + /* Assign the new console handle */ + ProcessData->ConsoleHandle = ConsoleHandle; + + /* Initialize the process handles */ + Status = ConSrvInitProcessHandles(ProcessData, + Console, + pInputHandle, + pOutputHandle, + pErrorHandle); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to initialize the process handles\n"); + ConSrvDeleteConsole(Console); + ProcessData->ConsoleHandle = NULL; + return Status; + } + + /* Duplicate the Initialization Events */ + Status = NtDuplicateObject(NtCurrentProcess(), + Console->InitEvents[INIT_SUCCESS], + ProcessData->Process->ProcessHandle, + &ConsoleInitInfo->ConsoleStartInfo->InitEvents[INIT_SUCCESS], + EVENT_ALL_ACCESS, 0, 0); + if (!NT_SUCCESS(Status)) + { + DPRINT1("NtDuplicateObject(InitEvents[INIT_SUCCESS]) failed: %lu\n", Status); + ConSrvFreeHandlesTable(ProcessData); + ConSrvDeleteConsole(Console); + ProcessData->ConsoleHandle = NULL; + return Status; + } + + Status = NtDuplicateObject(NtCurrentProcess(), + Console->InitEvents[INIT_FAILURE], + ProcessData->Process->ProcessHandle, + &ConsoleInitInfo->ConsoleStartInfo->InitEvents[INIT_FAILURE], + EVENT_ALL_ACCESS, 0, 0); + if (!NT_SUCCESS(Status)) + { + DPRINT1("NtDuplicateObject(InitEvents[INIT_FAILURE]) failed: %lu\n", Status); + NtDuplicateObject(ProcessData->Process->ProcessHandle, + ConsoleInitInfo->ConsoleStartInfo->InitEvents[INIT_SUCCESS], + NULL, NULL, 0, 0, DUPLICATE_CLOSE_SOURCE); + ConSrvFreeHandlesTable(ProcessData); + ConSrvDeleteConsole(Console); + ProcessData->ConsoleHandle = NULL; + return Status; + } + + /* Duplicate the Input Event */ + Status = NtDuplicateObject(NtCurrentProcess(), + Console->InputBuffer.ActiveEvent, + ProcessData->Process->ProcessHandle, + &ConsoleInitInfo->ConsoleStartInfo->InputWaitHandle, + EVENT_ALL_ACCESS, 0, 0); + if (!NT_SUCCESS(Status)) + { + DPRINT1("NtDuplicateObject(InputWaitHandle) failed: %lu\n", Status); + NtDuplicateObject(ProcessData->Process->ProcessHandle, + ConsoleInitInfo->ConsoleStartInfo->InitEvents[INIT_FAILURE], + NULL, NULL, 0, 0, DUPLICATE_CLOSE_SOURCE); + NtDuplicateObject(ProcessData->Process->ProcessHandle, + ConsoleInitInfo->ConsoleStartInfo->InitEvents[INIT_SUCCESS], + NULL, NULL, 0, 0, DUPLICATE_CLOSE_SOURCE); + ConSrvFreeHandlesTable(ProcessData); + ConSrvDeleteConsole(Console); + ProcessData->ConsoleHandle = NULL; + return Status; + } + + /* Mark the process as having a console */ + ProcessData->ConsoleApp = TRUE; + ProcessData->Process->Flags |= CsrProcessIsConsoleApp; + + /* Return the console handle to the caller */ + ConsoleInitInfo->ConsoleStartInfo->ConsoleHandle = ProcessData->ConsoleHandle; + + /* + * Insert the process into the processes list of the console, + * and set its foreground priority. + */ + InsertHeadList(&Console->ProcessList, &ProcessData->ConsoleLink); + ConSrvSetProcessFocus(ProcessData->Process, Console->HasFocus); + + /* Add a reference count because the process is tied to the console */ + _InterlockedIncrement(&Console->ReferenceCount); + + /* Update the internal info of the terminal */ + TermRefreshInternalInfo(Console); + + return STATUS_SUCCESS; +} + +NTSTATUS +ConSrvInheritConsole( + IN OUT PCONSOLE_PROCESS_DATA ProcessData, + IN HANDLE ConsoleHandle, + IN BOOLEAN CreateNewHandleTable, + OUT PHANDLE pInputHandle, + OUT PHANDLE pOutputHandle, + OUT PHANDLE pErrorHandle, + IN OUT PCONSOLE_START_INFO ConsoleStartInfo) +{ + NTSTATUS Status = STATUS_SUCCESS; + PCONSRV_CONSOLE Console; + + /* Validate and lock the console */ + if (!ConSrvValidateConsole(&Console, + ConsoleHandle, + CONSOLE_RUNNING, TRUE)) + { + // FIXME: Find another status code + return STATUS_UNSUCCESSFUL; + } + + /* Inherit the console */ + ProcessData->ConsoleHandle = ConsoleHandle; + + if (CreateNewHandleTable) + { + /* + * 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 handle 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. + * + * Therefore, free the handle table so that we can recreate + * a new one later on. + */ + ConSrvFreeHandlesTable(ProcessData); + + /* Initialize the process handles */ + Status = ConSrvInitProcessHandles(ProcessData, + Console, + pInputHandle, + pOutputHandle, + pErrorHandle); + if (!NT_SUCCESS(Status)) + { + DPRINT1("Failed to initialize the process handles\n"); + ProcessData->ConsoleHandle = NULL; + goto Quit; + } + } + + /* Duplicate the Initialization Events */ + Status = NtDuplicateObject(NtCurrentProcess(), + Console->InitEvents[INIT_SUCCESS], + ProcessData->Process->ProcessHandle, + &ConsoleStartInfo->InitEvents[INIT_SUCCESS], + EVENT_ALL_ACCESS, 0, 0); + if (!NT_SUCCESS(Status)) + { + DPRINT1("NtDuplicateObject(InitEvents[INIT_SUCCESS]) failed: %lu\n", Status); + ConSrvFreeHandlesTable(ProcessData); + ProcessData->ConsoleHandle = NULL; + goto Quit; + } + + Status = NtDuplicateObject(NtCurrentProcess(), + Console->InitEvents[INIT_FAILURE], + ProcessData->Process->ProcessHandle, + &ConsoleStartInfo->InitEvents[INIT_FAILURE], + EVENT_ALL_ACCESS, 0, 0); + if (!NT_SUCCESS(Status)) + { + DPRINT1("NtDuplicateObject(InitEvents[INIT_FAILURE]) failed: %lu\n", Status); + NtDuplicateObject(ProcessData->Process->ProcessHandle, + ConsoleStartInfo->InitEvents[INIT_SUCCESS], + NULL, NULL, 0, 0, DUPLICATE_CLOSE_SOURCE); + ConSrvFreeHandlesTable(ProcessData); + ProcessData->ConsoleHandle = NULL; + goto Quit; + } + + /* Duplicate the Input Event */ + Status = NtDuplicateObject(NtCurrentProcess(), + Console->InputBuffer.ActiveEvent, + ProcessData->Process->ProcessHandle, + &ConsoleStartInfo->InputWaitHandle, + EVENT_ALL_ACCESS, 0, 0); + if (!NT_SUCCESS(Status)) + { + DPRINT1("NtDuplicateObject(InputWaitHandle) failed: %lu\n", Status); + NtDuplicateObject(ProcessData->Process->ProcessHandle, + ConsoleStartInfo->InitEvents[INIT_FAILURE], + NULL, NULL, 0, 0, DUPLICATE_CLOSE_SOURCE); + NtDuplicateObject(ProcessData->Process->ProcessHandle, + ConsoleStartInfo->InitEvents[INIT_SUCCESS], + NULL, NULL, 0, 0, DUPLICATE_CLOSE_SOURCE); + ConSrvFreeHandlesTable(ProcessData); // NOTE: Always free the handle table. + ProcessData->ConsoleHandle = NULL; + goto Quit; + } + + /* Mark the process as having a console */ + ProcessData->ConsoleApp = TRUE; + ProcessData->Process->Flags |= CsrProcessIsConsoleApp; + + /* Return the console handle to the caller */ + ConsoleStartInfo->ConsoleHandle = ProcessData->ConsoleHandle; + + /* + * Insert the process into the processes list of the console, + * and set its foreground priority. + */ + InsertHeadList(&Console->ProcessList, &ProcessData->ConsoleLink); + ConSrvSetProcessFocus(ProcessData->Process, Console->HasFocus); + + /* Add a reference count because the process is tied to the console */ + _InterlockedIncrement(&Console->ReferenceCount); + + /* Update the internal info of the terminal */ + TermRefreshInternalInfo(Console); + + Status = STATUS_SUCCESS; + +Quit: + /* Unlock the console and return */ + LeaveCriticalSection(&Console->Lock); + return Status; +} + +NTSTATUS +ConSrvRemoveConsole( + IN OUT PCONSOLE_PROCESS_DATA ProcessData) +{ + PCONSRV_CONSOLE Console; + PCONSOLE_PROCESS_DATA ConsoleLeaderProcess; + + DPRINT("ConSrvRemoveConsole\n"); + + /* Mark the process as not having a console anymore */ + ProcessData->ConsoleApp = FALSE; + ProcessData->Process->Flags &= ~CsrProcessIsConsoleApp; + + /* Validate and lock the console */ + if (!ConSrvValidateConsole(&Console, + ProcessData->ConsoleHandle, + CONSOLE_RUNNING, TRUE)) + { + // FIXME: Find another status code + return STATUS_UNSUCCESSFUL; + } + + DPRINT("ConSrvRemoveConsole - Locking OK\n"); + + /* Retrieve the console leader process */ + ConsoleLeaderProcess = ConSrvGetConsoleLeaderProcess(Console); + + /* Close all console handles and free the handle table */ + ConSrvFreeHandlesTable(ProcessData); + + /* Detach the process from the console */ + ProcessData->ConsoleHandle = NULL; + + /* Remove the process from the console's list of processes */ + RemoveEntryList(&ProcessData->ConsoleLink); + + /* Check whether the console should send a last close notification */ + if (Console->NotifyLastClose) + { + /* If we are removing the process which wants the last close notification... */ + if (ProcessData == Console->NotifiedLastCloseProcess) + { + /* ... just reset the flag and the pointer... */ + Console->NotifyLastClose = FALSE; + Console->NotifiedLastCloseProcess = NULL; + } + /* + * ... otherwise, if we are removing the console leader process + * (that cannot be the process wanting the notification, because + * the previous case already dealt with it)... + */ + else if (ProcessData == ConsoleLeaderProcess) + { + /* + * ... reset the flag first (so that we avoid multiple notifications) + * and then send the last close notification. + */ + Console->NotifyLastClose = FALSE; + ConSrvConsoleCtrlEvent(CTRL_LAST_CLOSE_EVENT, Console->NotifiedLastCloseProcess); + + /* Only now, reset the pointer */ + Console->NotifiedLastCloseProcess = NULL; + } + } + + /* Update the internal info of the terminal */ + TermRefreshInternalInfo(Console); + + /* Release the console */ + DPRINT("ConSrvRemoveConsole - Decrement Console->ReferenceCount = %lu\n", Console->ReferenceCount); + ConSrvReleaseConsole(Console, TRUE); + + return STATUS_SUCCESS; +} + + /* CONSOLE PROCESS MANAGEMENT FUNCTIONS ***************************************/ NTSTATUS diff --git a/win32ss/user/winsrv/consrv/handle.c b/win32ss/user/winsrv/consrv/handle.c index 007533583dc..ec1afc9f6cf 100644 --- a/win32ss/user/winsrv/consrv/handle.c +++ b/win32ss/user/winsrv/consrv/handle.c @@ -116,89 +116,6 @@ ConSrvCloseHandle(IN PCONSOLE_IO_HANDLE Handle) } - - - - -/* Forward declaration, used in ConSrvInitHandlesTable */ -static VOID ConSrvFreeHandlesTable(PCONSOLE_PROCESS_DATA ProcessData); - -static NTSTATUS -ConSrvInitHandlesTable(IN OUT PCONSOLE_PROCESS_DATA ProcessData, - IN PCONSRV_CONSOLE Console, - OUT PHANDLE pInputHandle, - OUT PHANDLE pOutputHandle, - OUT PHANDLE pErrorHandle) -{ - NTSTATUS Status; - HANDLE InputHandle = INVALID_HANDLE_VALUE, - OutputHandle = INVALID_HANDLE_VALUE, - ErrorHandle = INVALID_HANDLE_VALUE; - - /* - * Initialize the handles table. Use temporary variables to store - * the handles values in such a way that, if we fail, we don't - * return to the caller invalid handle values. - * - * Insert the IO handles. - */ - - RtlEnterCriticalSection(&ProcessData->HandleTableLock); - - /* Insert the Input handle */ - Status = ConSrvInsertObject(ProcessData, - &InputHandle, - &Console->InputBuffer.Header, - GENERIC_READ | GENERIC_WRITE, - TRUE, - FILE_SHARE_READ | FILE_SHARE_WRITE); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Failed to insert the input handle\n"); - RtlLeaveCriticalSection(&ProcessData->HandleTableLock); - ConSrvFreeHandlesTable(ProcessData); - return Status; - } - - /* Insert the Output handle */ - Status = ConSrvInsertObject(ProcessData, - &OutputHandle, - &Console->ActiveBuffer->Header, - GENERIC_READ | GENERIC_WRITE, - TRUE, - FILE_SHARE_READ | FILE_SHARE_WRITE); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Failed to insert the output handle\n"); - RtlLeaveCriticalSection(&ProcessData->HandleTableLock); - ConSrvFreeHandlesTable(ProcessData); - return Status; - } - - /* Insert the Error handle */ - Status = ConSrvInsertObject(ProcessData, - &ErrorHandle, - &Console->ActiveBuffer->Header, - GENERIC_READ | GENERIC_WRITE, - TRUE, - FILE_SHARE_READ | FILE_SHARE_WRITE); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Failed to insert the error handle\n"); - RtlLeaveCriticalSection(&ProcessData->HandleTableLock); - ConSrvFreeHandlesTable(ProcessData); - return Status; - } - - /* Return the newly created handles */ - *pInputHandle = InputHandle; - *pOutputHandle = OutputHandle; - *pErrorHandle = ErrorHandle; - - RtlLeaveCriticalSection(&ProcessData->HandleTableLock); - return STATUS_SUCCESS; -} - NTSTATUS ConSrvInheritHandlesTable(IN PCONSOLE_PROCESS_DATA SourceProcessData, IN PCONSOLE_PROCESS_DATA TargetProcessData) @@ -251,7 +168,7 @@ Quit: return Status; } -static VOID +VOID ConSrvFreeHandlesTable(IN PCONSOLE_PROCESS_DATA ProcessData) { RtlEnterCriticalSection(&ProcessData->HandleTableLock); @@ -470,343 +387,6 @@ ConSrvReleaseObject(IN PCONSOLE_IO_OBJECT Object, } - -NTSTATUS -ConSrvAllocateConsole(PCONSOLE_PROCESS_DATA ProcessData, - PHANDLE pInputHandle, - PHANDLE pOutputHandle, - PHANDLE pErrorHandle, - PCONSOLE_INIT_INFO ConsoleInitInfo) -{ - NTSTATUS Status = STATUS_SUCCESS; - HANDLE ConsoleHandle; - PCONSRV_CONSOLE Console; - - /* - * 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. - * - * Therefore, free the handles table so that we can recreate - * a new one later on. - */ - ConSrvFreeHandlesTable(ProcessData); - - /* Initialize a new Console owned by this process */ - DPRINT("Initialization of console '%S' for process '%S' on desktop '%S'\n", - ConsoleInitInfo->ConsoleTitle ? ConsoleInitInfo->ConsoleTitle : L"n/a", - ConsoleInitInfo->AppName ? ConsoleInitInfo->AppName : L"n/a", - ConsoleInitInfo->Desktop ? ConsoleInitInfo->Desktop : L"n/a"); - Status = ConSrvInitConsole(&ConsoleHandle, - &Console, - ConsoleInitInfo, - ProcessData->Process); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Console initialization failed\n"); - return Status; - } - - /* Assign the new console handle */ - ProcessData->ConsoleHandle = ConsoleHandle; - - /* Initialize the handles table */ - Status = ConSrvInitHandlesTable(ProcessData, - Console, - pInputHandle, - pOutputHandle, - pErrorHandle); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Failed to initialize the handles table\n"); - ConSrvDeleteConsole(Console); - ProcessData->ConsoleHandle = NULL; - return Status; - } - - /* Duplicate the Initialization Events */ - Status = NtDuplicateObject(NtCurrentProcess(), - Console->InitEvents[INIT_SUCCESS], - ProcessData->Process->ProcessHandle, - &ConsoleInitInfo->ConsoleStartInfo->InitEvents[INIT_SUCCESS], - EVENT_ALL_ACCESS, 0, 0); - if (!NT_SUCCESS(Status)) - { - DPRINT1("NtDuplicateObject(InitEvents[INIT_SUCCESS]) failed: %lu\n", Status); - ConSrvFreeHandlesTable(ProcessData); - ConSrvDeleteConsole(Console); - ProcessData->ConsoleHandle = NULL; - return Status; - } - - Status = NtDuplicateObject(NtCurrentProcess(), - Console->InitEvents[INIT_FAILURE], - ProcessData->Process->ProcessHandle, - &ConsoleInitInfo->ConsoleStartInfo->InitEvents[INIT_FAILURE], - EVENT_ALL_ACCESS, 0, 0); - if (!NT_SUCCESS(Status)) - { - DPRINT1("NtDuplicateObject(InitEvents[INIT_FAILURE]) failed: %lu\n", Status); - NtDuplicateObject(ProcessData->Process->ProcessHandle, - ConsoleInitInfo->ConsoleStartInfo->InitEvents[INIT_SUCCESS], - NULL, NULL, 0, 0, DUPLICATE_CLOSE_SOURCE); - ConSrvFreeHandlesTable(ProcessData); - ConSrvDeleteConsole(Console); - ProcessData->ConsoleHandle = NULL; - return Status; - } - - /* Duplicate the Input Event */ - Status = NtDuplicateObject(NtCurrentProcess(), - Console->InputBuffer.ActiveEvent, - ProcessData->Process->ProcessHandle, - &ConsoleInitInfo->ConsoleStartInfo->InputWaitHandle, - EVENT_ALL_ACCESS, 0, 0); - if (!NT_SUCCESS(Status)) - { - DPRINT1("NtDuplicateObject(InputWaitHandle) failed: %lu\n", Status); - NtDuplicateObject(ProcessData->Process->ProcessHandle, - ConsoleInitInfo->ConsoleStartInfo->InitEvents[INIT_FAILURE], - NULL, NULL, 0, 0, DUPLICATE_CLOSE_SOURCE); - NtDuplicateObject(ProcessData->Process->ProcessHandle, - ConsoleInitInfo->ConsoleStartInfo->InitEvents[INIT_SUCCESS], - NULL, NULL, 0, 0, DUPLICATE_CLOSE_SOURCE); - ConSrvFreeHandlesTable(ProcessData); - ConSrvDeleteConsole(Console); - ProcessData->ConsoleHandle = NULL; - return Status; - } - - /* Mark the process as having a console */ - ProcessData->ConsoleApp = TRUE; - ProcessData->Process->Flags |= CsrProcessIsConsoleApp; - - /* Return the console handle to the caller */ - ConsoleInitInfo->ConsoleStartInfo->ConsoleHandle = ProcessData->ConsoleHandle; - - /* - * Insert the process into the processes list of the console, - * and set its foreground priority. - */ - InsertHeadList(&Console->ProcessList, &ProcessData->ConsoleLink); - ConSrvSetProcessFocus(ProcessData->Process, Console->HasFocus); - - /* Add a reference count because the process is tied to the console */ - _InterlockedIncrement(&Console->ReferenceCount); - - /* Update the internal info of the terminal */ - TermRefreshInternalInfo(Console); - - return STATUS_SUCCESS; -} - -NTSTATUS -ConSrvInheritConsole(PCONSOLE_PROCESS_DATA ProcessData, - HANDLE ConsoleHandle, - BOOLEAN CreateNewHandlesTable, - PHANDLE pInputHandle, - PHANDLE pOutputHandle, - PHANDLE pErrorHandle, - PCONSOLE_START_INFO ConsoleStartInfo) -{ - NTSTATUS Status = STATUS_SUCCESS; - PCONSRV_CONSOLE Console; - - /* Validate and lock the console */ - if (!ConSrvValidateConsole(&Console, - ConsoleHandle, - CONSOLE_RUNNING, TRUE)) - { - // FIXME: Find another status code - return STATUS_UNSUCCESSFUL; - } - - /* Inherit the console */ - ProcessData->ConsoleHandle = ConsoleHandle; - - if (CreateNewHandlesTable) - { - /* - * 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. - * - * Therefore, free the handles table so that we can recreate - * a new one later on. - */ - ConSrvFreeHandlesTable(ProcessData); - - /* Initialize the handles table */ - Status = ConSrvInitHandlesTable(ProcessData, - Console, - pInputHandle, - pOutputHandle, - pErrorHandle); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Failed to initialize the handles table\n"); - ProcessData->ConsoleHandle = NULL; - goto Quit; - } - } - - /* Duplicate the Initialization Events */ - Status = NtDuplicateObject(NtCurrentProcess(), - Console->InitEvents[INIT_SUCCESS], - ProcessData->Process->ProcessHandle, - &ConsoleStartInfo->InitEvents[INIT_SUCCESS], - EVENT_ALL_ACCESS, 0, 0); - if (!NT_SUCCESS(Status)) - { - DPRINT1("NtDuplicateObject(InitEvents[INIT_SUCCESS]) failed: %lu\n", Status); - ConSrvFreeHandlesTable(ProcessData); - ProcessData->ConsoleHandle = NULL; - goto Quit; - } - - Status = NtDuplicateObject(NtCurrentProcess(), - Console->InitEvents[INIT_FAILURE], - ProcessData->Process->ProcessHandle, - &ConsoleStartInfo->InitEvents[INIT_FAILURE], - EVENT_ALL_ACCESS, 0, 0); - if (!NT_SUCCESS(Status)) - { - DPRINT1("NtDuplicateObject(InitEvents[INIT_FAILURE]) failed: %lu\n", Status); - NtDuplicateObject(ProcessData->Process->ProcessHandle, - ConsoleStartInfo->InitEvents[INIT_SUCCESS], - NULL, NULL, 0, 0, DUPLICATE_CLOSE_SOURCE); - ConSrvFreeHandlesTable(ProcessData); - ProcessData->ConsoleHandle = NULL; - goto Quit; - } - - /* Duplicate the Input Event */ - Status = NtDuplicateObject(NtCurrentProcess(), - Console->InputBuffer.ActiveEvent, - ProcessData->Process->ProcessHandle, - &ConsoleStartInfo->InputWaitHandle, - EVENT_ALL_ACCESS, 0, 0); - if (!NT_SUCCESS(Status)) - { - DPRINT1("NtDuplicateObject(InputWaitHandle) failed: %lu\n", Status); - NtDuplicateObject(ProcessData->Process->ProcessHandle, - ConsoleStartInfo->InitEvents[INIT_FAILURE], - NULL, NULL, 0, 0, DUPLICATE_CLOSE_SOURCE); - NtDuplicateObject(ProcessData->Process->ProcessHandle, - ConsoleStartInfo->InitEvents[INIT_SUCCESS], - NULL, NULL, 0, 0, DUPLICATE_CLOSE_SOURCE); - ConSrvFreeHandlesTable(ProcessData); // NOTE: Always free the handles table. - ProcessData->ConsoleHandle = NULL; - goto Quit; - } - - /* Mark the process as having a console */ - ProcessData->ConsoleApp = TRUE; - ProcessData->Process->Flags |= CsrProcessIsConsoleApp; - - /* Return the console handle to the caller */ - ConsoleStartInfo->ConsoleHandle = ProcessData->ConsoleHandle; - - /* - * Insert the process into the processes list of the console, - * and set its foreground priority. - */ - InsertHeadList(&Console->ProcessList, &ProcessData->ConsoleLink); - ConSrvSetProcessFocus(ProcessData->Process, Console->HasFocus); - - /* Add a reference count because the process is tied to the console */ - _InterlockedIncrement(&Console->ReferenceCount); - - /* Update the internal info of the terminal */ - TermRefreshInternalInfo(Console); - - Status = STATUS_SUCCESS; - -Quit: - /* Unlock the console and return */ - LeaveCriticalSection(&Console->Lock); - return Status; -} - -NTSTATUS -ConSrvRemoveConsole(PCONSOLE_PROCESS_DATA ProcessData) -{ - PCONSRV_CONSOLE Console; - PCONSOLE_PROCESS_DATA ConsoleLeaderProcess; - - DPRINT("ConSrvRemoveConsole\n"); - - /* Mark the process as not having a console anymore */ - ProcessData->ConsoleApp = FALSE; - ProcessData->Process->Flags &= ~CsrProcessIsConsoleApp; - - /* Validate and lock the console */ - if (!ConSrvValidateConsole(&Console, - ProcessData->ConsoleHandle, - CONSOLE_RUNNING, TRUE)) - { - // FIXME: Find another status code - return STATUS_UNSUCCESSFUL; - } - - DPRINT("ConSrvRemoveConsole - Locking OK\n"); - - /* Retrieve the console leader process */ - ConsoleLeaderProcess = ConSrvGetConsoleLeaderProcess(Console); - - /* Close all console handles and free the handles table */ - ConSrvFreeHandlesTable(ProcessData); - - /* Detach the process from the console */ - ProcessData->ConsoleHandle = NULL; - - /* Remove the process from the console's list of processes */ - RemoveEntryList(&ProcessData->ConsoleLink); - - /* Check whether the console should send a last close notification */ - if (Console->NotifyLastClose) - { - /* If we are removing the process which wants the last close notification... */ - if (ProcessData == Console->NotifiedLastCloseProcess) - { - /* ... just reset the flag and the pointer... */ - Console->NotifyLastClose = FALSE; - Console->NotifiedLastCloseProcess = NULL; - } - /* - * ... otherwise, if we are removing the console leader process - * (that cannot be the process wanting the notification, because - * the previous case already dealt with it)... - */ - else if (ProcessData == ConsoleLeaderProcess) - { - /* - * ... reset the flag first (so that we avoid multiple notifications) - * and then send the last close notification. - */ - Console->NotifyLastClose = FALSE; - ConSrvConsoleCtrlEvent(CTRL_LAST_CLOSE_EVENT, Console->NotifiedLastCloseProcess); - - /* Only now, reset the pointer */ - Console->NotifiedLastCloseProcess = NULL; - } - } - - /* Update the internal info of the terminal */ - TermRefreshInternalInfo(Console); - - /* Release the console */ - DPRINT("ConSrvRemoveConsole - Decrement Console->ReferenceCount = %lu\n", Console->ReferenceCount); - ConSrvReleaseConsole(Console, TRUE); - - return STATUS_SUCCESS; -} - - /* PUBLIC SERVER APIS *********************************************************/ /* API_NUMBER: ConsolepOpenConsole */ diff --git a/win32ss/user/winsrv/consrv/handle.h b/win32ss/user/winsrv/consrv/handle.h index d154c5cc17c..525893e2735 100644 --- a/win32ss/user/winsrv/consrv/handle.h +++ b/win32ss/user/winsrv/consrv/handle.h @@ -10,6 +10,14 @@ #pragma once +NTSTATUS +ConSrvInheritHandlesTable(IN PCONSOLE_PROCESS_DATA SourceProcessData, + IN PCONSOLE_PROCESS_DATA TargetProcessData); + +VOID +ConSrvFreeHandlesTable(IN PCONSOLE_PROCESS_DATA ProcessData); + + VOID ConSrvInitObject(IN OUT PCONSOLE_IO_OBJECT Object, IN CONSOLE_IO_OBJECT_TYPE Type, diff --git a/win32ss/user/winsrv/consrv/init.c b/win32ss/user/winsrv/consrv/init.c index 448c1836965..4332ae531a4 100644 --- a/win32ss/user/winsrv/consrv/init.c +++ b/win32ss/user/winsrv/consrv/init.c @@ -320,11 +320,6 @@ PCHAR ConsoleServerApiNameTable[ConsolepMaxApiNumber - CONSRV_FIRST_API_NUMBER] /* FUNCTIONS ******************************************************************/ -/* See handle.c */ -NTSTATUS -ConSrvInheritHandlesTable(IN PCONSOLE_PROCESS_DATA SourceProcessData, - IN PCONSOLE_PROCESS_DATA TargetProcessData); - NTSTATUS NTAPI ConSrvNewProcess(PCSR_PROCESS SourceProcess, diff --git a/win32ss/user/winsrv/consrv/procinit.h b/win32ss/user/winsrv/consrv/procinit.h index 716ecd0a815..6eac76df2b0 100644 --- a/win32ss/user/winsrv/consrv/procinit.h +++ b/win32ss/user/winsrv/consrv/procinit.h @@ -8,16 +8,24 @@ #pragma once -NTSTATUS ConSrvAllocateConsole(PCONSOLE_PROCESS_DATA ProcessData, - PHANDLE pInputHandle, - PHANDLE pOutputHandle, - PHANDLE pErrorHandle, - PCONSOLE_INIT_INFO ConsoleInitInfo); -NTSTATUS ConSrvInheritConsole(PCONSOLE_PROCESS_DATA ProcessData, - HANDLE ConsoleHandle, - BOOLEAN CreateNewHandlesTable, - PHANDLE pInputHandle, - PHANDLE pOutputHandle, - PHANDLE pErrorHandle, - PCONSOLE_START_INFO ConsoleStartInfo); -NTSTATUS ConSrvRemoveConsole(PCONSOLE_PROCESS_DATA ProcessData); +NTSTATUS +ConSrvAllocateConsole( + IN OUT PCONSOLE_PROCESS_DATA ProcessData, + OUT PHANDLE pInputHandle, + OUT PHANDLE pOutputHandle, + OUT PHANDLE pErrorHandle, + IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo); + +NTSTATUS +ConSrvInheritConsole( + IN OUT PCONSOLE_PROCESS_DATA ProcessData, + IN HANDLE ConsoleHandle, + IN BOOLEAN CreateNewHandleTable, + OUT PHANDLE pInputHandle, + OUT PHANDLE pOutputHandle, + OUT PHANDLE pErrorHandle, + IN OUT PCONSOLE_START_INFO ConsoleStartInfo); + +NTSTATUS +ConSrvRemoveConsole( + IN OUT PCONSOLE_PROCESS_DATA ProcessData);