/* * LICENSE: GPL - See COPYING in the top level directory * PROJECT: ReactOS Console Server DLL * FILE: win32ss/user/winsrv/consrv_new/handle.c * PURPOSE: Console I/O Handles functions * PROGRAMMERS: David Welch * Jeffrey Morlan * Hermes Belusca-Maito (hermes.belusca@sfr.fr) */ /* INCLUDES *******************************************************************/ #include "consrv.h" #include "include/conio.h" #include "include/conio2.h" #include "handle.h" #include "include/console.h" #include "console.h" #include "conoutput.h" #define NDEBUG #include /* GLOBALS ********************************************************************/ typedef struct _CONSOLE_IO_HANDLE { PCONSOLE_IO_OBJECT Object; /* The object on which the handle points to */ DWORD Access; BOOL Inheritable; DWORD ShareMode; } CONSOLE_IO_HANDLE, *PCONSOLE_IO_HANDLE; /* PRIVATE FUNCTIONS **********************************************************/ static INT AdjustHandleCounts(PCONSOLE_IO_HANDLE Entry, INT Change) { PCONSOLE_IO_OBJECT Object = Entry->Object; DPRINT("AdjustHandleCounts(0x%p, %d), Object = 0x%p\n", Entry, Change, Object); DPRINT("\tAdjustHandleCounts(0x%p, %d), Object = 0x%p, Object->HandleCount = %d, Object->Type = %lu\n", Entry, Change, Object, Object->HandleCount, Object->Type); if (Entry->Access & GENERIC_READ) Object->AccessRead += Change; if (Entry->Access & GENERIC_WRITE) Object->AccessWrite += Change; if (!(Entry->ShareMode & FILE_SHARE_READ)) Object->ExclusiveRead += Change; if (!(Entry->ShareMode & FILE_SHARE_WRITE)) Object->ExclusiveWrite += Change; Object->HandleCount += Change; return Object->HandleCount; } static VOID ConSrvCreateHandleEntry(PCONSOLE_IO_HANDLE Entry) { /// LOCK /// PCONSOLE_IO_OBJECT Object = Entry->Object; /// LOCK /// EnterCriticalSection(&Object->Console->Lock); AdjustHandleCounts(Entry, +1); /// LOCK /// LeaveCriticalSection(&Object->Console->Lock); } static VOID ConSrvCloseHandleEntry(PCONSOLE_IO_HANDLE Entry) { PCONSOLE_IO_OBJECT Object = Entry->Object; if (Object != NULL) { /// LOCK /// PCONSOLE Console = Object->Console; /// LOCK /// EnterCriticalSection(&Console->Lock); /* * If this is a input handle, notify and dereference * all the waits related to this handle. */ if (Object->Type == INPUT_BUFFER) { PCONSOLE_INPUT_BUFFER InputBuffer = (PCONSOLE_INPUT_BUFFER)Object; /* * Wake up all the writing waiters related to this handle for this * input buffer, if any, then dereference them and purge them all * from the list. * To select them amongst all the waiters for this input buffer, * pass the handle pointer to the waiters, then they will check * whether or not they are related to this handle and if so, they * return. */ CsrNotifyWait(&InputBuffer->ReadWaitQueue, WaitAll, NULL, (PVOID)Entry); if (!IsListEmpty(&InputBuffer->ReadWaitQueue)) { CsrDereferenceWait(&InputBuffer->ReadWaitQueue); } } /* If the last handle to a screen buffer is closed, delete it... */ if (AdjustHandleCounts(Entry, -1) == 0) { if (Object->Type == TEXTMODE_BUFFER || Object->Type == GRAPHICS_BUFFER) { PCONSOLE_SCREEN_BUFFER Buffer = (PCONSOLE_SCREEN_BUFFER)Object; /* ...unless it's the only buffer left. Windows allows deletion * even of the last buffer, but having to deal with a lack of * any active buffer might be error-prone. */ if (Buffer->ListEntry.Flink != Buffer->ListEntry.Blink) ConioDeleteScreenBuffer(Buffer); } else if (Object->Type == INPUT_BUFFER) { DPRINT("Closing the input buffer\n"); } else { DPRINT1("Invalid object type %d\n", Object->Type); } } /// LOCK /// LeaveCriticalSection(&Console->Lock); /* Invalidate (zero-out) this handle entry */ // Entry->Object = NULL; // RtlZeroMemory(Entry, sizeof(*Entry)); } RtlZeroMemory(Entry, sizeof(*Entry)); // Be sure the whole entry is invalidated. } /* Forward declaration, used in ConSrvInitHandlesTable */ static VOID ConSrvFreeHandlesTable(PCONSOLE_PROCESS_DATA ProcessData); static NTSTATUS ConSrvInitHandlesTable(IN OUT PCONSOLE_PROCESS_DATA ProcessData, IN PCONSOLE 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) { NTSTATUS Status = STATUS_SUCCESS; ULONG i, j; RtlEnterCriticalSection(&SourceProcessData->HandleTableLock); /* Inherit a handles table only if there is no already */ if (TargetProcessData->HandleTable != NULL /* || TargetProcessData->HandleTableSize != 0 */) { Status = STATUS_UNSUCCESSFUL; goto Quit; } /* Allocate a new handle table for the child process */ TargetProcessData->HandleTable = ConsoleAllocHeap(HEAP_ZERO_MEMORY, SourceProcessData->HandleTableSize * sizeof(CONSOLE_IO_HANDLE)); if (TargetProcessData->HandleTable == NULL) { Status = STATUS_NO_MEMORY; goto Quit; } TargetProcessData->HandleTableSize = SourceProcessData->HandleTableSize; /* * Parse the parent process' handles table and, for each handle, * do a copy of it and reference it, if the handle is inheritable. */ for (i = 0, j = 0; i < SourceProcessData->HandleTableSize; i++) { if (SourceProcessData->HandleTable[i].Object != NULL && SourceProcessData->HandleTable[i].Inheritable) { /* * Copy the handle data and increment the reference count of the * pointed object (via the call to ConSrvCreateHandleEntry). */ TargetProcessData->HandleTable[j] = SourceProcessData->HandleTable[i]; ConSrvCreateHandleEntry(&TargetProcessData->HandleTable[j]); ++j; } } Quit: RtlLeaveCriticalSection(&SourceProcessData->HandleTableLock); return Status; } static VOID ConSrvFreeHandlesTable(PCONSOLE_PROCESS_DATA ProcessData) { RtlEnterCriticalSection(&ProcessData->HandleTableLock); if (ProcessData->HandleTable != NULL) { ULONG i; /* * ProcessData->ConsoleHandle is NULL (and the assertion fails) when * ConSrvFreeHandlesTable is called in ConSrvConnect during the * allocation of a new console. */ // ASSERT(ProcessData->ConsoleHandle); if (ProcessData->ConsoleHandle != NULL) { /* Close all the console handles */ for (i = 0; i < ProcessData->HandleTableSize; i++) { ConSrvCloseHandleEntry(&ProcessData->HandleTable[i]); } } /* Free the handles table memory */ ConsoleFreeHeap(ProcessData->HandleTable); ProcessData->HandleTable = NULL; } ProcessData->HandleTableSize = 0; RtlLeaveCriticalSection(&ProcessData->HandleTableLock); } VOID FASTCALL ConSrvInitObject(IN OUT PCONSOLE_IO_OBJECT Object, IN CONSOLE_IO_OBJECT_TYPE Type, IN PCONSOLE Console) { ASSERT(Object); // if (!Object) return; Object->Type = Type; Object->Console = Console; Object->AccessRead = Object->AccessWrite = 0; Object->ExclusiveRead = Object->ExclusiveWrite = 0; Object->HandleCount = 0; } NTSTATUS FASTCALL ConSrvInsertObject(PCONSOLE_PROCESS_DATA ProcessData, PHANDLE Handle, PCONSOLE_IO_OBJECT Object, DWORD Access, BOOL Inheritable, DWORD ShareMode) { #define IO_HANDLES_INCREMENT 2 * 3 ULONG i = 0; PCONSOLE_IO_HANDLE Block; // NOTE: Commented out because calling code always lock HandleTableLock before. // RtlEnterCriticalSection(&ProcessData->HandleTableLock); ASSERT( (ProcessData->HandleTable == NULL && ProcessData->HandleTableSize == 0) || (ProcessData->HandleTable != NULL && ProcessData->HandleTableSize != 0) ); if (ProcessData->HandleTable) { for (i = 0; i < ProcessData->HandleTableSize; i++) { if (ProcessData->HandleTable[i].Object == NULL) break; } } if (i >= ProcessData->HandleTableSize) { /* Allocate a new handles table */ Block = ConsoleAllocHeap(HEAP_ZERO_MEMORY, (ProcessData->HandleTableSize + IO_HANDLES_INCREMENT) * sizeof(CONSOLE_IO_HANDLE)); if (Block == NULL) { // RtlLeaveCriticalSection(&ProcessData->HandleTableLock); return STATUS_UNSUCCESSFUL; } /* If we previously had a handles table, free it and use the new one */ if (ProcessData->HandleTable) { /* Copy the handles from the old table to the new one */ RtlCopyMemory(Block, ProcessData->HandleTable, ProcessData->HandleTableSize * sizeof(CONSOLE_IO_HANDLE)); ConsoleFreeHeap(ProcessData->HandleTable); } ProcessData->HandleTable = Block; ProcessData->HandleTableSize += IO_HANDLES_INCREMENT; } ProcessData->HandleTable[i].Object = Object; ProcessData->HandleTable[i].Access = Access; ProcessData->HandleTable[i].Inheritable = Inheritable; ProcessData->HandleTable[i].ShareMode = ShareMode; ConSrvCreateHandleEntry(&ProcessData->HandleTable[i]); *Handle = ULongToHandle((i << 2) | 0x3); // RtlLeaveCriticalSection(&ProcessData->HandleTableLock); return STATUS_SUCCESS; } NTSTATUS FASTCALL ConSrvRemoveObject(PCONSOLE_PROCESS_DATA ProcessData, HANDLE Handle) { ULONG Index = HandleToULong(Handle) >> 2; PCONSOLE_IO_OBJECT Object; RtlEnterCriticalSection(&ProcessData->HandleTableLock); ASSERT(ProcessData->HandleTable); if (Index >= ProcessData->HandleTableSize || (Object = ProcessData->HandleTable[Index].Object) == NULL) { RtlLeaveCriticalSection(&ProcessData->HandleTableLock); return STATUS_INVALID_HANDLE; } ASSERT(ProcessData->ConsoleHandle); ConSrvCloseHandleEntry(&ProcessData->HandleTable[Index]); RtlLeaveCriticalSection(&ProcessData->HandleTableLock); return STATUS_SUCCESS; } NTSTATUS FASTCALL ConSrvGetObject(PCONSOLE_PROCESS_DATA ProcessData, HANDLE Handle, PCONSOLE_IO_OBJECT* Object, PVOID* Entry OPTIONAL, DWORD Access, BOOL LockConsole, CONSOLE_IO_OBJECT_TYPE Type) { // NTSTATUS Status; ULONG Index = HandleToULong(Handle) >> 2; PCONSOLE_IO_HANDLE HandleEntry = NULL; PCONSOLE_IO_OBJECT ObjectEntry = NULL; // PCONSOLE ObjectConsole; ASSERT(Object); if (Entry) *Entry = NULL; DPRINT("ConSrvGetObject -- Object: 0x%x, Handle: 0x%x\n", Object, Handle); RtlEnterCriticalSection(&ProcessData->HandleTableLock); if ( IsConsoleHandle(Handle) && Index < ProcessData->HandleTableSize ) { HandleEntry = &ProcessData->HandleTable[Index]; ObjectEntry = HandleEntry->Object; } if ( HandleEntry == NULL || ObjectEntry == NULL || (HandleEntry->Access & Access) == 0 || /*(Type != 0 && ObjectEntry->Type != Type)*/ (Type != 0 && (ObjectEntry->Type & Type) == 0) ) { DPRINT("ConSrvGetObject -- Invalid handle 0x%x of type %lu with access %lu ; retrieved object 0x%x (handle 0x%x) of type %lu with access %lu\n", Handle, Type, Access, ObjectEntry, HandleEntry, (ObjectEntry ? ObjectEntry->Type : 0), (HandleEntry ? HandleEntry->Access : 0)); RtlLeaveCriticalSection(&ProcessData->HandleTableLock); return STATUS_INVALID_HANDLE; } RtlLeaveCriticalSection(&ProcessData->HandleTableLock); // Status = ConDrvGetConsole(&ObjectConsole, ProcessData->ConsoleHandle, LockConsole); // if (NT_SUCCESS(Status)) if (ConDrvValidateConsoleUnsafe(ObjectEntry->Console, CONSOLE_RUNNING, LockConsole)) { _InterlockedIncrement(&ObjectEntry->Console->ReferenceCount); /* Return the objects to the caller */ *Object = ObjectEntry; if (Entry) *Entry = HandleEntry; // RtlLeaveCriticalSection(&ProcessData->HandleTableLock); return STATUS_SUCCESS; } else { // RtlLeaveCriticalSection(&ProcessData->HandleTableLock); return STATUS_INVALID_HANDLE; } } VOID FASTCALL ConSrvReleaseObject(PCONSOLE_IO_OBJECT Object, BOOL IsConsoleLocked) { ConSrvReleaseConsole(Object->Console, IsConsoleLocked); } NTSTATUS FASTCALL ConSrvAllocateConsole(PCONSOLE_PROCESS_DATA ProcessData, PHANDLE pInputHandle, PHANDLE pOutputHandle, PHANDLE pErrorHandle, PCONSOLE_START_INFO ConsoleStartInfo) { NTSTATUS Status = STATUS_SUCCESS; HANDLE ConsoleHandle; PCONSOLE 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 */ Status = ConSrvInitConsole(&ConsoleHandle, &Console, ConsoleStartInfo, HandleToUlong(ProcessData->Process->ClientId.UniqueProcess)); 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 Input Event */ Status = NtDuplicateObject(NtCurrentProcess(), Console->InputBuffer.ActiveEvent, ProcessData->Process->ProcessHandle, &ProcessData->ConsoleEvent, EVENT_ALL_ACCESS, 0, 0); if (!NT_SUCCESS(Status)) { DPRINT1("NtDuplicateObject() failed: %lu\n", Status); ConSrvFreeHandlesTable(ProcessData); ConSrvDeleteConsole(Console); ProcessData->ConsoleHandle = NULL; return Status; } /* Insert the process into the processes list of the console */ InsertHeadList(&Console->ProcessList, &ProcessData->ConsoleLink); /* Add a reference count because the process is tied to the console */ _InterlockedIncrement(&Console->ReferenceCount); /* Update the internal info of the terminal */ ConioRefreshInternalInfo(Console); return STATUS_SUCCESS; } NTSTATUS FASTCALL ConSrvInheritConsole(PCONSOLE_PROCESS_DATA ProcessData, HANDLE ConsoleHandle, BOOL CreateNewHandlesTable, PHANDLE pInputHandle, PHANDLE pOutputHandle, PHANDLE pErrorHandle) { NTSTATUS Status = STATUS_SUCCESS; PCONSOLE Console; /* Validate and lock the console */ if (!ConDrvValidateConsole(&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 Input Event */ Status = NtDuplicateObject(NtCurrentProcess(), Console->InputBuffer.ActiveEvent, ProcessData->Process->ProcessHandle, &ProcessData->ConsoleEvent, EVENT_ALL_ACCESS, 0, 0); if (!NT_SUCCESS(Status)) { DPRINT1("NtDuplicateObject() failed: %lu\n", Status); ConSrvFreeHandlesTable(ProcessData); // NOTE: Always free the handles table. ProcessData->ConsoleHandle = NULL; goto Quit; } /* Insert the process into the processes list of the console */ InsertHeadList(&Console->ProcessList, &ProcessData->ConsoleLink); /* Add a reference count because the process is tied to the console */ _InterlockedIncrement(&Console->ReferenceCount); /* Update the internal info of the terminal */ ConioRefreshInternalInfo(Console); Status = STATUS_SUCCESS; Quit: /* Unlock the console and return */ LeaveCriticalSection(&Console->Lock); return Status; } VOID FASTCALL ConSrvRemoveConsole(PCONSOLE_PROCESS_DATA ProcessData) { PCONSOLE Console; DPRINT("ConSrvRemoveConsole\n"); // RtlEnterCriticalSection(&ProcessData->HandleTableLock); /* Validate and lock the console */ if (ConDrvValidateConsole(&Console, ProcessData->ConsoleHandle, CONSOLE_RUNNING, TRUE)) { DPRINT("ConSrvRemoveConsole - Locking OK\n"); /* Close all console handles and free the handles table */ ConSrvFreeHandlesTable(ProcessData); /* Detach the process from the console */ ProcessData->ConsoleHandle = NULL; /* Remove ourselves from the console's list of processes */ RemoveEntryList(&ProcessData->ConsoleLink); /* Update the internal info of the terminal */ ConioRefreshInternalInfo(Console); /* Release the console */ DPRINT("ConSrvRemoveConsole - Decrement Console->ReferenceCount = %lu\n", Console->ReferenceCount); ConDrvReleaseConsole(Console, TRUE); //CloseHandle(ProcessData->ConsoleEvent); //ProcessData->ConsoleEvent = NULL; } // RtlLeaveCriticalSection(&ProcessData->HandleTableLock); } /* PUBLIC SERVER APIS *********************************************************/ CSR_API(SrvOpenConsole) { /* * This API opens a handle to either the input buffer or to * a screen-buffer of the console of the current process. */ NTSTATUS Status; PCONSOLE_OPENCONSOLE OpenConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.OpenConsoleRequest; PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process); PCONSOLE Console; DWORD DesiredAccess = OpenConsoleRequest->Access; DWORD ShareMode = OpenConsoleRequest->ShareMode; PCONSOLE_IO_OBJECT Object; OpenConsoleRequest->ConsoleHandle = INVALID_HANDLE_VALUE; Status = ConSrvGetConsole(ProcessData, &Console, TRUE); if (!NT_SUCCESS(Status)) { DPRINT1("Can't get console, status %lx\n", Status); return Status; } RtlEnterCriticalSection(&ProcessData->HandleTableLock); /* * Open a handle to either the active screen buffer or the input buffer. */ if (OpenConsoleRequest->HandleType == HANDLE_OUTPUT) { Object = &Console->ActiveBuffer->Header; } else // HANDLE_INPUT { Object = &Console->InputBuffer.Header; } if (((DesiredAccess & GENERIC_READ) && Object->ExclusiveRead != 0) || ((DesiredAccess & GENERIC_WRITE) && Object->ExclusiveWrite != 0) || (!(ShareMode & FILE_SHARE_READ) && Object->AccessRead != 0) || (!(ShareMode & FILE_SHARE_WRITE) && Object->AccessWrite != 0)) { DPRINT1("Sharing violation\n"); Status = STATUS_SHARING_VIOLATION; } else { Status = ConSrvInsertObject(ProcessData, &OpenConsoleRequest->ConsoleHandle, Object, DesiredAccess, OpenConsoleRequest->Inheritable, ShareMode); } RtlLeaveCriticalSection(&ProcessData->HandleTableLock); ConSrvReleaseConsole(Console, TRUE); return Status; } CSR_API(SrvCloseHandle) { NTSTATUS Status; PCONSOLE_CLOSEHANDLE CloseHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.CloseHandleRequest; PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process); PCONSOLE Console; Status = ConSrvGetConsole(ProcessData, &Console, TRUE); if (!NT_SUCCESS(Status)) { DPRINT1("Can't get console, status %lx\n", Status); return Status; } Status = ConSrvRemoveObject(ProcessData, CloseHandleRequest->ConsoleHandle); ConSrvReleaseConsole(Console, TRUE); return Status; } CSR_API(SrvVerifyConsoleIoHandle) { NTSTATUS Status; PCONSOLE_VERIFYHANDLE VerifyHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.VerifyHandleRequest; PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process); PCONSOLE Console; HANDLE ConsoleHandle = VerifyHandleRequest->ConsoleHandle; ULONG Index = HandleToULong(ConsoleHandle) >> 2; Status = ConSrvGetConsole(ProcessData, &Console, TRUE); if (!NT_SUCCESS(Status)) { DPRINT1("Can't get console, status %lx\n", Status); return Status; } RtlEnterCriticalSection(&ProcessData->HandleTableLock); if (!IsConsoleHandle(ConsoleHandle) || Index >= ProcessData->HandleTableSize || ProcessData->HandleTable[Index].Object == NULL) { DPRINT("SrvVerifyConsoleIoHandle failed\n"); Status = STATUS_INVALID_HANDLE; } RtlLeaveCriticalSection(&ProcessData->HandleTableLock); ConSrvReleaseConsole(Console, TRUE); return Status; } CSR_API(SrvDuplicateHandle) { NTSTATUS Status; PCONSOLE_DUPLICATEHANDLE DuplicateHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.DuplicateHandleRequest; PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process); PCONSOLE Console; HANDLE ConsoleHandle = DuplicateHandleRequest->ConsoleHandle; ULONG Index = HandleToULong(ConsoleHandle) >> 2; PCONSOLE_IO_HANDLE Entry; DWORD DesiredAccess; Status = ConSrvGetConsole(ProcessData, &Console, TRUE); if (!NT_SUCCESS(Status)) { DPRINT1("Can't get console, status %lx\n", Status); return Status; } RtlEnterCriticalSection(&ProcessData->HandleTableLock); if ( /** !IsConsoleHandle(ConsoleHandle) || **/ Index >= ProcessData->HandleTableSize || (Entry = &ProcessData->HandleTable[Index])->Object == NULL) { DPRINT1("Couldn't duplicate invalid handle %p\n", ConsoleHandle); Status = STATUS_INVALID_HANDLE; goto Quit; } if (DuplicateHandleRequest->Options & DUPLICATE_SAME_ACCESS) { DesiredAccess = Entry->Access; } else { DesiredAccess = DuplicateHandleRequest->Access; /* Make sure the source handle has all the desired flags */ if ((Entry->Access & DesiredAccess) == 0) { DPRINT1("Handle %p only has access %X; requested %X\n", ConsoleHandle, Entry->Access, DesiredAccess); Status = STATUS_INVALID_PARAMETER; goto Quit; } } /* Insert the new handle inside the process handles table */ Status = ConSrvInsertObject(ProcessData, &DuplicateHandleRequest->ConsoleHandle, // Use the new handle value! Entry->Object, DesiredAccess, DuplicateHandleRequest->Inheritable, Entry->ShareMode); if (NT_SUCCESS(Status) && (DuplicateHandleRequest->Options & DUPLICATE_CLOSE_SOURCE)) { /* Close the original handle if needed */ ConSrvCloseHandleEntry(Entry); } Quit: RtlLeaveCriticalSection(&ProcessData->HandleTableLock); ConSrvReleaseConsole(Console, TRUE); return Status; } /* EOF */