[CSRSRV]
[reactos.git] / win32ss / user / consrv / handle.c
index 703c5bb..339dbb3 100644 (file)
-/* $Id: handle.c 57570 2012-10-17 23:10:40Z hbelusca $
- *
- * reactos/subsys/csrss/api/handle.c
- *
- * CSRSS handle functions
- *
- * ReactOS Operating System
+/*
+ * LICENSE:         GPL - See COPYING in the top level directory
+ * PROJECT:         ReactOS Console Server DLL
+ * FILE:            win32ss/user/consrv/handle.c
+ * PURPOSE:         Console I/O Handles functions
+ * PROGRAMMERS:
  */
 
 /* INCLUDES ******************************************************************/
 
-#include <w32csr.h>
+#include "consrv.h"
+#include "conio.h"
 
-#define NDEBUG
+//#define NDEBUG
 #include <debug.h>
 
-/* FUNCTIONS *****************************************************************/
 
-static
-BOOL
-CsrIsConsoleHandle(HANDLE Handle)
-{
-    return ((ULONG_PTR)Handle & 0x10000003) == 0x3;
-}
+/* PRIVATE FUNCTIONS *********************************************************/
 
 static INT
-AdjustHandleCounts(PCSRSS_HANDLE Entry, INT Change)
+AdjustHandleCounts(PCONSOLE_IO_HANDLE Entry, INT Change)
 {
     Object_t *Object = Entry->Object;
+
+    DPRINT1("AdjustHandleCounts(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
-Win32CsrCreateHandleEntry(PCSRSS_HANDLE Entry)
+ConSrvCreateHandleEntry(PCONSOLE_IO_HANDLE Entry)
 {
-    Object_t *Object = Entry->Object;
-    EnterCriticalSection(&Object->Console->Lock);
+    /// LOCK /// Object_t *Object = Entry->Object;
+    /// LOCK /// EnterCriticalSection(&Object->Console->Lock);
     AdjustHandleCounts(Entry, +1);
-    LeaveCriticalSection(&Object->Console->Lock);
+    /// LOCK /// LeaveCriticalSection(&Object->Console->Lock);
 }
 
 static VOID
-Win32CsrCloseHandleEntry(PCSRSS_HANDLE Entry)
+ConSrvCloseHandleEntry(PCONSOLE_IO_HANDLE Entry)
 {
     Object_t *Object = Entry->Object;
     if (Object != NULL)
     {
-        PCSRSS_CONSOLE Console = Object->Console;
-        EnterCriticalSection(&Console->Lock);
-        /* If the last handle to a screen buffer is closed, delete it */
-        if (AdjustHandleCounts(Entry, -1) == 0
-            && Object->Type == CONIO_SCREEN_BUFFER_MAGIC)
+        /// 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 == CONIO_INPUT_BUFFER_MAGIC)
         {
-            PCSRSS_SCREEN_BUFFER Buffer = (PCSRSS_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);
+            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);
+            }
         }
-        LeaveCriticalSection(&Console->Lock);
+
+        /* If the last handle to a screen buffer is closed, delete it... */
+        if (AdjustHandleCounts(Entry, -1) == 0)
+        {
+            if (Object->Type == CONIO_SCREEN_BUFFER_MAGIC)
+            {
+                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 == CONIO_INPUT_BUFFER_MAGIC)
+            {
+                DPRINT1("Closing the input buffer\n");
+            }
+        }
+
+        /// LOCK /// LeaveCriticalSection(&Console->Lock);
         Entry->Object = NULL;
     }
 }
 
-NTSTATUS
+
+/* FUNCTIONS *****************************************************************/
+
+/* static */ NTSTATUS
 FASTCALL
-Win32CsrReleaseObject(PCSR_PROCESS ProcessData,
-                      HANDLE Handle)
+ConSrvInitHandlesTable(IN OUT PCONSOLE_PROCESS_DATA ProcessData,
+                       OUT PHANDLE pInputHandle,
+                       OUT PHANDLE pOutputHandle,
+                       OUT PHANDLE pErrorHandle)
 {
-    ULONG_PTR h = (ULONG_PTR)Handle >> 2;
-    Object_t *Object;
+    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);
-    if (h >= ProcessData->HandleTableSize
-            || (Object = ProcessData->HandleTable[h].Object) == NULL)
+
+    /* Insert the Input handle */
+    Status = ConSrvInsertObject(ProcessData,
+                                &InputHandle,
+                                &ProcessData->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);
-        return STATUS_INVALID_HANDLE;
+        ConSrvFreeHandlesTable(ProcessData);
+        return Status;
+    }
+
+    /* Insert the Output handle */
+    Status = ConSrvInsertObject(ProcessData,
+                                &OutputHandle,
+                                &ProcessData->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;
     }
