[KERNEL32]

- Correct a error return code (in AllocConsole).
- Implement AttachConsole (inspired by AllocConsole).

[CONSRV]
- Correct a error return code (in AllocConsole).
- Introduce helper functions to simplify console-initialization code.
- Implement server-side of AttachConsole (I used pieces of code from ConsoleNewProcess, ConsoleConnect and SrvAllocConsole).

Some debug prints were introduced (for debug-purposes :P), will be removed when all things work.

TODO: have a look on the handles code.

svn path=/branches/ros-csrss/; revision=58166
This commit is contained in:
Hermès Bélusca-Maïto 2013-01-13 17:07:25 +00:00
parent 074466b15e
commit df7477717c
6 changed files with 416 additions and 213 deletions

View file

@ -802,8 +802,8 @@ AllocConsole(VOID)
if (NtCurrentPeb()->ProcessParameters->ConsoleHandle) if (NtCurrentPeb()->ProcessParameters->ConsoleHandle)
{ {
DPRINT("AllocConsole: Allocate duplicate console to the same Process\n"); DPRINT1("AllocConsole: Allocate duplicate console to the same Process\n");
BaseSetLastNTError (STATUS_OBJECT_NAME_EXISTS); SetLastError(ERROR_ACCESS_DENIED);
return FALSE; return FALSE;
} }
@ -824,7 +824,6 @@ AllocConsole(VOID)
} }
NtCurrentPeb()->ProcessParameters->ConsoleHandle = AllocConsoleRequest->Console; NtCurrentPeb()->ProcessParameters->ConsoleHandle = AllocConsoleRequest->Console;
SetStdHandle(STD_INPUT_HANDLE , AllocConsoleRequest->InputHandle ); SetStdHandle(STD_INPUT_HANDLE , AllocConsoleRequest->InputHandle );
SetStdHandle(STD_OUTPUT_HANDLE, AllocConsoleRequest->OutputHandle); SetStdHandle(STD_OUTPUT_HANDLE, AllocConsoleRequest->OutputHandle);
SetStdHandle(STD_ERROR_HANDLE , AllocConsoleRequest->ErrorHandle ); SetStdHandle(STD_ERROR_HANDLE , AllocConsoleRequest->ErrorHandle );
@ -1910,13 +1909,50 @@ GetConsoleSelectionInfo(PCONSOLE_SELECTION_INFO lpConsoleSelectionInfo)
/*-------------------------------------------------------------- /*--------------------------------------------------------------
* AttachConsole * AttachConsole
* *
* @unimplemented * @implemented
*
* @note Strongly inspired by AllocConsole.
*/ */
BOOL BOOL
WINAPI WINAPI
AttachConsole(DWORD dwProcessId) AttachConsole(DWORD dwProcessId)
{ {
DPRINT1("AttachConsole(0x%x) UNIMPLEMENTED!\n", dwProcessId); NTSTATUS Status;
CONSOLE_API_MESSAGE ApiMessage;
PCONSOLE_ATTACHCONSOLE AttachConsoleRequest = &ApiMessage.Data.AttachConsoleRequest;
DPRINT1("AttachConsole(%lu)\n", dwProcessId);
if (NtCurrentPeb()->ProcessParameters->ConsoleHandle)
{
DPRINT1("AttachConsole: Attaching a console to a process already having one\n");
SetLastError(ERROR_ACCESS_DENIED);
return FALSE;
}
AttachConsoleRequest->ProcessId = dwProcessId;
AttachConsoleRequest->CtrlDispatcher = ConsoleControlDispatcher;
Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
NULL,
CSR_CREATE_API_NUMBER(CONSRV_SERVERDLL_INDEX, ConsolepAttach),
sizeof(CONSOLE_ATTACHCONSOLE));
if (!NT_SUCCESS(Status) || !NT_SUCCESS(Status = ApiMessage.Status))
{
BaseSetLastNTError(Status);
return FALSE;
}
NtCurrentPeb()->ProcessParameters->ConsoleHandle = AttachConsoleRequest->Console;
SetStdHandle(STD_INPUT_HANDLE , AttachConsoleRequest->InputHandle );
SetStdHandle(STD_OUTPUT_HANDLE, AttachConsoleRequest->OutputHandle);
SetStdHandle(STD_ERROR_HANDLE , AttachConsoleRequest->ErrorHandle );
/* Initialize Console Ctrl Handler */
InitConsoleCtrlHandling();
InputWaitHandle = AttachConsoleRequest->InputWaitHandle;
return TRUE; return TRUE;
} }

View file

