[KERNEL32]

GetNextVDMCommand function:
- Avoid using deep nested levels of indentation.
- Fix the error check conditions (+ status value) for the CsrClientCallServer call to make it compatible with what windows' basesrv can return to us.

[BASESRV]
- Remove some useless "NTAPI" from functions.
- Factor out some code used for creating and destroying console records, and for the destruction of the pair of event handles.
- Use "IsListEmpty" when needed.
- Fix BaseSrvFillCommandInfo so that it returns the needed lengths (even if the user-given lengths are zero) and set the expected status error in case the buffer lenghts are too small (not STATUS_BUFFER_TOO_SMALL but STATUS_INVALID_PARAMETER because it's what kernel32 error check expects, for windows compat; see above).
- Fix initialization of new DOS records: no need to create a new one if there is one already free (status VDM_READY).
- Fix the loop that searches for a valid DOS record containing command information available as well as the conditions in which case our caller needs to wait in GetNextVDMCommand call.

NOTE: The internal state flags of the DOS records have normally nothing to do with the VDM state flags we report back to the user.

CORE-8247 CORE-9711 CORE-9773

svn path=/trunk/; revision=69201
This commit is contained in:
Hermès Bélusca-Maïto 2015-09-12 16:23:32 +00:00
parent 38b81a6049
commit 28b957e970
3 changed files with 599 additions and 501 deletions

View file

@ -1411,8 +1411,8 @@ BOOL
WINAPI WINAPI
GetNextVDMCommand(PVDM_COMMAND_INFO CommandData) GetNextVDMCommand(PVDM_COMMAND_INFO CommandData)
{ {
BOOL Success = FALSE;
NTSTATUS Status; NTSTATUS Status;
BOOL Result = FALSE;
BASE_API_MESSAGE ApiMessage; BASE_API_MESSAGE ApiMessage;
PBASE_GET_NEXT_VDM_COMMAND GetNextVdmCommand = &ApiMessage.Data.GetNextVDMCommandRequest; PBASE_GET_NEXT_VDM_COMMAND GetNextVdmCommand = &ApiMessage.Data.GetNextVDMCommandRequest;
PBASE_IS_FIRST_VDM IsFirstVdm = &ApiMessage.Data.IsFirstVDMRequest; PBASE_IS_FIRST_VDM IsFirstVdm = &ApiMessage.Data.IsFirstVDMRequest;
@ -1420,311 +1420,343 @@ GetNextVDMCommand(PVDM_COMMAND_INFO CommandData)
PCSR_CAPTURE_BUFFER CaptureBuffer = NULL; PCSR_CAPTURE_BUFFER CaptureBuffer = NULL;
ULONG NumStrings = 0; ULONG NumStrings = 0;
if (CommandData != NULL) /*
* Special case to test whether the VDM is the first one.
*/
if (CommandData == NULL)
{ {
if ((CommandData->VDMState == VDM_INC_REENTER_COUNT) /* Call CSRSS */
|| (CommandData->VDMState == VDM_DEC_REENTER_COUNT)) CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
NULL,
CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepIsFirstVDM),
sizeof(*IsFirstVdm));
if (!NT_SUCCESS(ApiMessage.Status))
{ {
/* Setup the input parameters */ BaseSetLastNTError(ApiMessage.Status);
SetReenterCount->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle; return FALSE;
SetReenterCount->fIncDec = CommandData->VDMState;
/* Call CSRSS */
Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
NULL,
CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepSetReenterCount),
sizeof(*SetReenterCount));
BaseSetLastNTError(Status);
Result = NT_SUCCESS(Status);
} }
else
{
/* Clear the structure */
ZeroMemory(GetNextVdmCommand, sizeof(*GetNextVdmCommand));
/* Setup the input parameters */ /* Return TRUE if this is the first VDM */
GetNextVdmCommand->iTask = CommandData->TaskId; return IsFirstVdm->FirstVDM;
GetNextVdmCommand->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
GetNextVdmCommand->CmdLen = CommandData->CmdLen;
GetNextVdmCommand->AppLen = CommandData->AppLen;
GetNextVdmCommand->PifLen = CommandData->PifLen;
GetNextVdmCommand->CurDirectoryLen = CommandData->CurDirectoryLen;
GetNextVdmCommand->EnvLen = CommandData->EnvLen;
GetNextVdmCommand->DesktopLen = CommandData->DesktopLen;
GetNextVdmCommand->TitleLen = CommandData->TitleLen;
GetNextVdmCommand->ReservedLen = CommandData->ReservedLen;
GetNextVdmCommand->VDMState = CommandData->VDMState;
/* Count the number of strings */
if (CommandData->CmdLen) NumStrings++;
if (CommandData->AppLen) NumStrings++;
if (CommandData->PifLen) NumStrings++;
if (CommandData->CurDirectoryLen) NumStrings++;
if (CommandData->EnvLen) NumStrings++;
if (CommandData->DesktopLen) NumStrings++;
if (CommandData->TitleLen) NumStrings++;
if (CommandData->ReservedLen) NumStrings++;
/* Allocate the capture buffer */
CaptureBuffer = CsrAllocateCaptureBuffer(NumStrings + 1,
GetNextVdmCommand->CmdLen
+ GetNextVdmCommand->AppLen
+ GetNextVdmCommand->PifLen
+ GetNextVdmCommand->CurDirectoryLen
+ GetNextVdmCommand->EnvLen
+ GetNextVdmCommand->DesktopLen
+ GetNextVdmCommand->TitleLen
+ GetNextVdmCommand->ReservedLen
+ sizeof(STARTUPINFOA));
if (CaptureBuffer == NULL)
{
BaseSetLastNTError(STATUS_NO_MEMORY);
goto Cleanup;
}
/* Allocate memory for the startup info */
CsrAllocateMessagePointer(CaptureBuffer,
sizeof(STARTUPINFOA),
(PVOID*)&GetNextVdmCommand->StartupInfo);
if (CommandData->CmdLen)
{
/* Allocate memory for the command line */
CsrAllocateMessagePointer(CaptureBuffer,
CommandData->CmdLen,
(PVOID*)&GetNextVdmCommand->CmdLine);
}
if (CommandData->AppLen)
{
/* Allocate memory for the application name */
CsrAllocateMessagePointer(CaptureBuffer,
CommandData->AppLen,
(PVOID*)&GetNextVdmCommand->AppName);
}
if (CommandData->PifLen)
{
/* Allocate memory for the PIF file name */
CsrAllocateMessagePointer(CaptureBuffer,
CommandData->PifLen,
(PVOID*)&GetNextVdmCommand->PifFile);
}
if (CommandData->CurDirectoryLen)
{
/* Allocate memory for the current directory */
CsrAllocateMessagePointer(CaptureBuffer,
CommandData->CurDirectoryLen,
(PVOID*)&GetNextVdmCommand->CurDirectory);
}
if (CommandData->EnvLen)
{
/* Allocate memory for the environment */
CsrAllocateMessagePointer(CaptureBuffer,
CommandData->EnvLen,
(PVOID*)&GetNextVdmCommand->Env);
}
if (CommandData->DesktopLen)
{
/* Allocate memory for the desktop name */
CsrAllocateMessagePointer(CaptureBuffer,
CommandData->DesktopLen,
(PVOID*)&GetNextVdmCommand->Desktop);
}
if (CommandData->TitleLen)
{
/* Allocate memory for the title */
CsrAllocateMessagePointer(CaptureBuffer,
CommandData->TitleLen,
(PVOID*)&GetNextVdmCommand->Title);
}
if (CommandData->ReservedLen)
{
/* Allocate memory for the reserved parameter */
CsrAllocateMessagePointer(CaptureBuffer,
CommandData->ReservedLen,
(PVOID*)&GetNextVdmCommand->Reserved);
}
do
{
/* Call CSRSS */
Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
CaptureBuffer,
CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepGetNextVDMCommand),
sizeof(*GetNextVdmCommand));
if (!NT_SUCCESS(Status))
{
/* Store the correct lengths */
CommandData->CmdLen = GetNextVdmCommand->CmdLen;
CommandData->AppLen = GetNextVdmCommand->AppLen;
CommandData->PifLen = GetNextVdmCommand->PifLen;
CommandData->CurDirectoryLen = GetNextVdmCommand->CurDirectoryLen;
CommandData->EnvLen = GetNextVdmCommand->EnvLen;
CommandData->DesktopLen = GetNextVdmCommand->DesktopLen;
CommandData->TitleLen = GetNextVdmCommand->TitleLen;
CommandData->ReservedLen = GetNextVdmCommand->ReservedLen;
BaseSetLastNTError(Status);
goto Cleanup;
}
/* Did we receive an event handle? */
if (GetNextVdmCommand->WaitObjectForVDM != NULL)
{
/* Wait for the event to become signaled and try again */
Status = NtWaitForSingleObject(GetNextVdmCommand->WaitObjectForVDM,
FALSE,
NULL);
if (!NT_SUCCESS(Status))
{
BaseSetLastNTError(Status);
goto Cleanup;
}
/* Set the retry flag and clear the exit code */
GetNextVdmCommand->VDMState |= VDM_FLAG_RETRY;
GetNextVdmCommand->ExitCode = 0;
}
}
while (GetNextVdmCommand->WaitObjectForVDM != NULL);
/* Write back the standard handles */
CommandData->StdIn = GetNextVdmCommand->StdIn;
CommandData->StdOut = GetNextVdmCommand->StdOut;
CommandData->StdErr = GetNextVdmCommand->StdErr;
/* Write back the startup info */
RtlMoveMemory(&CommandData->StartupInfo,
GetNextVdmCommand->StartupInfo,
sizeof(STARTUPINFOA));
if (CommandData->CmdLen)
{
/* Write back the command line */
RtlMoveMemory(CommandData->CmdLine,
GetNextVdmCommand->CmdLine,
GetNextVdmCommand->CmdLen);
/* Set the actual length */
CommandData->CmdLen = GetNextVdmCommand->CmdLen;
}
if (CommandData->AppLen)
{
/* Write back the application name */
RtlMoveMemory(CommandData->AppName,
GetNextVdmCommand->AppName,
GetNextVdmCommand->AppLen);
/* Set the actual length */
CommandData->AppLen = GetNextVdmCommand->AppLen;
}
if (CommandData->PifLen)
{
/* Write back the PIF file name */
RtlMoveMemory(CommandData->PifFile,
GetNextVdmCommand->PifFile,
GetNextVdmCommand->PifLen);
/* Set the actual length */
CommandData->PifLen = GetNextVdmCommand->PifLen;
}
if (CommandData->CurDirectoryLen)
{
/* Write back the current directory */
RtlMoveMemory(CommandData->CurDirectory,
GetNextVdmCommand->CurDirectory,
GetNextVdmCommand->CurDirectoryLen);
/* Set the actual length */
CommandData->CurDirectoryLen = GetNextVdmCommand->CurDirectoryLen;
}
if (CommandData->EnvLen)
{
/* Write back the environment */
RtlMoveMemory(CommandData->Env,
GetNextVdmCommand->Env,
GetNextVdmCommand->EnvLen);
/* Set the actual length */
CommandData->EnvLen = GetNextVdmCommand->EnvLen;
}
if (CommandData->DesktopLen)
{
/* Write back the desktop name */
RtlMoveMemory(CommandData->Desktop,
GetNextVdmCommand->Desktop,
GetNextVdmCommand->DesktopLen);
/* Set the actual length */
CommandData->DesktopLen = GetNextVdmCommand->DesktopLen;
}
if (CommandData->TitleLen)
{
/* Write back the title */
RtlMoveMemory(CommandData->Title,
GetNextVdmCommand->Title,
GetNextVdmCommand->TitleLen);
/* Set the actual length */
CommandData->TitleLen = GetNextVdmCommand->TitleLen;
}
if (CommandData->ReservedLen)
{
/* Write back the reserved parameter */
RtlMoveMemory(CommandData->Reserved,
GetNextVdmCommand->Reserved,
GetNextVdmCommand->ReservedLen);
/* Set the actual length */
CommandData->ReservedLen = GetNextVdmCommand->ReservedLen;
}
/* Write the remaining output parameters */
CommandData->TaskId = GetNextVdmCommand->iTask;
CommandData->CreationFlags = GetNextVdmCommand->dwCreationFlags;
CommandData->CodePage = GetNextVdmCommand->CodePage;
CommandData->ExitCode = GetNextVdmCommand->ExitCode;
CommandData->CurrentDrive = GetNextVdmCommand->CurrentDrive;
CommandData->VDMState = GetNextVdmCommand->VDMState;
CommandData->ComingFromBat = GetNextVdmCommand->fComingFromBat;
/* It was successful */
Result = TRUE;
}
} }
else
/* CommandData != NULL */
/*
* Special case to increment or decrement the reentrancy count.
*/
if ((CommandData->VDMState == VDM_INC_REENTER_COUNT) ||
(CommandData->VDMState == VDM_DEC_REENTER_COUNT))
{
/* Setup the input parameters */
SetReenterCount->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
SetReenterCount->fIncDec = CommandData->VDMState;
/* Call CSRSS */
CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
NULL,
CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepSetReenterCount),
sizeof(*SetReenterCount));
if (!NT_SUCCESS(ApiMessage.Status))
{
BaseSetLastNTError(ApiMessage.Status);
return FALSE;
}
return TRUE;
}
/*
* TODO!
* Special case to retrieve or set WOW information.
*/
// TODO: if CommandData->VDMState & (VDM_LIST_WOW_PROCESSES | VDM_LIST_WOW_TASKS | VDM_ADD_WOW_TASK)
// then call BasepGetNextVDMCommand in a simpler way!
/*
* Regular case.
*/
/* Clear the structure */
RtlZeroMemory(GetNextVdmCommand, sizeof(*GetNextVdmCommand));
/* Setup the input parameters */
GetNextVdmCommand->iTask = CommandData->TaskId;
GetNextVdmCommand->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
GetNextVdmCommand->CmdLen = CommandData->CmdLen;
GetNextVdmCommand->AppLen = CommandData->AppLen;
GetNextVdmCommand->PifLen = CommandData->PifLen;
GetNextVdmCommand->CurDirectoryLen = CommandData->CurDirectoryLen;
GetNextVdmCommand->EnvLen = CommandData->EnvLen;
GetNextVdmCommand->DesktopLen = CommandData->DesktopLen;
GetNextVdmCommand->TitleLen = CommandData->TitleLen;
GetNextVdmCommand->ReservedLen = CommandData->ReservedLen;
GetNextVdmCommand->VDMState = CommandData->VDMState;
/* Count the number of strings */
if (CommandData->CmdLen) NumStrings++;
if (CommandData->AppLen) NumStrings++;
if (CommandData->PifLen) NumStrings++;
if (CommandData->CurDirectoryLen) NumStrings++;
if (CommandData->EnvLen) NumStrings++;
if (CommandData->DesktopLen) NumStrings++;
if (CommandData->TitleLen) NumStrings++;
if (CommandData->ReservedLen) NumStrings++;
/* Allocate the capture buffer */
CaptureBuffer = CsrAllocateCaptureBuffer(NumStrings + 1,
GetNextVdmCommand->CmdLen
+ GetNextVdmCommand->AppLen
+ GetNextVdmCommand->PifLen
+ GetNextVdmCommand->CurDirectoryLen
+ GetNextVdmCommand->EnvLen
+ GetNextVdmCommand->DesktopLen
+ GetNextVdmCommand->TitleLen
+ GetNextVdmCommand->ReservedLen
+ sizeof(*GetNextVdmCommand->StartupInfo));
if (CaptureBuffer == NULL)
{
BaseSetLastNTError(STATUS_NO_MEMORY);
goto Cleanup;
}
/* Capture the data */
CsrAllocateMessagePointer(CaptureBuffer,
sizeof(*GetNextVdmCommand->StartupInfo),
(PVOID*)&GetNextVdmCommand->StartupInfo);
if (CommandData->CmdLen)
{
CsrAllocateMessagePointer(CaptureBuffer,
CommandData->CmdLen,
(PVOID*)&GetNextVdmCommand->CmdLine);
}
if (CommandData->AppLen)
{
CsrAllocateMessagePointer(CaptureBuffer,
CommandData->AppLen,
(PVOID*)&GetNextVdmCommand->AppName);
}
if (CommandData->PifLen)
{
CsrAllocateMessagePointer(CaptureBuffer,
CommandData->PifLen,
(PVOID*)&GetNextVdmCommand->PifFile);
}
if (CommandData->CurDirectoryLen)
{
CsrAllocateMessagePointer(CaptureBuffer,
CommandData->CurDirectoryLen,
(PVOID*)&GetNextVdmCommand->CurDirectory);
}
if (CommandData->EnvLen)
{
CsrAllocateMessagePointer(CaptureBuffer,
CommandData->EnvLen,
(PVOID*)&GetNextVdmCommand->Env);
}
if (CommandData->DesktopLen)
{
CsrAllocateMessagePointer(CaptureBuffer,
CommandData->DesktopLen,
(PVOID*)&GetNextVdmCommand->Desktop);
}
if (CommandData->TitleLen)
{
CsrAllocateMessagePointer(CaptureBuffer,
CommandData->TitleLen,
(PVOID*)&GetNextVdmCommand->Title);
}
if (CommandData->ReservedLen)
{
CsrAllocateMessagePointer(CaptureBuffer,
CommandData->ReservedLen,
(PVOID*)&GetNextVdmCommand->Reserved);
}
while (TRUE)
{ {
/* Call CSRSS */ /* Call CSRSS */
Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage, Status = CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage,
NULL, CaptureBuffer,
CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepIsFirstVDM), CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepGetNextVDMCommand),
sizeof(*IsFirstVdm)); sizeof(*GetNextVdmCommand));
if (!NT_SUCCESS(Status))
/* Exit the waiting loop if we did not receive any event handle */
if (GetNextVdmCommand->WaitObjectForVDM == NULL)
break;
/* Wait for the event to become signaled and try again */
Status = NtWaitForSingleObject(GetNextVdmCommand->WaitObjectForVDM,
FALSE, NULL);
if (Status != STATUS_SUCCESS)
{ {
/* Fail if we timed out, or if some other error happened */
BaseSetLastNTError(Status); BaseSetLastNTError(Status);
goto Cleanup; goto Cleanup;
} }
/* Return TRUE if this is the first VDM */ /* Set the retry flag, clear the exit code, and retry a query */
Result = IsFirstVdm->FirstVDM; GetNextVdmCommand->VDMState |= VDM_FLAG_RETRY;
GetNextVdmCommand->ExitCode = 0;
} }
if (!NT_SUCCESS(Status))
{
if (Status == STATUS_INVALID_PARAMETER)
{
/*
* One of the buffer lengths was less than required. Store the correct ones.
* Note that the status code is not STATUS_BUFFER_TOO_SMALL as one would expect,
* in order to keep compatibility with Windows 2003 BASESRV.DLL.
*/
CommandData->CmdLen = GetNextVdmCommand->CmdLen;
CommandData->AppLen = GetNextVdmCommand->AppLen;
CommandData->PifLen = GetNextVdmCommand->PifLen;
CommandData->CurDirectoryLen = GetNextVdmCommand->CurDirectoryLen;
CommandData->EnvLen = GetNextVdmCommand->EnvLen;
CommandData->DesktopLen = GetNextVdmCommand->DesktopLen;
CommandData->TitleLen = GetNextVdmCommand->TitleLen;
CommandData->ReservedLen = GetNextVdmCommand->ReservedLen;
}
else
{
/* Any other failure */
CommandData->CmdLen = 0;
CommandData->AppLen = 0;
CommandData->PifLen = 0;
CommandData->CurDirectoryLen = 0;
CommandData->EnvLen = 0;
CommandData->DesktopLen = 0;
CommandData->TitleLen = 0;
CommandData->ReservedLen = 0;
}
BaseSetLastNTError(Status);
goto Cleanup;
}
/* Write back the standard handles */
CommandData->StdIn = GetNextVdmCommand->StdIn;
CommandData->StdOut = GetNextVdmCommand->StdOut;
CommandData->StdErr = GetNextVdmCommand->StdErr;
/* Write back the startup info */
RtlMoveMemory(&CommandData->StartupInfo,
GetNextVdmCommand->StartupInfo,
sizeof(*GetNextVdmCommand->StartupInfo));
if (CommandData->CmdLen)
{
/* Write back the command line */
RtlMoveMemory(CommandData->CmdLine,
GetNextVdmCommand->CmdLine,
GetNextVdmCommand->CmdLen);
/* Set the actual length */
CommandData->CmdLen = GetNextVdmCommand->CmdLen;
}
if (CommandData->AppLen)
{
/* Write back the application name */
RtlMoveMemory(CommandData->AppName,
GetNextVdmCommand->AppName,
GetNextVdmCommand->AppLen);
/* Set the actual length */
CommandData->AppLen = GetNextVdmCommand->AppLen;
}
if (CommandData->PifLen)
{
/* Write back the PIF file name */
RtlMoveMemory(CommandData->PifFile,
GetNextVdmCommand->PifFile,
GetNextVdmCommand->PifLen);
/* Set the actual length */
CommandData->PifLen = GetNextVdmCommand->PifLen;
}
if (CommandData->CurDirectoryLen)
{
/* Write back the current directory */
RtlMoveMemory(CommandData->CurDirectory,
GetNextVdmCommand->CurDirectory,
GetNextVdmCommand->CurDirectoryLen);
/* Set the actual length */
CommandData->CurDirectoryLen = GetNextVdmCommand->CurDirectoryLen;
}
if (CommandData->EnvLen)
{
/* Write back the environment */
RtlMoveMemory(CommandData->Env,
GetNextVdmCommand->Env,
GetNextVdmCommand->EnvLen);
/* Set the actual length */
CommandData->EnvLen = GetNextVdmCommand->EnvLen;
}
if (CommandData->DesktopLen)
{
/* Write back the desktop name */
RtlMoveMemory(CommandData->Desktop,
GetNextVdmCommand->Desktop,
GetNextVdmCommand->DesktopLen);
/* Set the actual length */
CommandData->DesktopLen = GetNextVdmCommand->DesktopLen;
}
if (CommandData->TitleLen)
{
/* Write back the title */
RtlMoveMemory(CommandData->Title,
GetNextVdmCommand->Title,
GetNextVdmCommand->TitleLen);
/* Set the actual length */
CommandData->TitleLen = GetNextVdmCommand->TitleLen;
}
if (CommandData->ReservedLen)
{
/* Write back the reserved parameter */
RtlMoveMemory(CommandData->Reserved,
GetNextVdmCommand->Reserved,
GetNextVdmCommand->ReservedLen);
/* Set the actual length */
CommandData->ReservedLen = GetNextVdmCommand->ReservedLen;
}
/* Write the remaining output parameters */
CommandData->TaskId = GetNextVdmCommand->iTask;
CommandData->CreationFlags = GetNextVdmCommand->dwCreationFlags;
CommandData->CodePage = GetNextVdmCommand->CodePage;
CommandData->ExitCode = GetNextVdmCommand->ExitCode;
CommandData->CurrentDrive = GetNextVdmCommand->CurrentDrive;
CommandData->VDMState = GetNextVdmCommand->VDMState;
CommandData->ComingFromBat = GetNextVdmCommand->fComingFromBat;
/* It was successful */
Success = TRUE;
Cleanup: Cleanup:
if (CaptureBuffer != NULL) CsrFreeCaptureBuffer(CaptureBuffer); if (CaptureBuffer != NULL) CsrFreeCaptureBuffer(CaptureBuffer);
return Result; return Success;
} }