-    Win32CsrCloseHandleEntry(&ProcessData->HandleTable[h]);
+
+    /* Insert the Error handle */
+    Status = ConSrvInsertObject(ProcessData,
+                                &ErrorHandle,
+                                &ProcessData->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
 FASTCALL
-Win32CsrLockObject(PCSR_PROCESS ProcessData,
-                   HANDLE Handle,
-                   Object_t **Object,
-                   DWORD Access,
-                   LONG Type)
+ConSrvInheritHandlesTable(IN PCONSOLE_PROCESS_DATA SourceProcessData,
+                          IN PCONSOLE_PROCESS_DATA TargetProcessData)
 {
-    ULONG_PTR h = (ULONG_PTR)Handle >> 2;
+    NTSTATUS Status = STATUS_SUCCESS;
+    ULONG i;
 
-    DPRINT("CsrGetObject, Object: %x, %x, %x\n",
-           Object, Handle, ProcessData ? ProcessData->HandleTableSize : 0);
+    RtlEnterCriticalSection(&SourceProcessData->HandleTableLock);
 
-    RtlEnterCriticalSection(&ProcessData->HandleTableLock);
-    if (!CsrIsConsoleHandle(Handle) || h >= ProcessData->HandleTableSize
-            || (*Object = ProcessData->HandleTable[h].Object) == NULL
-            || ~ProcessData->HandleTable[h].Access & Access
-            || (Type != 0 && (*Object)->Type != Type))
+    /* Inherit a handles table only if there is no already */
+    if (TargetProcessData->HandleTable != NULL /* || TargetProcessData->HandleTableSize != 0 */)
     {
-        DPRINT1("CsrGetObject returning invalid handle (%x)\n", Handle);
-        RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
-        return STATUS_INVALID_HANDLE;
+        Status = STATUS_UNSUCCESSFUL; /* STATUS_INVALID_PARAMETER */
+        goto Quit;
     }
-    _InterlockedIncrement(&(*Object)->Console->ReferenceCount);
-    RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
 
-    EnterCriticalSection(&((*Object)->Console->Lock));
-    return STATUS_SUCCESS;
-}
+    /* Allocate a new handle table for the child process */
+    TargetProcessData->HandleTable = RtlAllocateHeap(ConSrvHeap,
+                                                     HEAP_ZERO_MEMORY,
+                                                     SourceProcessData->HandleTableSize
+                                                             * sizeof(CONSOLE_IO_HANDLE));
+    if (TargetProcessData->HandleTable == NULL)
+    {
+        Status = STATUS_NO_MEMORY;
+        goto Quit;
+    }
 
-VOID
-FASTCALL
-Win32CsrUnlockObject(Object_t *Object)
-{
-    PCSRSS_CONSOLE Console = Object->Console;
-    LeaveCriticalSection(&Console->Lock);
-    /* dec ref count */
-    if (_InterlockedDecrement(&Console->ReferenceCount) == 0)
-        ConioDeleteConsole(&Console->Header);
+    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; 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[i] = SourceProcessData->HandleTable[i];
+            ConSrvCreateHandleEntry(&TargetProcessData->HandleTable[i]);
+        }
+    }
+
+Quit:
+    RtlLeaveCriticalSection(&SourceProcessData->HandleTableLock);
+    return Status;
 }
 
 VOID