@ -102,7 +102,7 @@ typedef enum _CONSRV_API_NUMBER
// ConsolepRegisterConsoleIME, // ConsolepRegisterConsoleIME,
// ConsolepUnregisterConsoleIME, // ConsolepUnregisterConsoleIME,
// ConsolepGetLangId, // ConsolepGetLangId,
// ConsolepAttach, ConsolepAttach,
ConsolepGetSelectionInfo, ConsolepGetSelectionInfo,
ConsolepGetProcessList, ConsolepGetProcessList,
ConsolepGetHistory, ConsolepGetHistory,
@ -177,6 +177,17 @@ typedef struct
LPTHREAD_START_ROUTINE CtrlDispatcher; LPTHREAD_START_ROUTINE CtrlDispatcher;
} CONSOLE_ALLOCCONSOLE, *PCONSOLE_ALLOCCONSOLE; } CONSOLE_ALLOCCONSOLE, *PCONSOLE_ALLOCCONSOLE;
typedef struct
{
DWORD ProcessId; // If ProcessId == ATTACH_PARENT_PROCESS == -1, then attach the current process to its parent process console.
HANDLE Console; // ConsoleHandle // In fact, it is a PCSRSS_CONSOLE <-- correct that !!
HANDLE InputHandle;
HANDLE OutputHandle;
HANDLE ErrorHandle;
HANDLE InputWaitHandle;
LPTHREAD_START_ROUTINE CtrlDispatcher;
} CONSOLE_ATTACHCONSOLE, *PCONSOLE_ATTACHCONSOLE;
typedef struct typedef struct
{ {
ULONG Dummy; ULONG Dummy;
@ -543,6 +554,7 @@ typedef struct _CONSOLE_API_MESSAGE
union union
{ {
CONSOLE_ALLOCCONSOLE AllocConsoleRequest; CONSOLE_ALLOCCONSOLE AllocConsoleRequest;
CONSOLE_ATTACHCONSOLE AttachConsoleRequest;
CONSOLE_FREECONSOLE FreeConsoleRequest; CONSOLE_FREECONSOLE FreeConsoleRequest;
/* Handles */ /* Handles */

View file

@ -301,58 +301,52 @@ CSR_API(SrvAllocConsole)
if (ProcessData->Console != NULL) if (ProcessData->Console != NULL)
{ {
DPRINT1("Process already has a console\n"); DPRINT1("Process already has a console\n");
return STATUS_INVALID_PARAMETER; return STATUS_ACCESS_DENIED;
} }
RtlEnterCriticalSection(&ProcessData->HandleTableLock); /******************************************************************************/
/** This comes from ConsoleConnect!! **/
DPRINT1("SrvAllocConsole - Checkpoint 1\n"); DPRINT1("SrvAllocConsole - Checkpoint 1\n");
#if 0000
/*
* We are about to create a new console. However when ConsoleNewProcess
* 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.
*/
Win32CsrReleaseConsole(ProcessData);
// Win32CsrFreeHandlesTable(ProcessData);
#endif
/* Initialize a new Console owned by the Console Leader Process */ /* Initialize a new Console owned by the Console Leader Process */
Status = CsrInitConsole(&ProcessData->Console, AllocConsoleRequest->ShowCmd, ConsoleLeader); Status = CsrInitConsole(&ProcessData->Console, AllocConsoleRequest->ShowCmd, ConsoleLeader);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
DPRINT1("Console initialization failed\n"); DPRINT1("Console initialization failed\n");
RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
return Status; return Status;
} }
/* Add a reference count because the process is tied to the console */
_InterlockedIncrement(&ProcessData->Console->ReferenceCount);
/* Insert the process into the processes list of the console */ /* Insert the process into the processes list of the console */
InsertHeadList(&ProcessData->Console->ProcessList, &ProcessData->ConsoleLink); InsertHeadList(&ProcessData->Console->ProcessList, &ProcessData->ConsoleLink);
/* Return it to the caller */ /* Return it to the caller */
AllocConsoleRequest->Console = ProcessData->Console; AllocConsoleRequest->Console = ProcessData->Console;
/* Add a reference count because the process is tied to the console */
_InterlockedIncrement(&ProcessData->Console->ReferenceCount);
#if 0000
/*
* We've just created a new console. However when ConsoleNewProcess 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 our handles table and recreate a new one.
*/
ULONG i;
/* Close all console handles and free the handle table memory */
for (i = 0; i < ProcessData->HandleTableSize; i++)
{
Win32CsrCloseHandleEntry(&ProcessData->HandleTable[i]);
}
ProcessData->HandleTableSize = 0;
RtlFreeHeap(ConSrvHeap, 0, ProcessData->HandleTable);
ProcessData->HandleTable = NULL;
#endif
/* /*
* Create a new handle table - Insert the IO handles * Create a new handle table - Insert the IO handles
*/ */
RtlEnterCriticalSection(&ProcessData->HandleTableLock);
/* Insert the Input handle */ /* Insert the Input handle */
Status = Win32CsrInsertObject(ProcessData, Status = Win32CsrInsertObject(ProcessData,
&AllocConsoleRequest->InputHandle, &AllocConsoleRequest->InputHandle,
@ -363,9 +357,10 @@ CSR_API(SrvAllocConsole)
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
DPRINT1("Failed to insert the input handle\n"); DPRINT1("Failed to insert the input handle\n");
ConioDeleteConsole(ProcessData->Console);
ProcessData->Console = NULL;
RtlLeaveCriticalSection(&ProcessData->HandleTableLock); RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
Win32CsrReleaseConsole(ProcessData);
// ConioDeleteConsole(ProcessData->Console);
// ProcessData->Console = NULL;
return Status; return Status;
} }
@ -379,11 +374,12 @@ CSR_API(SrvAllocConsole)
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
DPRINT1("Failed to insert the output handle\n"); DPRINT1("Failed to insert the output handle\n");
ConioDeleteConsole(ProcessData->Console);
Win32CsrReleaseObject(ProcessData,
AllocConsoleRequest->InputHandle);
ProcessData->Console = NULL;
RtlLeaveCriticalSection(&ProcessData->HandleTableLock); RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
Win32CsrReleaseConsole(ProcessData);
// Win32CsrReleaseObject(ProcessData,
// AllocConsoleRequest->InputHandle);
// ConioDeleteConsole(ProcessData->Console);
// ProcessData->Console = NULL;
return Status; return Status;
} }
@ -397,16 +393,19 @@ CSR_API(SrvAllocConsole)
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
DPRINT1("Failed to insert the error handle\n"); DPRINT1("Failed to insert the error handle\n");
ConioDeleteConsole(ProcessData->Console);
Win32CsrReleaseObject(ProcessData,
AllocConsoleRequest->OutputHandle);
Win32CsrReleaseObject(ProcessData,
AllocConsoleRequest->InputHandle);
ProcessData->Console = NULL;
RtlLeaveCriticalSection(&ProcessData->HandleTableLock); RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
Win32CsrReleaseConsole(ProcessData);
// Win32CsrReleaseObject(ProcessData,
// AllocConsoleRequest->OutputHandle);
// Win32CsrReleaseObject(ProcessData,
// AllocConsoleRequest->InputHandle);
// ConioDeleteConsole(ProcessData->Console);
// ProcessData->Console = NULL;
return Status; return Status;
} }
RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
/* Duplicate the Event */ /* Duplicate the Event */
Status = NtDuplicateObject(NtCurrentProcess(), Status = NtDuplicateObject(NtCurrentProcess(),
ProcessData->Console->ActiveEvent, ProcessData->Console->ActiveEvent,
@ -416,18 +415,18 @@ CSR_API(SrvAllocConsole)
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
DPRINT1("NtDuplicateObject() failed: %lu\n", Status); DPRINT1("NtDuplicateObject() failed: %lu\n", Status);
ConioDeleteConsole(ProcessData->Console); Win32CsrReleaseConsole(ProcessData);
// if (NewConsole /* || !ProcessData->bInheritHandles */) // if (NewConsole)
{ // {
Win32CsrReleaseObject(ProcessData, // Win32CsrReleaseObject(ProcessData,
AllocConsoleRequest->ErrorHandle); // AllocConsoleRequest->ErrorHandle);
Win32CsrReleaseObject(ProcessData, // Win32CsrReleaseObject(ProcessData,
AllocConsoleRequest->OutputHandle); // AllocConsoleRequest->OutputHandle);
Win32CsrReleaseObject(ProcessData, // Win32CsrReleaseObject(ProcessData,
AllocConsoleRequest->InputHandle); // AllocConsoleRequest->InputHandle);
} // }
ProcessData->Console = NULL; // ConioDeleteConsole(ProcessData->Console); // FIXME: Just release the console ?
RtlLeaveCriticalSection(&ProcessData->HandleTableLock); // ProcessData->Console = NULL;
return Status; return Status;
} }
/* Input Wait Handle */ /* Input Wait Handle */
@ -436,15 +435,149 @@ CSR_API(SrvAllocConsole)
/* Set the Ctrl Dispatcher */ /* Set the Ctrl Dispatcher */
ProcessData->CtrlDispatcher = AllocConsoleRequest->CtrlDispatcher; ProcessData->CtrlDispatcher = AllocConsoleRequest->CtrlDispatcher;
DPRINT("CONSRV: CtrlDispatcher address: %x\n", ProcessData->CtrlDispatcher); DPRINT("CONSRV: CtrlDispatcher address: %x\n", ProcessData->CtrlDispatcher);
/******************************************************************************/
RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
CSR_API(SrvAttachConsole)
{
NTSTATUS Status = STATUS_SUCCESS;
PCONSOLE_ATTACHCONSOLE AttachConsoleRequest = &((PCONSOLE_API_MESSAGE)ApiMessage)->Data.AttachConsoleRequest;
PCSR_PROCESS SourceProcess = NULL; // The parent process.
PCSR_PROCESS TargetProcess = CsrGetClientThread()->Process; // Ourselves.
HANDLE ProcessId = ULongToHandle(AttachConsoleRequest->ProcessId);
PCONSOLE_PROCESS_DATA SourceProcessData, TargetProcessData;
DPRINT("SrvAttachConsole\n");
TargetProcessData = ConsoleGetPerProcessData(TargetProcess);
if (TargetProcessData->Console != NULL)
{
DPRINT1("Process already has a console\n");
return STATUS_ACCESS_DENIED;
}
if (ProcessId == ULongToHandle(ATTACH_PARENT_PROCESS))
{
PROCESS_BASIC_INFORMATION ProcessInfo;
ULONG Length = sizeof(ProcessInfo);
/* Get the real parent's ID */
Status = NtQueryInformationProcess(TargetProcess->ProcessHandle,
ProcessBasicInformation,
&ProcessInfo,
Length, &Length);
if (!NT_SUCCESS(Status))
{
DPRINT1("SrvAttachConsole - Cannot retrieve basic process info, Status = %lu\n", Status);
return Status;
}
DPRINT("We, process (ID) %lu;%lu\n", TargetProcess->ClientId.UniqueProcess, TargetProcess->ClientId.UniqueThread);
ProcessId = ULongToHandle(ProcessInfo.InheritedFromUniqueProcessId);
DPRINT("Parent process ID = %lu\n", ProcessId);
}
/* Lock the target process via its PID */
DPRINT1("Lock process Id %lu\n", ProcessId);
Status = CsrLockProcessByClientId(ProcessId, &SourceProcess);
DPRINT1("Lock process Status %lu\n", Status);
if (!NT_SUCCESS(Status)) return Status;
DPRINT1("AttachConsole OK\n");
/******************************************************************************/
/** This comes from ConsoleNewProcess!! **/
SourceProcessData = ConsoleGetPerProcessData(SourceProcess);
/*
* Inherit the console from the parent,
* if any, otherwise return an error.
*/
DPRINT1("SourceProcessData->Console = 0x%p\n", SourceProcessData->Console);
if (SourceProcessData->Console == NULL)
{
Status = STATUS_INVALID_HANDLE;
goto Quit;
}
TargetProcessData->Console = SourceProcessData->Console;
DPRINT1("SrvAttachConsole - Copy the handle table (1)\n");
Status = Win32CsrInheritHandlesTable(SourceProcessData, TargetProcessData);
DPRINT1("SrvAttachConsole - Copy the handle table (2)\n");
if (!NT_SUCCESS(Status))
{
goto Quit;
}
/******************************************************************************/
/******************************************************************************/
/** This comes from ConsoleConnect / SrvAllocConsole!! **/
/* Add a reference count because the process is tied to the console */
_InterlockedIncrement(&TargetProcessData->Console->ReferenceCount);
/* Insert the process into the processes list of the console */
InsertHeadList(&TargetProcessData->Console->ProcessList, &TargetProcessData->ConsoleLink);
/* Return it to the caller */
AttachConsoleRequest->Console = TargetProcessData->Console;
/** Here, we inherited the console handles from the "source" process,
** so no need to reinitialize the handles table. **/
DPRINT1("SrvAttachConsole - Checkpoint\n");
/* Duplicate the Event */
Status = NtDuplicateObject(NtCurrentProcess(),
TargetProcessData->Console->ActiveEvent,
TargetProcessData->Process->ProcessHandle,
&TargetProcessData->ConsoleEvent,
EVENT_ALL_ACCESS, 0, 0);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtDuplicateObject() failed: %lu\n", Status);
Win32CsrReleaseConsole(TargetProcessData);
// #if 0
// if (NewConsole)
// {
// Win32CsrReleaseObject(TargetProcessData,
// AttachConsoleRequest->ErrorHandle);
// Win32CsrReleaseObject(TargetProcessData,
// AttachConsoleRequest->OutputHandle);
// Win32CsrReleaseObject(TargetProcessData,
// AttachConsoleRequest->InputHandle);
// }
// #endif
// ConioDeleteConsole(TargetProcessData->Console); // FIXME: Just release the console ?
// TargetProcessData->Console = NULL;
goto Quit;
}
/* Input Wait Handle */
AttachConsoleRequest->InputWaitHandle = TargetProcessData->ConsoleEvent;
/* Set the Ctrl Dispatcher */
TargetProcessData->CtrlDispatcher = AttachConsoleRequest->CtrlDispatcher;
DPRINT("CONSRV: CtrlDispatcher address: %x\n", TargetProcessData->CtrlDispatcher);
Status = STATUS_SUCCESS;
/******************************************************************************/
Quit:
DPRINT1("SrvAttachConsole - exiting 1\n");
/* Unlock the "source" process */
CsrUnlockProcess(SourceProcess);
DPRINT1("SrvAttachConsole - exiting 2\n");
return Status;
}
CSR_API(SrvFreeConsole) CSR_API(SrvFreeConsole)
{ {
DPRINT1("SrvFreeConsole\n"); DPRINT1("SrvFreeConsole\n");
Win32CsrReleaseConsole(CsrGetClientThread()->Process); Win32CsrReleaseConsole(ConsoleGetPerProcessData(CsrGetClientThread()->Process));
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }

View file

@ -73,7 +73,6 @@ typedef struct _CONSOLE_PROCESS_DATA
/* PCONSOLE */ struct _CONSOLE* Console; /* PCONSOLE */ struct _CONSOLE* Console;
/* PCONSOLE */ struct _CONSOLE* ParentConsole; /* PCONSOLE */ struct _CONSOLE* ParentConsole;
// BOOL bInheritHandles;
BOOL ConsoleApp; // TRUE if it is a CUI app, FALSE otherwise. BOOL ConsoleApp; // TRUE if it is a CUI app, FALSE otherwise.
RTL_CRITICAL_SECTION HandleTableLock; RTL_CRITICAL_SECTION HandleTableLock;
@ -118,6 +117,7 @@ CSR_API(SrvSetConsoleScreenBufferSize);
/* console.c */ /* console.c */
CSR_API(SrvOpenConsole); CSR_API(SrvOpenConsole);
CSR_API(SrvAllocConsole); CSR_API(SrvAllocConsole);
CSR_API(SrvAttachConsole);
CSR_API(SrvFreeConsole); CSR_API(SrvFreeConsole);
CSR_API(SrvSetConsoleMode); CSR_API(SrvSetConsoleMode);
CSR_API(SrvGetConsoleMode); CSR_API(SrvGetConsoleMode);
@ -139,6 +139,9 @@ CSR_API(SrvVerifyConsoleIoHandle);
CSR_API(SrvDuplicateHandle); CSR_API(SrvDuplicateHandle);
/// CSR_API(CsrGetInputWaitHandle); /// CSR_API(CsrGetInputWaitHandle);
NTSTATUS FASTCALL Win32CsrInheritHandlesTable(IN PCONSOLE_PROCESS_DATA SourceProcessData,
IN PCONSOLE_PROCESS_DATA TargetProcessData);
VOID FASTCALL Win32CsrFreeHandlesTable(PCONSOLE_PROCESS_DATA ProcessData);
NTSTATUS FASTCALL Win32CsrInsertObject(PCONSOLE_PROCESS_DATA ProcessData, NTSTATUS FASTCALL Win32CsrInsertObject(PCONSOLE_PROCESS_DATA ProcessData,
PHANDLE Handle, PHANDLE Handle,
Object_t *Object, Object_t *Object,
@ -153,6 +156,7 @@ NTSTATUS FASTCALL Win32CsrLockObject(PCONSOLE_PROCESS_DATA ProcessData,
VOID FASTCALL Win32CsrUnlockObject(Object_t *Object); VOID FASTCALL Win32CsrUnlockObject(Object_t *Object);
NTSTATUS FASTCALL Win32CsrReleaseObject(PCONSOLE_PROCESS_DATA ProcessData, NTSTATUS FASTCALL Win32CsrReleaseObject(PCONSOLE_PROCESS_DATA ProcessData,
HANDLE Handle); HANDLE Handle);
VOID FASTCALL Win32CsrReleaseConsole(PCONSOLE_PROCESS_DATA ProcessData);
NTSTATUS NTAPI ConsoleNewProcess(PCSR_PROCESS SourceProcess, NTSTATUS NTAPI ConsoleNewProcess(PCSR_PROCESS SourceProcess,
PCSR_PROCESS TargetProcess); PCSR_PROCESS TargetProcess);
@ -160,7 +164,6 @@ NTSTATUS NTAPI ConsoleConnect(IN PCSR_PROCESS CsrProcess,
IN OUT PVOID ConnectionInfo, IN OUT PVOID ConnectionInfo,
IN OUT PULONG ConnectionInfoLength); IN OUT PULONG ConnectionInfoLength);
VOID NTAPI ConsoleDisconnect(PCSR_PROCESS Process); VOID NTAPI ConsoleDisconnect(PCSR_PROCESS Process);
VOID NTAPI Win32CsrReleaseConsole(PCSR_PROCESS Process);
/* lineinput.c */ /* lineinput.c */
CSR_API(SrvGetConsoleCommandHistoryLength); CSR_API(SrvGetConsoleCommandHistoryLength);

View file

@ -79,6 +79,85 @@ Win32CsrCloseHandleEntry(PCONSOLE_IO_HANDLE Entry)
/* FUNCTIONS *****************************************************************/ /* FUNCTIONS *****************************************************************/
NTSTATUS
FASTCALL
Win32CsrInheritHandlesTable(IN PCONSOLE_PROCESS_DATA SourceProcessData,
IN PCONSOLE_PROCESS_DATA TargetProcessData)
{
NTSTATUS Status = STATUS_SUCCESS;
ULONG i;
RtlEnterCriticalSection(&SourceProcessData->HandleTableLock);
/* Inherit a handles table only if there is no already */
if (TargetProcessData->HandleTable != NULL /* || TargetProcessData->HandleTableSize != 0 */)
{
Status = STATUS_UNSUCCESSFUL; /* STATUS_INVALID_PARAMETER */
goto Quit;
}
/* 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;
}
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 Win32CsrCreateHandleEntry).
*/
TargetProcessData->HandleTable[i] = SourceProcessData->HandleTable[i];
Win32CsrCreateHandleEntry(&TargetProcessData->HandleTable[i]);
}
}
Quit:
RtlLeaveCriticalSection(&SourceProcessData->HandleTableLock);
return Status;
}
VOID
FASTCALL
Win32CsrFreeHandlesTable(PCONSOLE_PROCESS_DATA ProcessData)
{
DPRINT1("Win32CsrFreeHandlesTable\n");
RtlEnterCriticalSection(&ProcessData->HandleTableLock);
if (ProcessData->HandleTable != NULL)
{
ULONG i;
/* Close all console handles and free the handle table memory */
for (i = 0; i < ProcessData->HandleTableSize; i++)
{
Win32CsrCloseHandleEntry(&ProcessData->HandleTable[i]);
}
RtlFreeHeap(ConSrvHeap, 0, ProcessData->HandleTable);
ProcessData->HandleTable = NULL;
}
ProcessData->HandleTableSize = 0;
RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
}
NTSTATUS NTSTATUS
FASTCALL FASTCALL
Win32CsrInsertObject(PCONSOLE_PROCESS_DATA ProcessData, Win32CsrInsertObject(PCONSOLE_PROCESS_DATA ProcessData,
@ -122,7 +201,8 @@ Win32CsrInsertObject(PCONSOLE_PROCESS_DATA ProcessData,
ProcessData->HandleTable[i].Inheritable = Inheritable; ProcessData->HandleTable[i].Inheritable = Inheritable;
ProcessData->HandleTable[i].ShareMode = ShareMode; ProcessData->HandleTable[i].ShareMode = ShareMode;
Win32CsrCreateHandleEntry(&ProcessData->HandleTable[i]); Win32CsrCreateHandleEntry(&ProcessData->HandleTable[i]);
*Handle = UlongToHandle((i << 2) | 0x3); *Handle = ULongToHandle((i << 2) | 0x3);
RtlLeaveCriticalSection(&ProcessData->HandleTableLock); RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
@ -202,9 +282,33 @@ Win32CsrUnlockObject(Object_t *Object)
Win32CsrUnlockConsole(Object->Console); Win32CsrUnlockConsole(Object->Console);
} }
VOID
FASTCALL
Win32CsrReleaseConsole(PCONSOLE_PROCESS_DATA ProcessData)
{
PCONSOLE Console;
DPRINT1("Win32CsrReleaseConsole\n");
/* Close all console handles and free the handle table memory */
Win32CsrFreeHandlesTable(ProcessData);
/* Detach process from console */
Console = ProcessData->Console;
if (Console != NULL)
{
DPRINT1("Win32CsrReleaseConsole - Console->ReferenceCount = %lu - We are going to decrement it !\n", Console->ReferenceCount);
ProcessData->Console = NULL;
EnterCriticalSection(&Console->Lock);
RemoveEntryList(&ProcessData->ConsoleLink);
Win32CsrUnlockConsole(Console);
//CloseHandle(ProcessData->ConsoleEvent);
//ProcessData->ConsoleEvent = NULL;
}
}
/** Remark: this function can be called by SrvAttachConsole (not yet implemented) **/
NTSTATUS NTSTATUS
NTAPI NTAPI
ConsoleNewProcess(PCSR_PROCESS SourceProcess, ConsoleNewProcess(PCSR_PROCESS SourceProcess,
@ -223,7 +327,6 @@ ConsoleNewProcess(PCSR_PROCESS SourceProcess,
**************************************************************************/ **************************************************************************/
PCONSOLE_PROCESS_DATA SourceProcessData, TargetProcessData; PCONSOLE_PROCESS_DATA SourceProcessData, TargetProcessData;
ULONG i;
DPRINT1("ConsoleNewProcess inside\n"); DPRINT1("ConsoleNewProcess inside\n");
DPRINT1("SourceProcess = 0x%p ; TargetProcess = 0x%p\n", SourceProcess, TargetProcess); DPRINT1("SourceProcess = 0x%p ; TargetProcess = 0x%p\n", SourceProcess, TargetProcess);
@ -243,14 +346,13 @@ ConsoleNewProcess(PCSR_PROCESS SourceProcess,
TargetProcessData->Process = TargetProcess; TargetProcessData->Process = TargetProcess;
TargetProcessData->ConsoleEvent = NULL; TargetProcessData->ConsoleEvent = NULL;
TargetProcessData->Console = TargetProcessData->ParentConsole = NULL; TargetProcessData->Console = TargetProcessData->ParentConsole = NULL;
// TargetProcessData->bInheritHandles = FALSE;
TargetProcessData->ConsoleApp = ((TargetProcess->Flags & CsrProcessIsConsoleApp) ? TRUE : FALSE); TargetProcessData->ConsoleApp = ((TargetProcess->Flags & CsrProcessIsConsoleApp) ? TRUE : FALSE);
// Testing // Testing
TargetProcessData->HandleTableSize = 0; TargetProcessData->HandleTableSize = 0;
TargetProcessData->HandleTable = NULL; TargetProcessData->HandleTable = NULL;
/* HACK */ RtlZeroMemory(&TargetProcessData->HandleTableLock, sizeof(RTL_CRITICAL_SECTION)); /**** HACK !!!! ****/ RtlZeroMemory(&TargetProcessData->HandleTableLock, sizeof(RTL_CRITICAL_SECTION));
RtlInitializeCriticalSection(&TargetProcessData->HandleTableLock); RtlInitializeCriticalSection(&TargetProcessData->HandleTableLock);
/* Do nothing if the source process is NULL */ /* Do nothing if the source process is NULL */
@ -267,51 +369,17 @@ ConsoleNewProcess(PCSR_PROCESS SourceProcess,
if ( SourceProcessData->Console != NULL && /* SourceProcessData->ConsoleApp */ if ( SourceProcessData->Console != NULL && /* SourceProcessData->ConsoleApp */
TargetProcessData->ConsoleApp ) TargetProcessData->ConsoleApp )
{ {
/* NTSTATUS Status;
if (TargetProcessData->HandleTableSize)
{
return STATUS_INVALID_PARAMETER;
}
*/
DPRINT1("ConsoleNewProcess - Copy the handle table (1)\n"); Status = Win32CsrInheritHandlesTable(SourceProcessData, TargetProcessData);
if (!NT_SUCCESS(Status))
{
return Status;
}
// FIXME: Do it before, or after the handles table inheritance ??
/* Temporary "inherit" the console from the parent */ /* Temporary "inherit" the console from the parent */
TargetProcessData->ParentConsole = SourceProcessData->Console; TargetProcessData->ParentConsole = SourceProcessData->Console;
RtlEnterCriticalSection(&SourceProcessData->HandleTableLock);
DPRINT1("ConsoleNewProcess - Copy the handle table (2)\n");
/* 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)
{
RtlLeaveCriticalSection(&SourceProcessData->HandleTableLock);
return STATUS_UNSUCCESSFUL;
}
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 Win32CsrCreateHandleEntry).
*/
TargetProcessData->HandleTable[i] = SourceProcessData->HandleTable[i];
Win32CsrCreateHandleEntry(&TargetProcessData->HandleTable[i]);
}
}
RtlLeaveCriticalSection(&SourceProcessData->HandleTableLock);
} }
else else
{ {
@ -335,7 +403,6 @@ ConsoleConnect(IN PCSR_PROCESS CsrProcess,
PCONSOLE_CONNECTION_INFO ConnectInfo = (PCONSOLE_CONNECTION_INFO)ConnectionInfo; PCONSOLE_CONNECTION_INFO ConnectInfo = (PCONSOLE_CONNECTION_INFO)ConnectionInfo;
PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrProcess); PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(CsrProcess);
BOOLEAN NewConsole = FALSE; BOOLEAN NewConsole = FALSE;
// PCONSOLE Console = NULL;
DPRINT1("ConsoleConnect\n"); DPRINT1("ConsoleConnect\n");
@ -354,21 +421,30 @@ ConsoleConnect(IN PCSR_PROCESS CsrProcess,
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
RtlEnterCriticalSection(&ProcessData->HandleTableLock);
/* If we don't have a console, then create a new one... */ /* If we don't have a console, then create a new one... */
if (!ConnectInfo->Console || if (!ConnectInfo->Console ||
ConnectInfo->Console != ProcessData->ParentConsole) ConnectInfo->Console != ProcessData->ParentConsole)
{ {
DPRINT1("ConsoleConnect - Allocate a new console\n"); DPRINT1("ConsoleConnect - Allocate a new console\n");
/*
* We are about to create a new console. However when ConsoleNewProcess
* 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.
*/
Win32CsrReleaseConsole(ProcessData);
/* Initialize a new Console owned by the Console Leader Process */ /* Initialize a new Console owned by the Console Leader Process */
NewConsole = TRUE; NewConsole = TRUE;
Status = CsrInitConsole(&ProcessData->Console, ConnectInfo->ShowCmd, CsrProcess); Status = CsrInitConsole(&ProcessData->Console, ConnectInfo->ShowCmd, CsrProcess);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
DPRINT1("Console initialization failed\n"); DPRINT1("Console initialization failed\n");
RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
return Status; return Status;
} }
} }
@ -381,42 +457,23 @@ ConsoleConnect(IN PCSR_PROCESS CsrProcess,
ProcessData->Console = ConnectInfo->Console; ProcessData->Console = ConnectInfo->Console;
} }
/* Add a reference count because the process is tied to the console */
_InterlockedIncrement(&ProcessData->Console->ReferenceCount);
/* Insert the process into the processes list of the console */ /* Insert the process into the processes list of the console */
InsertHeadList(&ProcessData->Console->ProcessList, &ProcessData->ConsoleLink); InsertHeadList(&ProcessData->Console->ProcessList, &ProcessData->ConsoleLink);
/* Return it to the caller */ /* Return it to the caller */
ConnectInfo->Console = ProcessData->Console; ConnectInfo->Console = ProcessData->Console;
/* Add a reference count because the process is tied to the console */ if (NewConsole)
_InterlockedIncrement(&ProcessData->Console->ReferenceCount);
if (NewConsole /* || !ProcessData->bInheritHandles */)
{ {
/*
* We've just created a new console. However when ConsoleNewProcess 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 our handles table and recreate a new one.
*/
ULONG i;
/* Close all console handles and free the handle table memory */
for (i = 0; i < ProcessData->HandleTableSize; i++)
{
Win32CsrCloseHandleEntry(&ProcessData->HandleTable[i]);
}
ProcessData->HandleTableSize = 0;
RtlFreeHeap(ConSrvHeap, 0, ProcessData->HandleTable);
ProcessData->HandleTable = NULL;
/* /*
* Create a new handle table - Insert the IO handles * Create a new handle table - Insert the IO handles
*/ */
RtlEnterCriticalSection(&ProcessData->HandleTableLock);
/* Insert the Input handle */ /* Insert the Input handle */
Status = Win32CsrInsertObject(ProcessData, Status = Win32CsrInsertObject(ProcessData,
&ConnectInfo->InputHandle, &ConnectInfo->InputHandle,
@ -427,9 +484,10 @@ ConsoleConnect(IN PCSR_PROCESS CsrProcess,
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
DPRINT1("Failed to insert the input handle\n"); DPRINT1("Failed to insert the input handle\n");
ConioDeleteConsole(ProcessData->Console);
ProcessData->Console = NULL;
RtlLeaveCriticalSection(&ProcessData->HandleTableLock); RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
Win32CsrReleaseConsole(ProcessData);
// ConioDeleteConsole(ProcessData->Console);
// ProcessData->Console = NULL;
return Status; return Status;
} }
@ -443,11 +501,12 @@ ConsoleConnect(IN PCSR_PROCESS CsrProcess,
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
DPRINT1("Failed to insert the output handle\n"); DPRINT1("Failed to insert the output handle\n");
ConioDeleteConsole(ProcessData->Console);
Win32CsrReleaseObject(ProcessData,
ConnectInfo->InputHandle);
ProcessData->Console = NULL;
RtlLeaveCriticalSection(&ProcessData->HandleTableLock); RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
Win32CsrReleaseConsole(ProcessData);
// Win32CsrReleaseObject(ProcessData,
// ConnectInfo->InputHandle);
// ConioDeleteConsole(ProcessData->Console);
// ProcessData->Console = NULL;
return Status; return Status;
} }
@ -461,15 +520,18 @@ ConsoleConnect(IN PCSR_PROCESS CsrProcess,
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
DPRINT1("Failed to insert the error handle\n"); DPRINT1("Failed to insert the error handle\n");
ConioDeleteConsole(ProcessData->Console);
Win32CsrReleaseObject(ProcessData,
ConnectInfo->OutputHandle);
Win32CsrReleaseObject(ProcessData,
ConnectInfo->InputHandle);
ProcessData->Console = NULL;
RtlLeaveCriticalSection(&ProcessData->HandleTableLock); RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
Win32CsrReleaseConsole(ProcessData);
// Win32CsrReleaseObject(ProcessData,
// ConnectInfo->OutputHandle);
// Win32CsrReleaseObject(ProcessData,
// ConnectInfo->InputHandle);
// ConioDeleteConsole(ProcessData->Console);
// ProcessData->Console = NULL;
return Status; return Status;
} }
RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
} }
/* Duplicate the Event */ /* Duplicate the Event */
@ -481,18 +543,18 @@ ConsoleConnect(IN PCSR_PROCESS CsrProcess,
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
DPRINT1("NtDuplicateObject() failed: %lu\n", Status); DPRINT1("NtDuplicateObject() failed: %lu\n", Status);
ConioDeleteConsole(ProcessData->Console); Win32CsrReleaseConsole(ProcessData);
if (NewConsole /* || !ProcessData->bInheritHandles */) // if (NewConsole)
{ // {
Win32CsrReleaseObject(ProcessData, // Win32CsrReleaseObject(ProcessData,
ConnectInfo->ErrorHandle); // ConnectInfo->ErrorHandle);
Win32CsrReleaseObject(ProcessData, // Win32CsrReleaseObject(ProcessData,
ConnectInfo->OutputHandle); // ConnectInfo->OutputHandle);
Win32CsrReleaseObject(ProcessData, // Win32CsrReleaseObject(ProcessData,
ConnectInfo->InputHandle); // ConnectInfo->InputHandle);
} // }
ProcessData->Console = NULL; // ConioDeleteConsole(ProcessData->Console); // FIXME: Just release the console ?
RtlLeaveCriticalSection(&ProcessData->HandleTableLock); // ProcessData->Console = NULL;
return Status; return Status;
} }
/* Input Wait Handle */ /* Input Wait Handle */
@ -500,49 +562,11 @@ ConsoleConnect(IN PCSR_PROCESS CsrProcess,
/* Set the Ctrl Dispatcher */ /* Set the Ctrl Dispatcher */
ProcessData->CtrlDispatcher = ConnectInfo->CtrlDispatcher; ProcessData->CtrlDispatcher = ConnectInfo->CtrlDispatcher;
DPRINT("CSRSS:CtrlDispatcher address: %x\n", ProcessData->CtrlDispatcher); DPRINT("CONSRV: CtrlDispatcher address: %x\n", ProcessData->CtrlDispatcher);
RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
VOID
WINAPI
Win32CsrReleaseConsole(PCSR_PROCESS Process)
{
PCONSOLE_PROCESS_DATA ProcessData = ConsoleGetPerProcessData(Process);
PCONSOLE Console;
ULONG i;
DPRINT1("Win32CsrReleaseConsole\n");
RtlEnterCriticalSection(&ProcessData->HandleTableLock);
/* Close all console handles and free the handle table memory */
for (i = 0; i < ProcessData->HandleTableSize; i++)
{
Win32CsrCloseHandleEntry(&ProcessData->HandleTable[i]);
}
ProcessData->HandleTableSize = 0;
RtlFreeHeap(ConSrvHeap, 0, ProcessData->HandleTable);
ProcessData->HandleTable = NULL;
/* Detach process from console */
Console = ProcessData->Console;
if (Console != NULL)
{
DPRINT1("Win32CsrReleaseConsole - Console->ReferenceCount = %lu - We are going to decrement it !\n", Console->ReferenceCount);
ProcessData->Console = NULL;
EnterCriticalSection(&Console->Lock);
RemoveEntryList(&ProcessData->ConsoleLink);
Win32CsrUnlockConsole(Console);
//CloseHandle(ProcessData->ConsoleEvent);
//ProcessData->ConsoleEvent = NULL;
}
RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
}
VOID VOID
WINAPI WINAPI
ConsoleDisconnect(PCSR_PROCESS Process) ConsoleDisconnect(PCSR_PROCESS Process)
@ -551,19 +575,14 @@ ConsoleDisconnect(PCSR_PROCESS Process)
/************************************************************************** /**************************************************************************
* This function is called whenever a new process (GUI or CUI) is destroyed. * This function is called whenever a new process (GUI or CUI) is destroyed.
*
* Only do something if the process is a CUI. <-- modify this behaviour if
* we deal with a GUI which
* quits and acquired a
* console...
**************************************************************************/ **************************************************************************/
DPRINT1("ConsoleDisconnect called\n"); DPRINT1("ConsoleDisconnect called\n");
// if (ProcessData->Console != NULL) if ( ProcessData->Console != NULL ||
if (ProcessData->ConsoleApp) ProcessData->HandleTable != NULL )
{ {
DPRINT1("ConsoleDisconnect - calling Win32CsrReleaseConsole\n"); DPRINT1("ConsoleDisconnect - calling Win32CsrReleaseConsole\n");
Win32CsrReleaseConsole(Process); Win32CsrReleaseConsole(ProcessData);
} }
RtlDeleteCriticalSection(&ProcessData->HandleTableLock); RtlDeleteCriticalSection(&ProcessData->HandleTableLock);

View file

@ -107,7 +107,7 @@ PCSR_API_ROUTINE ConsoleServerApiDispatchTable[ConsolepMaxApiNumber] =
// SrvRegisterConsoleIME, // SrvRegisterConsoleIME,
// SrvUnregisterConsoleIME, // SrvUnregisterConsoleIME,
// SrvGetConsoleLangId, // SrvGetConsoleLangId,
// SrvAttachConsole, SrvAttachConsole,
SrvGetConsoleSelectionInfo, SrvGetConsoleSelectionInfo,
SrvGetConsoleProcessList, SrvGetConsoleProcessList,
SrvGetConsoleHistory, SrvGetConsoleHistory,
@ -198,7 +198,7 @@ BOOLEAN ConsoleServerApiServerValidTable[ConsolepMaxApiNumber] =
// FALSE, // SrvRegisterConsoleIME, // FALSE, // SrvRegisterConsoleIME,
// FALSE, // SrvUnregisterConsoleIME, // FALSE, // SrvUnregisterConsoleIME,
// FALSE, // SrvGetConsoleLangId, // FALSE, // SrvGetConsoleLangId,
// FALSE, // SrvAttachConsole, FALSE, // SrvAttachConsole,
FALSE, // SrvGetConsoleSelectionInfo, FALSE, // SrvGetConsoleSelectionInfo,
FALSE, // SrvGetConsoleProcessList, FALSE, // SrvGetConsoleProcessList,
FALSE, // SrvGetConsoleHistory, FALSE, // SrvGetConsoleHistory,
@ -291,7 +291,7 @@ PCHAR ConsoleServerApiNameTable[ConsolepMaxApiNumber] =
// "RegisterConsoleIME", // "RegisterConsoleIME",
// "UnregisterConsoleIME", // "UnregisterConsoleIME",
// "GetConsoleLangId", // "GetConsoleLangId",
// "AttachConsole", "AttachConsole",
"GetConsoleSelectionInfo", "GetConsoleSelectionInfo",
"GetConsoleProcessList", "GetConsoleProcessList",
"GetConsoleHistory", "GetConsoleHistory",