View file

@ -22,9 +22,31 @@ LIST_ENTRY VDMConsoleListHead;
RTL_CRITICAL_SECTION DosCriticalSection; RTL_CRITICAL_SECTION DosCriticalSection;
RTL_CRITICAL_SECTION WowCriticalSection; RTL_CRITICAL_SECTION WowCriticalSection;
/* FUNCTIONS ******************************************************************/ /* HELPER FUNCTIONS ***********************************************************/
NTSTATUS NTAPI BaseSrvGetConsoleRecord(HANDLE ConsoleHandle, PVDM_CONSOLE_RECORD *Record) PVDM_CONSOLE_RECORD BaseSrvCreateConsoleRecord(VOID)
{
PVDM_CONSOLE_RECORD ConsoleRecord;
ConsoleRecord = RtlAllocateHeap(BaseSrvHeap, HEAP_ZERO_MEMORY,
sizeof(VDM_CONSOLE_RECORD));
if (ConsoleRecord == NULL)
return NULL;
/* Initialize the console record */
ConsoleRecord->ConsoleHandle = NULL;
ConsoleRecord->ProcessHandle = NULL;
ConsoleRecord->ServerEvent = ConsoleRecord->ClientEvent = NULL;
ConsoleRecord->ReenterCount = 0;
ConsoleRecord->CurrentDirs = NULL;
ConsoleRecord->CurDirsLength = 0;
ConsoleRecord->SessionId = 0;
InitializeListHead(&ConsoleRecord->DosListHead);
return ConsoleRecord;
}
NTSTATUS BaseSrvGetConsoleRecord(HANDLE ConsoleHandle, PVDM_CONSOLE_RECORD *Record)
{ {
PLIST_ENTRY i; PLIST_ENTRY i;
PVDM_CONSOLE_RECORD CurrentRecord = NULL; PVDM_CONSOLE_RECORD CurrentRecord = NULL;
@ -46,7 +68,31 @@ NTSTATUS NTAPI BaseSrvGetConsoleRecord(HANDLE ConsoleHandle, PVDM_CONSOLE_RECORD
return CurrentRecord ? STATUS_SUCCESS : STATUS_NOT_FOUND; return CurrentRecord ? STATUS_SUCCESS : STATUS_NOT_FOUND;
} }
NTSTATUS NTAPI GetConsoleRecordBySessionId(ULONG TaskId, PVDM_CONSOLE_RECORD *Record) VOID BaseSrvDestroyConsoleRecord(PVDM_CONSOLE_RECORD ConsoleRecord)
{
if (ConsoleRecord->CurrentDirs != NULL)
{
/* Free the current directories */
RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord->CurrentDirs);
ConsoleRecord->CurrentDirs = NULL;
ConsoleRecord->CurDirsLength = 0;
}
/* Close the process handle */
if (ConsoleRecord->ProcessHandle)
NtClose(ConsoleRecord->ProcessHandle);
/* Close the event handle */
if (ConsoleRecord->ServerEvent)
NtClose(ConsoleRecord->ServerEvent);
/* Remove the console record */
// RemoveEntryList(&ConsoleRecord->Entry);
RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord);
}
NTSTATUS GetConsoleRecordBySessionId(ULONG TaskId, PVDM_CONSOLE_RECORD *Record)
{ {
PLIST_ENTRY i; PLIST_ENTRY i;
PVDM_CONSOLE_RECORD CurrentRecord = NULL; PVDM_CONSOLE_RECORD CurrentRecord = NULL;
@ -65,7 +111,7 @@ NTSTATUS NTAPI GetConsoleRecordBySessionId(ULONG TaskId, PVDM_CONSOLE_RECORD *Re
return CurrentRecord ? STATUS_SUCCESS : STATUS_NOT_FOUND; return CurrentRecord ? STATUS_SUCCESS : STATUS_NOT_FOUND;
} }
ULONG NTAPI GetNextDosSesId(VOID) ULONG GetNextDosSesId(VOID)
{ {
ULONG SessionId; ULONG SessionId;
PLIST_ENTRY i; PLIST_ENTRY i;
@ -94,7 +140,7 @@ ULONG NTAPI GetNextDosSesId(VOID)
return SessionId; return SessionId;
} }
BOOLEAN NTAPI BaseSrvIsVdmAllowed(VOID) BOOLEAN BaseSrvIsVdmAllowed(VOID)
{ {
NTSTATUS Status; NTSTATUS Status;
BOOLEAN VdmAllowed = TRUE; BOOLEAN VdmAllowed = TRUE;
@ -191,7 +237,7 @@ BOOLEAN NTAPI BaseSrvIsVdmAllowed(VOID)
return VdmAllowed; return VdmAllowed;
} }
NTSTATUS NTAPI BaseSrvCreatePairWaitHandles(PHANDLE ServerEvent, PHANDLE ClientEvent) NTSTATUS BaseSrvCreatePairWaitHandles(PHANDLE ServerEvent, PHANDLE ClientEvent)
{ {
NTSTATUS Status; NTSTATUS Status;
@ -212,7 +258,27 @@ NTSTATUS NTAPI BaseSrvCreatePairWaitHandles(PHANDLE ServerEvent, PHANDLE ClientE
return Status; return Status;
} }
VOID NTAPI BaseSrvFreeVDMInfo(PVDM_COMMAND_INFO CommandInfo) VOID BaseSrvDestroyPairWaitHandles(HANDLE ServerEvent, HANDLE ClientEvent)
{
if (ServerEvent) NtClose(ServerEvent);
if (ClientEvent)
{
/* Close the remote handle */
NtDuplicateObject(CsrGetClientThread()->Process->ProcessHandle,
ClientEvent,
NULL,
NULL,
0,
0,
DUPLICATE_CLOSE_SOURCE);
}
}
/* WOW SUPPORT FUNCTIONS ******************************************************/
/* DOS SUPPORT FUNCTIONS ******************************************************/
VOID BaseSrvFreeVDMInfo(PVDM_COMMAND_INFO CommandInfo)
{ {
/* Free the allocated structure members */ /* Free the allocated structure members */
if (CommandInfo->CmdLine != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->CmdLine); if (CommandInfo->CmdLine != NULL) RtlFreeHeap(BaseSrvHeap, 0, CommandInfo->CmdLine);
@ -228,9 +294,7 @@ VOID NTAPI BaseSrvFreeVDMInfo(PVDM_COMMAND_INFO CommandInfo)
RtlFreeHeap(BaseSrvHeap, 0, CommandInfo); RtlFreeHeap(BaseSrvHeap, 0, CommandInfo);
} }
VOID VOID BaseSrvCleanupVDMResources(IN PCSR_PROCESS CsrProcess)
NTAPI
BaseSrvCleanupVDMResources(IN PCSR_PROCESS CsrProcess)
{ {
ULONG ProcessId = HandleToUlong(CsrProcess->ClientId.UniqueProcess); ULONG ProcessId = HandleToUlong(CsrProcess->ClientId.UniqueProcess);
PVDM_CONSOLE_RECORD ConsoleRecord = NULL; PVDM_CONSOLE_RECORD ConsoleRecord = NULL;
@ -241,22 +305,33 @@ BaseSrvCleanupVDMResources(IN PCSR_PROCESS CsrProcess)
RtlEnterCriticalSection(&DosCriticalSection); RtlEnterCriticalSection(&DosCriticalSection);
/* Search for a record that has the same process handle */ /* Search for a record that has the same process handle */
for (i = VDMConsoleListHead.Flink; i != &VDMConsoleListHead; i = i->Flink) i = VDMConsoleListHead.Flink;
while (i != &VDMConsoleListHead)
{ {
ConsoleRecord = CONTAINING_RECORD(i, VDM_CONSOLE_RECORD, Entry); ConsoleRecord = CONTAINING_RECORD(i, VDM_CONSOLE_RECORD, Entry);
i = i->Flink;
if (ConsoleRecord->ProcessId == ProcessId) if (ConsoleRecord->ProcessId == ProcessId)
{ {
if (ConsoleRecord->ServerEvent)
{
NtClose(ConsoleRecord->ServerEvent);
ConsoleRecord->ServerEvent = NULL;
}
/* Cleanup the DOS records */ /* Cleanup the DOS records */
while (ConsoleRecord->DosListHead.Flink != &ConsoleRecord->DosListHead) while (!IsListEmpty(&ConsoleRecord->DosListHead))
{ {
DosRecord = CONTAINING_RECORD(ConsoleRecord->DosListHead.Flink, DosRecord = CONTAINING_RECORD(ConsoleRecord->DosListHead.Flink,
VDM_DOS_RECORD, VDM_DOS_RECORD, Entry);
Entry);
/* Set the event and close it */ /* Set the event and close it */
NtSetEvent(DosRecord->ServerEvent, NULL); if (DosRecord->ServerEvent)
NtClose(DosRecord->ServerEvent); {
NtSetEvent(DosRecord->ServerEvent, NULL);
NtClose(DosRecord->ServerEvent);
DosRecord->ServerEvent = NULL;
}
/* Remove the DOS entry */ /* Remove the DOS entry */
if (DosRecord->CommandInfo) BaseSrvFreeVDMInfo(DosRecord->CommandInfo); if (DosRecord->CommandInfo) BaseSrvFreeVDMInfo(DosRecord->CommandInfo);
@ -264,24 +339,9 @@ BaseSrvCleanupVDMResources(IN PCSR_PROCESS CsrProcess)
RtlFreeHeap(BaseSrvHeap, 0, DosRecord); RtlFreeHeap(BaseSrvHeap, 0, DosRecord);
} }
if (ConsoleRecord->CurrentDirs != NULL)
{
/* Free the current directories */
RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord->CurrentDirs);
ConsoleRecord->CurrentDirs = NULL;
ConsoleRecord->CurDirsLength = 0;
}
/* Close the process handle */
if (ConsoleRecord->ProcessHandle) NtClose(ConsoleRecord->ProcessHandle);
/* Close the event handle */
if (ConsoleRecord->ServerEvent) NtClose(ConsoleRecord->ServerEvent);
/* Remove the console record */ /* Remove the console record */
i = i->Blink;
RemoveEntryList(&ConsoleRecord->Entry); RemoveEntryList(&ConsoleRecord->Entry);
RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord); BaseSrvDestroyConsoleRecord(ConsoleRecord);
} }
} }
@ -289,7 +349,7 @@ BaseSrvCleanupVDMResources(IN PCSR_PROCESS CsrProcess)
RtlLeaveCriticalSection(&DosCriticalSection); RtlLeaveCriticalSection(&DosCriticalSection);
} }
BOOLEAN NTAPI BaseSrvCopyCommand(PBASE_CHECK_VDM CheckVdmRequest, PVDM_DOS_RECORD DosRecord) BOOLEAN BaseSrvCopyCommand(PBASE_CHECK_VDM CheckVdmRequest, PVDM_DOS_RECORD DosRecord)
{ {
BOOLEAN Success = FALSE; BOOLEAN Success = FALSE;
PVDM_COMMAND_INFO CommandInfo = NULL; PVDM_COMMAND_INFO CommandInfo = NULL;
@ -436,8 +496,8 @@ Cleanup:
return Success; return Success;
} }
NTSTATUS NTAPI BaseSrvFillCommandInfo(PVDM_COMMAND_INFO CommandInfo, NTSTATUS BaseSrvFillCommandInfo(PVDM_COMMAND_INFO CommandInfo,
PBASE_GET_NEXT_VDM_COMMAND Message) PBASE_GET_NEXT_VDM_COMMAND Message)
{ {
NTSTATUS Status = STATUS_SUCCESS; NTSTATUS Status = STATUS_SUCCESS;
@ -453,116 +513,84 @@ NTSTATUS NTAPI BaseSrvFillCommandInfo(PVDM_COMMAND_INFO CommandInfo,
Message->VDMState = CommandInfo->VDMState; Message->VDMState = CommandInfo->VDMState;
Message->fComingFromBat = CommandInfo->ComingFromBat; Message->fComingFromBat = CommandInfo->ComingFromBat;
if (CommandInfo->CmdLen && Message->CmdLen) if (Message->CmdLen >= CommandInfo->CmdLen)
{ {
if (Message->CmdLen >= CommandInfo->CmdLen) /* Copy the command line */
{ RtlMoveMemory(Message->CmdLine, CommandInfo->CmdLine, CommandInfo->CmdLen);
/* Copy the command line */
RtlMoveMemory(Message->CmdLine, CommandInfo->CmdLine, CommandInfo->CmdLen);
}
else Status = STATUS_BUFFER_TOO_SMALL;
Message->CmdLen = CommandInfo->CmdLen;
} }
else Status = STATUS_INVALID_PARAMETER;
Message->CmdLen = CommandInfo->CmdLen;
if (CommandInfo->AppLen && Message->AppLen) if (Message->AppLen >= CommandInfo->AppLen)
{ {
if (Message->AppLen >= CommandInfo->AppLen) /* Copy the application name */
{ RtlMoveMemory(Message->AppName, CommandInfo->AppName, CommandInfo->AppLen);
/* Copy the application name */
RtlMoveMemory(Message->AppName, CommandInfo->AppName, CommandInfo->AppLen);
}
else Status = STATUS_BUFFER_TOO_SMALL;
Message->AppLen = CommandInfo->AppLen;
} }
else Status = STATUS_INVALID_PARAMETER;
Message->AppLen = CommandInfo->AppLen;
if (CommandInfo->PifLen && Message->PifLen) if (Message->PifLen >= CommandInfo->PifLen)
{ {
if (Message->PifLen >= CommandInfo->PifLen) /* Copy the PIF file name */
{ RtlMoveMemory(Message->PifFile, CommandInfo->PifFile, CommandInfo->PifLen);
/* Copy the PIF file name */
RtlMoveMemory(Message->PifFile, CommandInfo->PifFile, CommandInfo->PifLen);
}
else Status = STATUS_BUFFER_TOO_SMALL;
Message->PifLen = CommandInfo->PifLen;
} }
else Status = STATUS_INVALID_PARAMETER;
Message->PifLen = CommandInfo->PifLen;
if (CommandInfo->CurDirectoryLen && Message->CurDirectoryLen) if (Message->CurDirectoryLen >= CommandInfo->CurDirectoryLen)
{ {
if (Message->CurDirectoryLen >= CommandInfo->CurDirectoryLen) /* Copy the current directory */
{ RtlMoveMemory(Message->CurDirectory, CommandInfo->CurDirectory, CommandInfo->CurDirectoryLen);
/* Copy the current directory */
RtlMoveMemory(Message->CurDirectory, CommandInfo->CurDirectory, CommandInfo->CurDirectoryLen);
}
else Status = STATUS_BUFFER_TOO_SMALL;
Message->CurDirectoryLen = CommandInfo->CurDirectoryLen;
} }
else Status = STATUS_INVALID_PARAMETER;
Message->CurDirectoryLen = CommandInfo->CurDirectoryLen;
if (CommandInfo->EnvLen && Message->EnvLen) if (Message->EnvLen >= CommandInfo->EnvLen)
{ {
if (Message->EnvLen >= CommandInfo->EnvLen) /* Copy the environment */
{ RtlMoveMemory(Message->Env, CommandInfo->Env, CommandInfo->EnvLen);
/* Copy the environment */
RtlMoveMemory(Message->Env, CommandInfo->Env, CommandInfo->EnvLen);
}
else Status = STATUS_BUFFER_TOO_SMALL;
Message->EnvLen = CommandInfo->EnvLen;
} }
else Status = STATUS_INVALID_PARAMETER;
Message->EnvLen = CommandInfo->EnvLen;
/* Copy the startup info */ /* Copy the startup info */
RtlMoveMemory(Message->StartupInfo, RtlMoveMemory(Message->StartupInfo,
&CommandInfo->StartupInfo, &CommandInfo->StartupInfo,
sizeof(STARTUPINFOA)); sizeof(STARTUPINFOA));
if (CommandInfo->DesktopLen && Message->DesktopLen) if (Message->DesktopLen >= CommandInfo->DesktopLen)
{ {
if (Message->DesktopLen >= CommandInfo->DesktopLen) /* Copy the desktop name */
{ RtlMoveMemory(Message->Desktop, CommandInfo->Desktop, CommandInfo->DesktopLen);
/* Copy the desktop name */
RtlMoveMemory(Message->Desktop, CommandInfo->Desktop, CommandInfo->DesktopLen);
}
else Status = STATUS_BUFFER_TOO_SMALL;
Message->DesktopLen = CommandInfo->DesktopLen;
} }
else Status = STATUS_INVALID_PARAMETER;
Message->DesktopLen = CommandInfo->DesktopLen;
if (CommandInfo->TitleLen && Message->TitleLen) if (Message->TitleLen >= CommandInfo->TitleLen)
{ {
if (Message->TitleLen >= CommandInfo->TitleLen) /* Copy the title */
{ RtlMoveMemory(Message->Title, CommandInfo->Title, CommandInfo->TitleLen);
/* Copy the title */
RtlMoveMemory(Message->Title, CommandInfo->Title, CommandInfo->TitleLen);
}
else Status = STATUS_BUFFER_TOO_SMALL;
Message->TitleLen = CommandInfo->TitleLen;
} }
else Status = STATUS_INVALID_PARAMETER;
Message->TitleLen = CommandInfo->TitleLen;
if (CommandInfo->ReservedLen && Message->ReservedLen) if (Message->ReservedLen >= CommandInfo->ReservedLen)
{ {
if (Message->ReservedLen >= CommandInfo->ReservedLen) /* Copy the reserved parameter */
{ RtlMoveMemory(Message->Reserved, CommandInfo->Reserved, CommandInfo->ReservedLen);
/* Copy the reserved parameter */
RtlMoveMemory(Message->Reserved, CommandInfo->Reserved, CommandInfo->ReservedLen);
}
else Status = STATUS_BUFFER_TOO_SMALL;
Message->ReservedLen = CommandInfo->ReservedLen;
} }
else Status = STATUS_INVALID_PARAMETER;
Message->ReservedLen = CommandInfo->ReservedLen;
return Status; return Status;
} }
VOID NTAPI BaseInitializeVDM(VOID) VOID BaseInitializeVDM(VOID)
{ {
/* Initialize the list head */ /* Initialize the list head */
InitializeListHead(&VDMConsoleListHead); InitializeListHead(&VDMConsoleListHead);
/* Initialize the critical section */ /* Initialize the critical sections */
RtlInitializeCriticalSection(&DosCriticalSection); RtlInitializeCriticalSection(&DosCriticalSection);
RtlInitializeCriticalSection(&WowCriticalSection); RtlInitializeCriticalSection(&WowCriticalSection);
} }
@ -577,6 +605,7 @@ CSR_API(BaseSrvCheckVDM)
PVDM_CONSOLE_RECORD ConsoleRecord = NULL; PVDM_CONSOLE_RECORD ConsoleRecord = NULL;
PVDM_DOS_RECORD DosRecord = NULL; PVDM_DOS_RECORD DosRecord = NULL;
BOOLEAN NewConsoleRecord = FALSE; BOOLEAN NewConsoleRecord = FALSE;
BOOLEAN NewDosRecord = FALSE;
/* Don't do anything if the VDM has been disabled in the registry */ /* Don't do anything if the VDM has been disabled in the registry */
if (!BaseSrvIsVdmAllowed()) return STATUS_VDM_DISALLOWED; if (!BaseSrvIsVdmAllowed()) return STATUS_VDM_DISALLOWED;
@ -627,53 +656,75 @@ CSR_API(BaseSrvCheckVDM)
/* Get the console record */ /* Get the console record */
Status = BaseSrvGetConsoleRecord(CheckVdmRequest->ConsoleHandle, Status = BaseSrvGetConsoleRecord(CheckVdmRequest->ConsoleHandle,
&ConsoleRecord); &ConsoleRecord);
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
/* Allocate a new console record */ /* Allocate a new console record */
ConsoleRecord = (PVDM_CONSOLE_RECORD)RtlAllocateHeap(BaseSrvHeap, ConsoleRecord = BaseSrvCreateConsoleRecord();
HEAP_ZERO_MEMORY,
sizeof(VDM_CONSOLE_RECORD));
if (ConsoleRecord == NULL) if (ConsoleRecord == NULL)
{ {
Status = STATUS_NO_MEMORY; Status = STATUS_NO_MEMORY;
goto Cleanup; goto Cleanup;
} }
/* Remember that the console record was allocated here */
NewConsoleRecord = TRUE;
/* Initialize the console record */ /* Initialize the console record */
ConsoleRecord->ConsoleHandle = CheckVdmRequest->ConsoleHandle; ConsoleRecord->ConsoleHandle = CheckVdmRequest->ConsoleHandle;
ConsoleRecord->ProcessHandle = NULL; if (ConsoleRecord->ConsoleHandle == NULL)
ConsoleRecord->ServerEvent = ConsoleRecord->ClientEvent = NULL; {
ConsoleRecord->ReenterCount = 0; /* The parent doesn't have a console, get a new session ID */
ConsoleRecord->CurrentDirs = NULL; ConsoleRecord->SessionId = GetNextDosSesId();
ConsoleRecord->CurDirsLength = 0; }
ConsoleRecord->SessionId = GetNextDosSesId(); else
InitializeListHead(&ConsoleRecord->DosListHead); {
/* No session ID is needed */
ConsoleRecord->SessionId = 0;
}
/* Remember that the console record was allocated here */
NewConsoleRecord = TRUE;
} }
/* Allocate a new DOS record */ if (!NewConsoleRecord)
DosRecord = (PVDM_DOS_RECORD)RtlAllocateHeap(BaseSrvHeap,
HEAP_ZERO_MEMORY,
sizeof(VDM_DOS_RECORD));
if (DosRecord == NULL)
{ {
Status = STATUS_NO_MEMORY; /* Get the primary DOS record */
goto Cleanup; DosRecord = (PVDM_DOS_RECORD)CONTAINING_RECORD(ConsoleRecord->DosListHead.Flink,
VDM_DOS_RECORD, Entry);
if (DosRecord->State != VDM_READY) // == VDM_NOT_READY
{
/* Allocate a new DOS record */
DosRecord = (PVDM_DOS_RECORD)RtlAllocateHeap(BaseSrvHeap,
HEAP_ZERO_MEMORY,
sizeof(VDM_DOS_RECORD));
if (DosRecord == NULL)
{
Status = STATUS_NO_MEMORY;
goto Cleanup;
}
/* Remember that the DOS record was allocated here */
NewDosRecord = TRUE;
}
}
else
{
/* Allocate a new DOS record */
DosRecord = (PVDM_DOS_RECORD)RtlAllocateHeap(BaseSrvHeap,
HEAP_ZERO_MEMORY,
sizeof(VDM_DOS_RECORD));
if (DosRecord == NULL)
{
Status = STATUS_NO_MEMORY;
goto Cleanup;
}
/* Remember that the DOS record was allocated here */
NewDosRecord = TRUE;
} }
/* Initialize the DOS record */ /* Initialize the DOS record */
DosRecord->State = VDM_NOT_LOADED; DosRecord->State = VDM_NOT_READY;
DosRecord->ExitCode = 0; DosRecord->ExitCode = 0;
Status = BaseSrvCreatePairWaitHandles(&DosRecord->ServerEvent, &DosRecord->ClientEvent);
if (!NT_SUCCESS(Status)) goto Cleanup;
/* Return the client event handle */
CheckVdmRequest->WaitObjectForParent = DosRecord->ClientEvent;
/* Translate the input structure into a VDM command structure and set it in the DOS record */ /* Translate the input structure into a VDM command structure and set it in the DOS record */
if (!BaseSrvCopyCommand(CheckVdmRequest, DosRecord)) if (!BaseSrvCopyCommand(CheckVdmRequest, DosRecord))
{ {
@ -682,9 +733,23 @@ CSR_API(BaseSrvCheckVDM)
goto Cleanup; goto Cleanup;
} }
/* Add the DOS record */ if (NewDosRecord)
InsertHeadList(&ConsoleRecord->DosListHead, &DosRecord->Entry); {
/* Add the DOS record */
InsertHeadList(&ConsoleRecord->DosListHead, &DosRecord->Entry);
}
if (!NewConsoleRecord)
{
Status = BaseSrvCreatePairWaitHandles(&DosRecord->ServerEvent, &DosRecord->ClientEvent);
if (!NT_SUCCESS(Status)) goto Cleanup;
/* Return the client event handle */
CheckVdmRequest->WaitObjectForParent = DosRecord->ClientEvent;
}
// FIXME: We may notify ONLY if ConsoleRecord->nReEntrancy is > 0
// in case NewConsoleRecord == FALSE AND NewDosRecord == TRUE.
if (ConsoleRecord->ServerEvent) if (ConsoleRecord->ServerEvent)
{ {
/* Signal the session event */ /* Signal the session event */
@ -697,13 +762,7 @@ CSR_API(BaseSrvCheckVDM)
InsertTailList(&VDMConsoleListHead, &ConsoleRecord->Entry); InsertTailList(&VDMConsoleListHead, &ConsoleRecord->Entry);
} }
if (ConsoleRecord->ConsoleHandle == NULL) CheckVdmRequest->iTask = ConsoleRecord->SessionId;
{
/* The parent doesn't have a console, so return the session ID */
CheckVdmRequest->iTask = ConsoleRecord->SessionId;
}
else CheckVdmRequest->iTask = 0;
CheckVdmRequest->VDMState = NewConsoleRecord ? VDM_NOT_LOADED : VDM_READY; CheckVdmRequest->VDMState = NewConsoleRecord ? VDM_NOT_LOADED : VDM_READY;
Status = STATUS_SUCCESS; Status = STATUS_SUCCESS;
} }
@ -718,21 +777,13 @@ Cleanup:
/* Check if it failed */ /* Check if it failed */
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
/* Free the DOS record */ /* Free the DOS record if it was allocated here */
if (DosRecord != NULL) if (NewDosRecord)
{ {
if (DosRecord->ServerEvent) NtClose(DosRecord->ServerEvent); ASSERT(DosRecord != NULL);
if (DosRecord->ClientEvent)
{ BaseSrvDestroyPairWaitHandles(DosRecord->ServerEvent,
/* Close the remote handle */ DosRecord->ClientEvent);
NtDuplicateObject(CsrGetClientThread()->Process->ProcessHandle,
DosRecord->ClientEvent,
NULL,
NULL,
0,
0,
DUPLICATE_CLOSE_SOURCE);
}
RtlFreeHeap(BaseSrvHeap, 0, DosRecord); RtlFreeHeap(BaseSrvHeap, 0, DosRecord);
DosRecord = NULL; DosRecord = NULL;
@ -741,6 +792,8 @@ Cleanup:
/* Free the console record if it was allocated here */ /* Free the console record if it was allocated here */
if (NewConsoleRecord) if (NewConsoleRecord)
{ {
ASSERT(ConsoleRecord != NULL);
RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord); RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord);
ConsoleRecord = NULL; ConsoleRecord = NULL;
} }
@ -787,8 +840,7 @@ CSR_API(BaseSrvUpdateVDMEntry)
/* Get the primary DOS record */ /* Get the primary DOS record */
DosRecord = (PVDM_DOS_RECORD)CONTAINING_RECORD(ConsoleRecord->DosListHead.Flink, DosRecord = (PVDM_DOS_RECORD)CONTAINING_RECORD(ConsoleRecord->DosListHead.Flink,
VDM_DOS_RECORD, VDM_DOS_RECORD, Entry);
Entry);
switch (UpdateVdmEntryRequest->EntryIndex) switch (UpdateVdmEntryRequest->EntryIndex)
{ {
@ -811,10 +863,8 @@ CSR_API(BaseSrvUpdateVDMEntry)
*/ */
if (ConsoleRecord->DosListHead.Flink == &ConsoleRecord->DosListHead) if (ConsoleRecord->DosListHead.Flink == &ConsoleRecord->DosListHead)
{ {
if (ConsoleRecord->ProcessHandle) NtClose(ConsoleRecord->ProcessHandle);
if (ConsoleRecord->ServerEvent) NtClose(ConsoleRecord->ServerEvent);
RemoveEntryList(&ConsoleRecord->Entry); RemoveEntryList(&ConsoleRecord->Entry);
RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord); BaseSrvDestroyConsoleRecord(ConsoleRecord);
} }
} }
@ -836,6 +886,10 @@ CSR_API(BaseSrvUpdateVDMEntry)
DUPLICATE_SAME_ATTRIBUTES | DUPLICATE_SAME_ACCESS); DUPLICATE_SAME_ATTRIBUTES | DUPLICATE_SAME_ACCESS);
if (!NT_SUCCESS(Status)) goto Cleanup; if (!NT_SUCCESS(Status)) goto Cleanup;
//
// FIXME! Should we always do the following??
//
/* Create a pair of handles to one event object */ /* Create a pair of handles to one event object */
Status = BaseSrvCreatePairWaitHandles(&DosRecord->ServerEvent, Status = BaseSrvCreatePairWaitHandles(&DosRecord->ServerEvent,
&DosRecord->ClientEvent); &DosRecord->ClientEvent);
@ -881,7 +935,7 @@ CSR_API(BaseSrvGetNextVDMCommand)
{ {
NTSTATUS Status; NTSTATUS Status;
PBASE_GET_NEXT_VDM_COMMAND GetNextVdmCommandRequest = PBASE_GET_NEXT_VDM_COMMAND GetNextVdmCommandRequest =
&((PBASE_API_MESSAGE)ApiMessage)->Data.GetNextVDMCommandRequest; &((PBASE_API_MESSAGE)ApiMessage)->Data.GetNextVDMCommandRequest;
PRTL_CRITICAL_SECTION CriticalSection; PRTL_CRITICAL_SECTION CriticalSection;
PLIST_ENTRY i = NULL; PLIST_ENTRY i = NULL;
PVDM_CONSOLE_RECORD ConsoleRecord = NULL; PVDM_CONSOLE_RECORD ConsoleRecord = NULL;
@ -935,7 +989,14 @@ CSR_API(BaseSrvGetNextVDMCommand)
/* Enter the critical section */ /* Enter the critical section */
RtlEnterCriticalSection(CriticalSection); RtlEnterCriticalSection(CriticalSection);
if (!(GetNextVdmCommandRequest->VDMState & VDM_FLAG_WOW)) if (GetNextVdmCommandRequest->VDMState & VDM_FLAG_WOW)
{
// TODO: WOW SUPPORT NOT IMPLEMENTED
UNIMPLEMENTED;
Status = STATUS_NOT_IMPLEMENTED;
goto Cleanup;
}
// else if (!(GetNextVdmCommandRequest->VDMState & VDM_FLAG_WOW))
{ {
if (GetNextVdmCommandRequest->iTask != 0) if (GetNextVdmCommandRequest->iTask != 0)
{ {
@ -1018,16 +1079,16 @@ CSR_API(BaseSrvGetNextVDMCommand)
DosRecord->ServerEvent = NULL; DosRecord->ServerEvent = NULL;
} }
/* Search for a DOS record that isn't loaded yet */ /* Search for a DOS record that is currently running and has command information */
for (i = ConsoleRecord->DosListHead.Flink; i != &ConsoleRecord->DosListHead; i = i->Flink) for (i = ConsoleRecord->DosListHead.Flink; i != &ConsoleRecord->DosListHead; i = i->Flink)
{ {
DosRecord = CONTAINING_RECORD(i, VDM_DOS_RECORD, Entry); DosRecord = CONTAINING_RECORD(i, VDM_DOS_RECORD, Entry);
if (DosRecord->State == VDM_NOT_LOADED) break; if ((DosRecord->State == VDM_NOT_READY) && (DosRecord->CommandInfo != NULL)) break;
} }
/* Check if we found any */
if (i != &ConsoleRecord->DosListHead) if (i != &ConsoleRecord->DosListHead)
{ {
/* DOS tasks which haven't been loaded yet should have a command info structure */
ASSERT(DosRecord->CommandInfo != NULL); ASSERT(DosRecord->CommandInfo != NULL);
/* Check if the caller only wants environment data */ /* Check if the caller only wants environment data */
@ -1060,22 +1121,22 @@ CSR_API(BaseSrvGetNextVDMCommand)
DosRecord->CommandInfo = NULL; DosRecord->CommandInfo = NULL;
/* Update the VDM state */ /* Update the VDM state */
GetNextVdmCommandRequest->VDMState = DosRecord->State = VDM_NOT_READY; DosRecord->State = VDM_NOT_READY;
} }
Status = STATUS_SUCCESS; Status = STATUS_SUCCESS;
goto Cleanup; goto Cleanup;
} }
} }
else
{
// TODO: WOW SUPPORT NOT IMPLEMENTED
Status = STATUS_NOT_IMPLEMENTED;
goto Cleanup;
}
/* There is no command yet */ GetNextVdmCommandRequest->WaitObjectForVDM = NULL;
if (!(GetNextVdmCommandRequest->VDMState & VDM_FLAG_DONT_WAIT))
/*
* There is no command yet. Prepare for waiting if we asked so,
* and if we were not retrying a request.
*/
if (!(GetNextVdmCommandRequest->VDMState & VDM_FLAG_DONT_WAIT) ||
!(GetNextVdmCommandRequest->VDMState & VDM_FLAG_RETRY))
{ {
if (ConsoleRecord->ServerEvent) if (ConsoleRecord->ServerEvent)
{ {
@ -1122,16 +1183,30 @@ CSR_API(BaseSrvExitVDM)
Status = BaseSrvGetConsoleRecord(ExitVdmRequest->ConsoleHandle, &ConsoleRecord); Status = BaseSrvGetConsoleRecord(ExitVdmRequest->ConsoleHandle, &ConsoleRecord);
if (!NT_SUCCESS(Status)) goto Cleanup; if (!NT_SUCCESS(Status)) goto Cleanup;
if (ConsoleRecord->ServerEvent)
ExitVdmRequest->WaitObjectForVDM = ConsoleRecord->ClientEvent;
// NOTE: The following is the same as in BaseSrvCleanupVDMResources.
if (ConsoleRecord->ServerEvent)
{
NtClose(ConsoleRecord->ServerEvent);
ConsoleRecord->ServerEvent = NULL;
}
/* Cleanup the DOS records */ /* Cleanup the DOS records */
while (ConsoleRecord->DosListHead.Flink != &ConsoleRecord->DosListHead) while (!IsListEmpty(&ConsoleRecord->DosListHead))
{ {
DosRecord = CONTAINING_RECORD(ConsoleRecord->DosListHead.Flink, DosRecord = CONTAINING_RECORD(ConsoleRecord->DosListHead.Flink,
VDM_DOS_RECORD, VDM_DOS_RECORD, Entry);
Entry);
/* Set the event and close it */ /* Set the event and close it */
NtSetEvent(DosRecord->ServerEvent, NULL); if (DosRecord->ServerEvent)
NtClose(DosRecord->ServerEvent); {
NtSetEvent(DosRecord->ServerEvent, NULL);
NtClose(DosRecord->ServerEvent);
DosRecord->ServerEvent = NULL;
}
/* Remove the DOS entry */ /* Remove the DOS entry */
if (DosRecord->CommandInfo) BaseSrvFreeVDMInfo(DosRecord->CommandInfo); if (DosRecord->CommandInfo) BaseSrvFreeVDMInfo(DosRecord->CommandInfo);
@ -1139,20 +1214,9 @@ CSR_API(BaseSrvExitVDM)
RtlFreeHeap(BaseSrvHeap, 0, DosRecord); RtlFreeHeap(BaseSrvHeap, 0, DosRecord);
} }
if (ConsoleRecord->CurrentDirs != NULL)
{
/* Free the current directories */
RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord->CurrentDirs);
ConsoleRecord->CurrentDirs = NULL;
ConsoleRecord->CurDirsLength = 0;
}
/* Close the event handle */
if (ConsoleRecord->ServerEvent) NtClose(ConsoleRecord->ServerEvent);
/* Remove the console record */ /* Remove the console record */
RemoveEntryList(&ConsoleRecord->Entry); RemoveEntryList(&ConsoleRecord->Entry);
RtlFreeHeap(BaseSrvHeap, 0, ConsoleRecord); BaseSrvDestroyConsoleRecord(ConsoleRecord);
} }
else else
{ {
@ -1220,6 +1284,8 @@ CSR_API(BaseSrvGetVDMExitCode)
/* Return the exit code */ /* Return the exit code */
GetVDMExitCodeRequest->ExitCode = DosRecord->ExitCode; GetVDMExitCodeRequest->ExitCode = DosRecord->ExitCode;
// FIXME: We may just change DosRecord->State to VDM_READY in some cases...
/* Since this is a zombie task record, remove it */ /* Since this is a zombie task record, remove it */
if (DosRecord->CommandInfo) BaseSrvFreeVDMInfo(DosRecord->CommandInfo); if (DosRecord->CommandInfo) BaseSrvFreeVDMInfo(DosRecord->CommandInfo);
RemoveEntryList(&DosRecord->Entry); RemoveEntryList(&DosRecord->Entry);
@ -1245,13 +1311,20 @@ CSR_API(BaseSrvSetReenterCount)
Status = BaseSrvGetConsoleRecord(SetReenterCountRequest->ConsoleHandle, &ConsoleRecord); Status = BaseSrvGetConsoleRecord(SetReenterCountRequest->ConsoleHandle, &ConsoleRecord);
if (!NT_SUCCESS(Status)) goto Cleanup; if (!NT_SUCCESS(Status)) goto Cleanup;
if (SetReenterCountRequest->fIncDec == VDM_INC_REENTER_COUNT) ConsoleRecord->ReenterCount++; if (SetReenterCountRequest->fIncDec == VDM_INC_REENTER_COUNT)
{
ConsoleRecord->ReenterCount++;
}
else if (SetReenterCountRequest->fIncDec == VDM_DEC_REENTER_COUNT) else if (SetReenterCountRequest->fIncDec == VDM_DEC_REENTER_COUNT)
{ {
ConsoleRecord->ReenterCount--; ConsoleRecord->ReenterCount--;
if (ConsoleRecord->ServerEvent != NULL) NtSetEvent(ConsoleRecord->ServerEvent, NULL); if (ConsoleRecord->ServerEvent)
NtSetEvent(ConsoleRecord->ServerEvent, NULL);
}
else
{
Status = STATUS_INVALID_PARAMETER;
} }
else Status = STATUS_INVALID_PARAMETER;
Cleanup: Cleanup:
/* Leave the critical section */ /* Leave the critical section */

View file

@ -43,18 +43,11 @@ typedef struct _VDM_DOS_RECORD
/* FUNCTIONS ******************************************************************/ /* FUNCTIONS ******************************************************************/
NTSTATUS NTAPI BaseSrvGetConsoleRecord(HANDLE ConsoleHandle, PVDM_CONSOLE_RECORD *Record); NTSTATUS BaseSrvGetConsoleRecord(HANDLE ConsoleHandle, PVDM_CONSOLE_RECORD *Record);
NTSTATUS NTAPI GetConsoleRecordBySessionId(ULONG TaskId, PVDM_CONSOLE_RECORD *Record); NTSTATUS GetConsoleRecordBySessionId(ULONG TaskId, PVDM_CONSOLE_RECORD *Record);
ULONG NTAPI GetNextDosSesId(VOID);
BOOLEAN NTAPI BaseSrvIsVdmAllowed(VOID); BOOLEAN BaseSrvIsVdmAllowed(VOID);
NTSTATUS NTAPI BaseSrvCreatePairWaitHandles(PHANDLE ServerEvent, PHANDLE ClientEvent); VOID BaseInitializeVDM(VOID);
VOID NTAPI BaseSrvFreeVDMInfo(PVDM_COMMAND_INFO CommandInfo); VOID BaseSrvCleanupVDMResources(IN PCSR_PROCESS CsrProcess);
VOID NTAPI BaseSrvCleanupVDMResources(IN PCSR_PROCESS CsrProcess);
BOOLEAN NTAPI BaseSrvCopyCommand(PBASE_CHECK_VDM CheckVdmRequest, PVDM_DOS_RECORD DosRecord);
NTSTATUS NTAPI BaseSrvFillCommandInfo(
PVDM_COMMAND_INFO CommandInfo,
PBASE_GET_NEXT_VDM_COMMAND Message
);
VOID NTAPI BaseInitializeVDM(VOID);
#endif // __VDM_H__ #endif // __VDM_H__