-WINAPI
-Win32CsrReleaseConsole(PCSR_PROCESS ProcessData)
+FASTCALL
+ConSrvFreeHandlesTable(PCONSOLE_PROCESS_DATA ProcessData)
 {
-    PCSRSS_CONSOLE Console;
-    ULONG i;
+    DPRINT1("ConSrvFreeHandlesTable\n");
 
-    /* Close all console handles and detach process from console */
     RtlEnterCriticalSection(&ProcessData->HandleTableLock);
 
-    for (i = 0; i < ProcessData->HandleTableSize; i++)
-        Win32CsrCloseHandleEntry(&ProcessData->HandleTable[i]);
-    ProcessData->HandleTableSize = 0;
-    RtlFreeHeap(ConSrvHeap, 0, ProcessData->HandleTable);
-    ProcessData->HandleTable = NULL;
-
-    Console = ProcessData->Console;
-    if (Console != NULL)
+    if (ProcessData->HandleTable != NULL)
     {
-        ProcessData->Console = NULL;
-        EnterCriticalSection(&Console->Lock);
-        RemoveEntryList(&ProcessData->ConsoleLink);
-        LeaveCriticalSection(&Console->Lock);
-        if (_InterlockedDecrement(&Console->ReferenceCount) == 0)
-            ConioDeleteConsole(&Console->Header);
-        //CloseHandle(ProcessData->ConsoleEvent);
-        //ProcessData->ConsoleEvent = NULL;
+        ULONG i;
+
+        /* Close all console handles and free the handle table memory */
+        for (i = 0; i < ProcessData->HandleTableSize; i++)
+        {
+            ConSrvCloseHandleEntry(&ProcessData->HandleTable[i]);
+        }
+        RtlFreeHeap(ConSrvHeap, 0, ProcessData->HandleTable);
+        ProcessData->HandleTable = NULL;
     }
+
+    ProcessData->HandleTableSize = 0;
+
     RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
 }
 
 NTSTATUS
 FASTCALL
-Win32CsrInsertObject(PCSR_PROCESS ProcessData,
-                     PHANDLE Handle,
-                     Object_t *Object,
-                     DWORD Access,
-                     BOOL Inheritable,
-                     DWORD ShareMode)
+ConSrvInsertObject(PCONSOLE_PROCESS_DATA ProcessData,
+                   PHANDLE Handle,
+                   Object_t *Object,
+                   DWORD Access,
+                   BOOL Inheritable,
+                   DWORD ShareMode)
 {
+#define IO_HANDLES_INCREMENT    2*3
+
     ULONG i;
-    PCSRSS_HANDLE Block;
+    PCONSOLE_IO_HANDLE Block;
 
     RtlEnterCriticalSection(&ProcessData->HandleTableLock);
 
@@ -185,138 +287,502 @@ Win32CsrInsertObject(PCSR_PROCESS ProcessData,
     {
         Block = RtlAllocateHeap(ConSrvHeap,
                                 HEAP_ZERO_MEMORY,
-                                (ProcessData->HandleTableSize + 64) * sizeof(CSRSS_HANDLE));
+                                (ProcessData->HandleTableSize +
+                                    IO_HANDLES_INCREMENT) * sizeof(CONSOLE_IO_HANDLE));
         if (Block == NULL)
         {
             RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
-            return(STATUS_UNSUCCESSFUL);
+            return STATUS_UNSUCCESSFUL;
         }
         RtlCopyMemory(Block,
                       ProcessData->HandleTable,
-                      ProcessData->HandleTableSize * sizeof(CSRSS_HANDLE));
+                      ProcessData->HandleTableSize * sizeof(CONSOLE_IO_HANDLE));
         RtlFreeHeap(ConSrvHeap, 0, ProcessData->HandleTable);
         ProcessData->HandleTable = Block;
-        ProcessData->HandleTableSize += 64;
+        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;
-    Win32CsrCreateHandleEntry(&ProcessData->HandleTable[i]);
-    *Handle = UlongToHandle((i << 2) | 0x3);
+    ConSrvCreateHandleEntry(&ProcessData->HandleTable[i]);
+    *Handle = ULongToHandle((i << 2) | 0x3);
+
     RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
-    return(STATUS_SUCCESS);
+
+    return STATUS_SUCCESS;
 }
 
 NTSTATUS
-WINAPI
-Win32CsrDuplicateHandleTable(PCSR_PROCESS SourceProcessData,
-                             PCSR_PROCESS TargetProcessData)
+FASTCALL
+ConSrvRemoveObject(PCONSOLE_PROCESS_DATA ProcessData,
+                   HANDLE Handle)
 {
-    ULONG i;
-    
-    /* Only inherit if the flag was set */
-    if (!TargetProcessData->bInheritHandles) return STATUS_SUCCESS;
+    ULONG_PTR h = (ULONG_PTR)Handle >> 2;
+    Object_t *Object;
+
+    RtlEnterCriticalSection(&ProcessData->HandleTableLock);
 
-    if (TargetProcessData->HandleTableSize)
+    if (h >= ProcessData->HandleTableSize ||
+        (Object = ProcessData->HandleTable[h].Object) == NULL)
     {
-        return STATUS_INVALID_PARAMETER;
+        RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+        return STATUS_INVALID_HANDLE;
     }
 
-    RtlEnterCriticalSection(&SourceProcessData->HandleTableLock);
+    DPRINT1("ConSrvRemoveObject - Process 0x%p, Release 0x%p\n", ProcessData->Process, &ProcessData->HandleTable[h]);
+    ConSrvCloseHandleEntry(&ProcessData->HandleTable[h]);
 
-    /* we are called from CreateProcessData, it isn't necessary to lock the target process data */
+    RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
 
-    TargetProcessData->HandleTable = RtlAllocateHeap(ConSrvHeap,
-                                                     HEAP_ZERO_MEMORY,
-                                                     SourceProcessData->HandleTableSize
-                                                             * sizeof(CSRSS_HANDLE));
-    if (TargetProcessData->HandleTable == NULL)
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+FASTCALL
+ConSrvGetObject(PCONSOLE_PROCESS_DATA ProcessData,
+                HANDLE Handle,
+                Object_t** Object,
+                PCONSOLE_IO_HANDLE* Entry OPTIONAL,
+                DWORD Access,
+                BOOL LockConsole,
+                ULONG Type)
+{
+    ULONG_PTR h = (ULONG_PTR)Handle >> 2;
+    PCONSOLE_IO_HANDLE HandleEntry = NULL;
+    Object_t* ObjectEntry = NULL;
+
+    ASSERT(Object);
+    if (Entry) *Entry = NULL;
+
+    // DPRINT("ConSrvGetObject, Object: %x, %x, %x\n",
+           // Object, Handle, ProcessData ? ProcessData->HandleTableSize : 0);
+
+    RtlEnterCriticalSection(&ProcessData->HandleTableLock);
+
+    if ( IsConsoleHandle(Handle) &&
+         h < ProcessData->HandleTableSize )
     {
-        RtlLeaveCriticalSection(&SourceProcessData->HandleTableLock);
-        return(STATUS_UNSUCCESSFUL);
+        HandleEntry = &ProcessData->HandleTable[h];
+        ObjectEntry = HandleEntry->Object;
     }
-    TargetProcessData->HandleTableSize = SourceProcessData->HandleTableSize;
-    for (i = 0; i < SourceProcessData->HandleTableSize; i++)
+
+    if ( HandleEntry == NULL ||
+         ObjectEntry == NULL ||
+         (HandleEntry->Access & Access) == 0 ||
+         (Type != 0 && ObjectEntry->Type != Type) )
     {
-        if (SourceProcessData->HandleTable[i].Object != NULL &&
-            SourceProcessData->HandleTable[i].Inheritable)
+        DPRINT1("ConSrvGetObject returning invalid handle (%x) of type %lu with access %lu\n", Handle, Type, Access);
+        RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+        return STATUS_INVALID_HANDLE;
+    }
+
+    _InterlockedIncrement(&ObjectEntry->Console->ReferenceCount);
+    RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+
+    if (LockConsole) EnterCriticalSection(&ObjectEntry->Console->Lock);
+
+    /* Return the objects to the caller */
+    *Object = ObjectEntry;
+    if (Entry) *Entry = HandleEntry;
+
+    return STATUS_SUCCESS;
+}
+
+VOID
+FASTCALL
+ConSrvReleaseObject(Object_t *Object,
+                    BOOL IsConsoleLocked)
+{
+    ConSrvReleaseConsole(Object->Console, IsConsoleLocked);
+}
+
+NTSTATUS
+FASTCALL
+ConSrvAllocateConsole(PCONSOLE_PROCESS_DATA ProcessData,
+                      LPCWSTR AppPath,
+                      PHANDLE pInputHandle,
+                      PHANDLE pOutputHandle,
+                      PHANDLE pErrorHandle,
+                      PCONSOLE_START_INFO ConsoleStartInfo)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    /* Initialize a new Console owned by this process */
+    Status = ConSrvInitConsole(&ProcessData->Console, AppPath, ConsoleStartInfo, ProcessData->Process);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Console initialization failed\n");
+        return Status;
+    }
+
+    /* Initialize the handles table */
+    Status = ConSrvInitHandlesTable(ProcessData,
+                                    pInputHandle,
+                                    pOutputHandle,
+                                    pErrorHandle);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Failed to initialize the handles table\n");
+        ConSrvDeleteConsole(ProcessData->Console);
+        ProcessData->Console = NULL;
+        return Status;
+    }
+
+    /* Duplicate the Input Event */
+    Status = NtDuplicateObject(NtCurrentProcess(),
+                               ProcessData->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(ProcessData->Console);
+        ProcessData->Console = NULL;
+        return Status;
+    }
+
+    /* Insert the process into the processes list of the console */
+    InsertHeadList(&ProcessData->Console->ProcessList, &ProcessData->ConsoleLink);
+
+    /* Add a reference count because the process is tied to the console */
+    _InterlockedIncrement(&ProcessData->Console->ReferenceCount);
+
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+FASTCALL
+ConSrvInheritConsole(PCONSOLE_PROCESS_DATA ProcessData,
+                     PCONSOLE Console,
+                     BOOL CreateNewHandlesTable,
+                     PHANDLE pInputHandle,
+                     PHANDLE pOutputHandle,
+                     PHANDLE pErrorHandle)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    /* Inherit the console */
+    ProcessData->Console = Console;
+
+    if (CreateNewHandlesTable)
+    {
+        /* Initialize the handles table */
+        Status = ConSrvInitHandlesTable(ProcessData,
+                                        pInputHandle,
+                                        pOutputHandle,
+                                        pErrorHandle);
+        if (!NT_SUCCESS(Status))
         {
-            TargetProcessData->HandleTable[i] = SourceProcessData->HandleTable[i];
-            Win32CsrCreateHandleEntry(&TargetProcessData->HandleTable[i]);
+            DPRINT1("Failed to initialize the handles table\n");
+            ProcessData->Console = NULL;
+            return Status;
         }
     }
-    RtlLeaveCriticalSection(&SourceProcessData->HandleTableLock);
-    return(STATUS_SUCCESS);
+
+    /* Duplicate the Input Event */
+    Status = NtDuplicateObject(NtCurrentProcess(),
+                               ProcessData->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->Console = NULL;
+        return Status;
+    }
+
+    /* Insert the process into the processes list of the console */
+    InsertHeadList(&ProcessData->Console->ProcessList, &ProcessData->ConsoleLink);
+
+    /* Add a reference count because the process is tied to the console */
+    _InterlockedIncrement(&ProcessData->Console->ReferenceCount);
+
+    return STATUS_SUCCESS;
 }
 
-CSR_API(CsrGetHandle)
+VOID
+FASTCALL
+ConSrvRemoveConsole(PCONSOLE_PROCESS_DATA ProcessData)
 {
-    NTSTATUS Status = STATUS_SUCCESS;
-    PCSR_PROCESS ProcessData = CsrGetClientThread()->Process;
+    PCONSOLE Console;
 
-    ApiMessage->Data.GetInputHandleRequest.Handle = INVALID_HANDLE_VALUE;
+    DPRINT1("ConSrvRemoveConsole\n");
+
+    /* Close all console handles and free the handle table memory */
+    ConSrvFreeHandlesTable(ProcessData);
+
+    /* Detach process from console */
+    Console = ProcessData->Console;
+    if (Console != NULL)
+    {
+        DPRINT1("ConSrvRemoveConsole - Console->ReferenceCount = %lu - We are going to decrement it !\n", Console->ReferenceCount);
+        ProcessData->Console = NULL;
+
+        EnterCriticalSection(&Console->Lock);
+        DPRINT1("ConSrvRemoveConsole - Locking OK\n");
+
+        /* Remove ourselves from the console's list of processes */
+        RemoveEntryList(&ProcessData->ConsoleLink);
+
+        /* Update the console leader process */
+        // SetConsoleWndConsoleLeaderCID(Console);
+
+        /* Release the console */
+        ConSrvReleaseConsole(Console, TRUE);
+        //CloseHandle(ProcessData->ConsoleEvent);
+        //ProcessData->ConsoleEvent = NULL;
+    }
+}
+
+NTSTATUS
+FASTCALL
+ConSrvGetConsole(PCONSOLE_PROCESS_DATA ProcessData,
+                 PCONSOLE* Console,
+                 BOOL LockConsole)
+{
+    PCONSOLE ProcessConsole;
 
     RtlEnterCriticalSection(&ProcessData->HandleTableLock);
-    if (ProcessData->Console)
+    ProcessConsole = ProcessData->Console;
+
+    if (!ProcessConsole)
     {
-        DWORD DesiredAccess = ApiMessage->Data.GetInputHandleRequest.Access;
-        DWORD ShareMode = ApiMessage->Data.GetInputHandleRequest.ShareMode;
+        *Console = NULL;
+        RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
+        return STATUS_INVALID_HANDLE;
+    }
 
-        PCSRSS_CONSOLE Console = ProcessData->Console;
-        Object_t *Object;
+    InterlockedIncrement(&ProcessConsole->ReferenceCount);
+    RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
 
-        EnterCriticalSection(&Console->Lock);
-        if (ApiMessage->ApiNumber == GET_OUTPUT_HANDLE)
-            Object = &Console->ActiveBuffer->Header;
-        else
-            Object = &Console->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))
+    if (LockConsole) EnterCriticalSection(&ProcessConsole->Lock);
+
+    *Console = ProcessConsole;
+
+    return STATUS_SUCCESS;
+}
+
+VOID FASTCALL
+ConSrvReleaseConsole(PCONSOLE Console,
+                     BOOL IsConsoleLocked)
+{
+    if (IsConsoleLocked) LeaveCriticalSection(&Console->Lock);
+
+    /* Decrement reference count */
+    if (_InterlockedDecrement(&Console->ReferenceCount) == 0)
+        ConSrvDeleteConsole(Console);
+}
+
+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.
+     **************************************************************************/
+
+    PCONSOLE_PROCESS_DATA SourceProcessData, TargetProcessData;
+
+    /* An empty target process is invalid */
+    if (!TargetProcess) return STATUS_INVALID_PARAMETER;
+
+    TargetProcessData = ConsoleGetPerProcessData(TargetProcess);
+
+    /**** HACK !!!! ****/ RtlZeroMemory(TargetProcessData, sizeof(*TargetProcessData));
+
+    /* Initialize the new (target) process */
+    TargetProcessData->Process = TargetProcess;
+    TargetProcessData->ConsoleEvent = NULL;
+    TargetProcessData->Console = TargetProcessData->ParentConsole = NULL;
+    TargetProcessData->ConsoleApp = ((TargetProcess->Flags & CsrProcessIsConsoleApp) ? TRUE : FALSE);
+
+    // Testing
+    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 both of the processes (parent and new child) are console applications,
+     * then try to inherit handles from the parent process.
+     */
+    if ( SourceProcessData->Console != NULL && /* SourceProcessData->ConsoleApp */
+         TargetProcessData->ConsoleApp )
+    {
+        NTSTATUS Status;
+
+        Status = ConSrvInheritHandlesTable(SourceProcessData, TargetProcessData);
+        if (!NT_SUCCESS(Status)) return Status;
+
+        /* Temporary save the parent's console */
+        TargetProcessData->ParentConsole = SourceProcessData->Console;
+    }
+
+    return STATUS_SUCCESS;
+}
+
+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;
+    PCONSOLE_CONNECTION_INFO ConnectInfo = (PCONSOLE_CONNECTION_INFO)ConnectionInfo;
+    PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrProcess);
+
+    if ( ConnectionInfo       == NULL ||
+         ConnectionInfoLength == NULL ||
+        *ConnectionInfoLength != sizeof(CONSOLE_CONNECTION_INFO) )
+    {
+        DPRINT1("CONSRV: Connection failed\n");
+        return STATUS_UNSUCCESSFUL;
+    }
+
+    /* If we don't need a console, then get out of here */
+    if (!ConnectInfo->ConsoleNeeded || !ProcessData->ConsoleApp) // In fact, it is for GUI apps.
+    {
+        return STATUS_SUCCESS;
+    }
+
+    /* If we don't have a console, then create a new one... */
+    if (!ConnectInfo->Console ||
+         ConnectInfo->Console != ProcessData->ParentConsole)
+    {
+        DPRINT1("ConSrvConnect - Allocate a new console\n");
+
+        /*
+         * 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 console we can have and our handles table,
+         * and recreate a new one later on.
+         */
+        ConSrvRemoveConsole(ProcessData);
+
+        /* Initialize a new Console owned by the Console Leader Process */
+        Status = ConSrvAllocateConsole(ProcessData,
+                                       ConnectInfo->AppPath,
+                                       &ConnectInfo->InputHandle,
+                                       &ConnectInfo->OutputHandle,
+                                       &ConnectInfo->ErrorHandle,
+                                       &ConnectInfo->ConsoleStartInfo);
+        if (!NT_SUCCESS(Status))
         {
-            DPRINT1("Sharing violation\n");
-            Status = STATUS_SHARING_VIOLATION;
+            DPRINT1("Console allocation failed\n");
+            return Status;
         }
-        else
+    }
+    else /* We inherit it from the parent */
+    {
+        DPRINT1("ConSrvConnect - Reuse current (parent's) console\n");
+
+        /* Reuse our current console */
+        Status = ConSrvInheritConsole(ProcessData,
+                                      ConnectInfo->Console,
+                                      FALSE,
+                                      NULL,  // &ConnectInfo->InputHandle,
+                                      NULL,  // &ConnectInfo->OutputHandle,
+                                      NULL); // &ConnectInfo->ErrorHandle);
+        if (!NT_SUCCESS(Status))
         {
-            Status = Win32CsrInsertObject(ProcessData,
-                                          &ApiMessage->Data.GetInputHandleRequest.Handle,
-                                          Object,
-                                          DesiredAccess,
-                                          ApiMessage->Data.GetInputHandleRequest.Inheritable,
-                                          ShareMode);
+            DPRINT1("Console inheritance failed\n");
+            return Status;
         }
-        LeaveCriticalSection(&Console->Lock);
     }
-    RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
 
-    return Status;
+    /* Return it to the caller */
+    ConnectInfo->Console = ProcessData->Console;
+
+    /* Input Wait Handle */
+    ConnectInfo->InputWaitHandle = ProcessData->ConsoleEvent;
+
+    /* Set the Property Dialog Handler */
+    ProcessData->PropDispatcher = ConnectInfo->PropDispatcher;
+
+    /* Set the Ctrl Dispatcher */
+    ProcessData->CtrlDispatcher = ConnectInfo->CtrlDispatcher;
+
+    return STATUS_SUCCESS;
 }
 
-// CSR_API(CsrSetHandle) ??
+VOID
+NTAPI
+ConSrvDisconnect(PCSR_PROCESS Process)
+{
+    PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(Process);
+
+    /**************************************************************************
+     * This function is called whenever a new process (GUI or CUI) is destroyed.
+     **************************************************************************/
+
+    DPRINT1("ConSrvDisconnect\n");
+
+    if ( ProcessData->Console     != NULL ||
+         ProcessData->HandleTable != NULL )
+    {
+        DPRINT1("ConSrvDisconnect - calling ConSrvRemoveConsole\n");
+        ConSrvRemoveConsole(ProcessData);
+    }
+
+    RtlDeleteCriticalSection(&ProcessData->HandleTableLock);
+}
+
+
 
 CSR_API(SrvCloseHandle)
 {
-    return Win32CsrReleaseObject(CsrGetClientThread()->Process, ApiMessage->Data.CloseHandleRequest.Handle);
+    PCONSOLE_CLOSEHANDLE CloseHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.CloseHandleRequest;
+
+    return ConSrvRemoveObject(ConsoleGetPerProcessData(CsrGetClientThread()->Process),
+                                 CloseHandleRequest->ConsoleHandle);
 }
 
 CSR_API(SrvVerifyConsoleIoHandle)
 {
-    ULONG_PTR Index;
     NTSTATUS Status = STATUS_SUCCESS;
-    PCSR_PROCESS ProcessData = CsrGetClientThread()->Process;
+    PCONSOLE_VERIFYHANDLE VerifyHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.VerifyHandleRequest;
+    PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
+    HANDLE ConsoleHandle = VerifyHandleRequest->ConsoleHandle;
+    ULONG_PTR Index = (ULONG_PTR)ConsoleHandle >> 2;
 
-    Index = (ULONG_PTR)ApiMessage->Data.VerifyHandleRequest.Handle >> 2;
     RtlEnterCriticalSection(&ProcessData->HandleTableLock);
-    if (Index >= ProcessData->HandleTableSize ||
+
+    if (!IsConsoleHandle(ConsoleHandle)    ||
+        Index >= ProcessData->HandleTableSize ||
         ProcessData->HandleTable[Index].Object == NULL)
     {
-        DPRINT("CsrVerifyObject failed\n");
+        DPRINT("SrvVerifyConsoleIoHandle failed\n");
         Status = STATUS_INVALID_HANDLE;
     }
+
     RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
 
     return Status;
@@ -324,58 +790,55 @@ CSR_API(SrvVerifyConsoleIoHandle)
 
 CSR_API(SrvDuplicateHandle)
 {
-    ULONG_PTR Index;
-    PCSRSS_HANDLE Entry;
+    PCONSOLE_IO_HANDLE Entry;
     DWORD DesiredAccess;
-    PCSR_PROCESS ProcessData = CsrGetClientThread()->Process;
+    PCONSOLE_DUPLICATEHANDLE DuplicateHandleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.DuplicateHandleRequest;
+    PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrGetClientThread()->Process);
+    HANDLE ConsoleHandle = DuplicateHandleRequest->ConsoleHandle;
+    ULONG_PTR Index = (ULONG_PTR)ConsoleHandle >> 2;
 
-    Index = (ULONG_PTR)ApiMessage->Data.DuplicateHandleRequest.Handle >> 2;
     RtlEnterCriticalSection(&ProcessData->HandleTableLock);
-    if (Index >= ProcessData->HandleTableSize
-        || (Entry = &ProcessData->HandleTable[Index])->Object == NULL)
+
+    if ( /** !IsConsoleHandle(ConsoleHandle)    || **/
+        Index >= ProcessData->HandleTableSize ||
+        (Entry = &ProcessData->HandleTable[Index])->Object == NULL)
     {
-        DPRINT1("Couldn't dup invalid handle %p\n", ApiMessage->Data.DuplicateHandleRequest.Handle);
+        DPRINT1("Couldn't duplicate invalid handle %p\n", ConsoleHandle);
         RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
         return STATUS_INVALID_HANDLE;
     }
 
-    if (ApiMessage->Data.DuplicateHandleRequest.Options & DUPLICATE_SAME_ACCESS)
+    if (DuplicateHandleRequest->Options & DUPLICATE_SAME_ACCESS)
     {
         DesiredAccess = Entry->Access;
     }
     else
     {
-        DesiredAccess = ApiMessage->Data.DuplicateHandleRequest.Access;
+        DesiredAccess = DuplicateHandleRequest->Access;
         /* Make sure the source handle has all the desired flags */
-        if (~Entry->Access & DesiredAccess)
+        if ((Entry->Access & DesiredAccess) == 0)
         {
             DPRINT1("Handle %p only has access %X; requested %X\n",
-                ApiMessage->Data.DuplicateHandleRequest.Handle, Entry->Access, DesiredAccess);
+                ConsoleHandle, Entry->Access, DesiredAccess);
             RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
             return STATUS_INVALID_PARAMETER;
         }
     }
 
-    ApiMessage->Status = Win32CsrInsertObject(ProcessData,
-                                           &ApiMessage->Data.DuplicateHandleRequest.Handle,
-                                           Entry->Object,
-                                           DesiredAccess,
-                                           ApiMessage->Data.DuplicateHandleRequest.Inheritable,
-                                           Entry->ShareMode);
-    if (NT_SUCCESS(ApiMessage->Status)
-        && ApiMessage->Data.DuplicateHandleRequest.Options & DUPLICATE_CLOSE_SOURCE)
+    ApiMessage->Status = ConSrvInsertObject(ProcessData,
+                                            &DuplicateHandleRequest->ConsoleHandle, // Use the new handle value!
+                                            Entry->Object,
+                                            DesiredAccess,
+                                            DuplicateHandleRequest->Inheritable,
+                                            Entry->ShareMode);
+    if (NT_SUCCESS(ApiMessage->Status) &&
+        DuplicateHandleRequest->Options & DUPLICATE_CLOSE_SOURCE)
     {
-        Win32CsrCloseHandleEntry(Entry);
+        ConSrvCloseHandleEntry(Entry);
     }
 
     RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
     return ApiMessage->Status;
 }
 
-CSR_API(CsrGetInputWaitHandle)
-{
-    ApiMessage->Data.GetConsoleInputWaitHandle.InputWaitHandle = CsrGetClientThread()->Process->ConsoleEvent;
-    return STATUS_SUCCESS;
-}
-
 /* EOF */