NT4/private/windows/base/server/srvvdm.c
2020-09-30 17:12:29 +02:00

2921 lines
82 KiB
C

/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
srvvdm.c
Abstract:
This module implements windows server functions for VDMs
Author:
Sudeep Bharati (sudeepb) 03-Sep-1991
Revision History:
Sudeepb 18-Sep-1992
Added code to make VDM termination and resource cleanup robust.
AndyH 23-May-1994
Added Code to allow the Shared WOW to run if client is Interactive or SYSTEM
impersonating Interactive.
--*/
#include "basesrv.h"
//
// Initialize to an unused LUID value.
// Nobody will ever be assigned this value, so it shouldn't
// match any legitimately logged on user.
//
LUID WowAuthId={0xFFFFFFFF,-1};
BOOL fIsFirstVDM = TRUE;
PWOWHEAD WOWHead = NULL; // Head of WOW Tasks list
PCONSOLERECORD DOSHead = NULL; // Head Of DOS tasks with a valid Console
PBATRECORD BatRecordHead = NULL;
ULONG WOWTaskIdNext = WOWMINID;
RTL_CRITICAL_SECTION BaseSrvDOSCriticalSection;
RTL_CRITICAL_SECTION BaseSrvWOWCriticalSection;
HANDLE hwndWowExec = NULL;
DWORD dwWowExecProcessId = 0;
DWORD dwWowExecThreadId = 0;
ULONG ulWowExecProcessSequenceNumber = 0;
typedef BOOL (WINAPI *POSTMESSAGEPROC)(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
POSTMESSAGEPROC BaseSrvPostMessageA;
typedef BOOL (WINAPI *GETWINDOWTHREADPROCESSIDPROC)(HWND hWnd, LPDWORD lpdwProcessId);
GETWINDOWTHREADPROCESSIDPROC BaseSrvGetWindowThreadProcessId;
typedef NTSTATUS (*USERTESTTOKENFORINTERACTIVE)(HANDLE Token, PLUID pluidCaller);
USERTESTTOKENFORINTERACTIVE UserTestTokenForInteractive = NULL;
// internal prototypes
ULONG
GetNextDosSesId(VOID);
NTSTATUS
GetConsoleRecordDosSesId (
IN ULONG DosSesId,
IN OUT PCONSOLERECORD *pConsoleRecord
);
NTSTATUS
OkToRunInSharedWOW(
IN HANDLE UniqueProcessClientId,
OUT PLUID pAuthenticationId
);
BOOL
IsClientSystem(
HANDLE hUserToken
);
VOID
BaseSrvVDMInit(VOID)
{
NTSTATUS Status;
Status = RtlInitializeCriticalSection( &BaseSrvDOSCriticalSection );
ASSERT( NT_SUCCESS( Status ) );
Status = RtlInitializeCriticalSection( &BaseSrvWOWCriticalSection );
ASSERT( NT_SUCCESS( Status ) );
return;
}
ULONG
BaseSrvCheckVDM(
IN OUT PCSR_API_MSG m,
IN OUT PCSR_REPLY_STATUS ReplyStatus
)
{
NTSTATUS Status;
PBASE_CHECKVDM_MSG b = (PBASE_CHECKVDM_MSG)&m->u.ApiMessageData;
if(b->BinaryType == BINARY_TYPE_WIN16) {
Status = BaseSrvCheckWOW (b, m->h.ClientId.UniqueProcess);
}
else
Status = BaseSrvCheckDOS (b);
return ((ULONG)Status);
}
ULONG
BaseSrvUpdateVDMEntry(
IN OUT PCSR_API_MSG m,
IN OUT PCSR_REPLY_STATUS ReplyStatus
)
{
PBASE_UPDATE_VDM_ENTRY_MSG b = (PBASE_UPDATE_VDM_ENTRY_MSG)&m->u.ApiMessageData;
if(b->ConsoleHandle == (HANDLE)-1)
return (BaseSrvUpdateWOWEntry (b));
else
return (BaseSrvUpdateDOSEntry (b));
}
ULONG
BaseSrvGetNextVDMCommand(
IN OUT PCSR_API_MSG m,
IN OUT PCSR_REPLY_STATUS ReplyStatus
)
{
NTSTATUS Status;
PBASE_GET_NEXT_VDM_COMMAND_MSG b = (PBASE_GET_NEXT_VDM_COMMAND_MSG)&m->u.ApiMessageData;
PDOSRECORD pDOSRecord,pDOSRecordTemp=NULL;
PWOWRECORD pWOWRecord;
PCONSOLERECORD pConsoleRecord;
PVDMINFO lpVDMInfo;
HANDLE Handle,TargetHandle;
LONG WaitState;
PBATRECORD pBatRecord;
if(b->ConsoleHandle == (HANDLE)-1){
//
// WowExec is asking for a command. We never block when
// asking for a WOW binary, since WOW no longer has a thread
// blocked in GetNextVDMCommand. Instead, WowExec gets a
// message posted to it by BaseSrv when there are command(s)
// waiting for it, and it loops calling GetNextVDMCommand
// until it fails -- but it must not block.
//
Status = RtlEnterCriticalSection( &BaseSrvWOWCriticalSection );
ASSERT( NT_SUCCESS( Status ) );
b->WaitObjectForVDM = 0;
if ((pWOWRecord = BaseSrvCheckAvailableWOWCommand()) == NULL) {
//
// There's no command waiting for WOW, so just return.
// This is where we used to cause blocking.
//
b->TitleLen =
b->EnvLen =
b->DesktopLen =
b->ReservedLen =
b->CmdLen =
b->AppLen =
b->PifLen =
b->CurDirectoryLen = 0;
RtlLeaveCriticalSection( &BaseSrvWOWCriticalSection );
return ((ULONG)STATUS_SUCCESS);
}
lpVDMInfo = pWOWRecord->lpVDMInfo;
if (b->VDMState & ASKING_FOR_PIF) {
Status = BaseSrvFillPifInfo (lpVDMInfo,b);
RtlLeaveCriticalSection( &BaseSrvWOWCriticalSection );
return (Status);
}
}
else{
//
// DOS VDM or Separate WOW is asking for next command.
//
Status = RtlEnterCriticalSection( &BaseSrvDOSCriticalSection );
ASSERT(NT_SUCCESS(Status));
if (b->VDMState & ASKING_FOR_PIF && b->iTask)
Status = GetConsoleRecordDosSesId(b->iTask,&pConsoleRecord);
else
Status = BaseSrvGetConsoleRecord(b->ConsoleHandle,&pConsoleRecord);
if (!NT_SUCCESS (Status)) {
RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
return ((ULONG)STATUS_INVALID_PARAMETER);
}
pDOSRecord = pConsoleRecord->DOSRecord;
if (b->VDMState & ASKING_FOR_PIF) {
if (pDOSRecord) {
Status = BaseSrvFillPifInfo (pDOSRecord->lpVDMInfo,b);
if (b->iTask) {
if (!pConsoleRecord->hConsole) {
pConsoleRecord->hConsole = b->ConsoleHandle;
pConsoleRecord->DosSesId = 0;
}
else {
Status = STATUS_INVALID_PARAMETER;
}
}
}
else {
Status = STATUS_INVALID_PARAMETER;
}
RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
return (Status);
}
if (!(b->VDMState & ASKING_FOR_SEPWOW_BINARY)) {
if (!(b->VDMState & (ASKING_FOR_FIRST_COMMAND |
ASKING_FOR_SECOND_TIME |
NO_PARENT_TO_WAKE))
|| (b->VDMState & ASKING_FOR_SECOND_TIME && b->ExitCode != 0))
{
// Search first VDM_TO_TAKE_A_COMMAND or last VDM_BUSY record as
// per the case.
if (b->VDMState & ASKING_FOR_SECOND_TIME){
while(pDOSRecord && pDOSRecord->VDMState != VDM_TO_TAKE_A_COMMAND)
pDOSRecord = pDOSRecord->DOSRecordNext;
}
else {
while(pDOSRecord){
if(pDOSRecord->VDMState == VDM_BUSY)
pDOSRecordTemp = pDOSRecord;
pDOSRecord = pDOSRecord->DOSRecordNext;
}
pDOSRecord = pDOSRecordTemp;
}
if (pDOSRecord == NULL) {
RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
return STATUS_SUCCESS;
}
pDOSRecord->ErrorCode = b->ExitCode;
pDOSRecord->VDMState = VDM_HAS_RETURNED_ERROR_CODE;
NtSetEvent (pDOSRecord->hWaitForParentDup,NULL);
NtClose (pDOSRecord->hWaitForParentDup);
pDOSRecord->hWaitForParentDup = 0;
pDOSRecord = pDOSRecord->DOSRecordNext;
}
}
while (pDOSRecord && pDOSRecord->VDMState != VDM_TO_TAKE_A_COMMAND)
pDOSRecord = pDOSRecord->DOSRecordNext;
if (pDOSRecord == NULL) {
if ((b->VDMState & ASKING_FOR_SEPWOW_BINARY) ||
(b->VDMState & RETURN_ON_NO_COMMAND && b->VDMState & ASKING_FOR_SECOND_TIME))
{
b->WaitObjectForVDM = 0;
RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
return ((ULONG)STATUS_NO_MEMORY);
}
if(pConsoleRecord->hWaitForVDMDup == 0 ){
if(NT_SUCCESS(BaseSrvCreatePairWaitHandles (&Handle,
&TargetHandle))){
pConsoleRecord->hWaitForVDMDup = Handle;
pConsoleRecord->hWaitForVDM = TargetHandle;
}
else {
b->WaitObjectForVDM = 0;
RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
return ((ULONG)STATUS_NO_MEMORY);
}
}
else {
NtResetEvent(pConsoleRecord->hWaitForVDMDup,&WaitState);
}
b->WaitObjectForVDM = pConsoleRecord->hWaitForVDM;
RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
return STATUS_SUCCESS;
}
b->WaitObjectForVDM = 0;
lpVDMInfo = pDOSRecord->lpVDMInfo;
}
//
// ASKING_FOR_ENVIRONMENT
// Return the information but DO NOT delete the lpVDMInfo
// associated with the DOS record
//
if (b->VDMState & ASKING_FOR_ENVIRONMENT) {
if (lpVDMInfo->EnviornmentSize <= b->EnvLen) {
RtlMoveMemory(b->Env,
lpVDMInfo->Enviornment,
lpVDMInfo->EnviornmentSize);
Status = STATUS_SUCCESS;
}
else {
Status = STATUS_INVALID_PARAMETER;
}
b->EnvLen = lpVDMInfo->EnviornmentSize;
if(b->ConsoleHandle == (HANDLE)-1)
RtlLeaveCriticalSection( &BaseSrvWOWCriticalSection );
else
RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
return Status;
}
//
// check buffer sizes, CmdLine is mandatory!
//
if (!b->CmdLine || lpVDMInfo->CmdSize > b->CmdLen ||
(b->AppName && lpVDMInfo->AppLen > b->AppLen) ||
(b->Env && lpVDMInfo->EnviornmentSize > b->EnvLen) ||
(b->PifFile && lpVDMInfo->PifLen > b->PifLen) ||
(b->CurDirectory && lpVDMInfo->CurDirectoryLen > b->CurDirectoryLen) ||
(b->Title && lpVDMInfo->TitleLen > b->TitleLen) ||
(b->Reserved && lpVDMInfo->ReservedLen > b->ReservedLen) ||
(b->Desktop && lpVDMInfo->DesktopLen > b->DesktopLen))
{
Status = STATUS_INVALID_PARAMETER;
}
else {
Status = STATUS_SUCCESS;
}
b->CmdLen = lpVDMInfo->CmdSize;
b->AppLen = lpVDMInfo->AppLen;
b->PifLen = lpVDMInfo->PifLen;
b->EnvLen = lpVDMInfo->EnviornmentSize;
b->CurDirectoryLen = lpVDMInfo->CurDirectoryLen;
b->DesktopLen = lpVDMInfo->DesktopLen;
b->TitleLen = lpVDMInfo->TitleLen;
b->ReservedLen = lpVDMInfo->ReservedLen;
if (!NT_SUCCESS(Status)) {
if(b->ConsoleHandle == (HANDLE)-1)
RtlLeaveCriticalSection( &BaseSrvWOWCriticalSection );
else
RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
return (Status);
}
if (lpVDMInfo->CmdLine && b->CmdLine)
RtlMoveMemory(b->CmdLine,
lpVDMInfo->CmdLine,
lpVDMInfo->CmdSize);
if (lpVDMInfo->AppName && b->AppName)
RtlMoveMemory(b->AppName,
lpVDMInfo->AppName,
lpVDMInfo->AppLen);
if (lpVDMInfo->PifFile && b->PifFile)
RtlMoveMemory(b->PifFile,
lpVDMInfo->PifFile,
lpVDMInfo->PifLen);
if (lpVDMInfo->CurDirectory && b->CurDirectory)
RtlMoveMemory(b->CurDirectory,
lpVDMInfo->CurDirectory,
lpVDMInfo->CurDirectoryLen);
if (lpVDMInfo->Title && b->Title)
RtlMoveMemory(b->Title,
lpVDMInfo->Title,
lpVDMInfo->TitleLen);
if (lpVDMInfo->Reserved && b->Reserved)
RtlMoveMemory(b->Reserved,
lpVDMInfo->Reserved,
lpVDMInfo->ReservedLen);
if (lpVDMInfo->Enviornment && b->Env)
RtlMoveMemory(b->Env,
lpVDMInfo->Enviornment,
lpVDMInfo->EnviornmentSize);
if (lpVDMInfo->VDMState & STARTUP_INFO_RETURNED)
RtlMoveMemory(b->StartupInfo,
&lpVDMInfo->StartupInfo,
sizeof (STARTUPINFOA));
if (lpVDMInfo->Desktop && b->Desktop)
RtlMoveMemory(b->Desktop,
lpVDMInfo->Desktop,
lpVDMInfo->DesktopLen);
if ((pBatRecord = BaseSrvGetBatRecord (b->ConsoleHandle)) != NULL)
b->fComingFromBat = TRUE;
else
b->fComingFromBat = FALSE;
b->CurrentDrive = lpVDMInfo->CurDrive;
b->CodePage = lpVDMInfo->CodePage;
b->dwCreationFlags = lpVDMInfo->dwCreationFlags;
b->VDMState = lpVDMInfo->VDMState;
if (b->ConsoleHandle == (HANDLE)-1){
b->iTask = pWOWRecord->iTask;
pWOWRecord->fDispatched = TRUE;
}
else {
pDOSRecord->VDMState = VDM_BUSY;
}
b->StdIn = lpVDMInfo->StdIn;
b->StdOut = lpVDMInfo->StdOut;
b->StdErr = lpVDMInfo->StdErr;
if (b->VDMState & ASKING_FOR_SEPWOW_BINARY) {
BaseSrvFreeConsoleRecord(pConsoleRecord);
RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
}
else {
BaseSrvFreeVDMInfo (lpVDMInfo);
if(b->ConsoleHandle == (HANDLE)-1){
pWOWRecord->lpVDMInfo = NULL;
RtlLeaveCriticalSection( &BaseSrvWOWCriticalSection );
}
else {
pDOSRecord->lpVDMInfo = NULL;
RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
}
}
return Status;
}
ULONG
BaseSrvExitVDM(
IN OUT PCSR_API_MSG m,
IN OUT PCSR_REPLY_STATUS ReplyStatus
)
{
PBASE_EXIT_VDM_MSG b = (PBASE_EXIT_VDM_MSG)&m->u.ApiMessageData;
if(b->ConsoleHandle == (HANDLE)-1)
return BaseSrvExitWOWTask (b, m->h.ClientId.UniqueProcess);
else
return BaseSrvExitDOSTask (b);
}
ULONG
BaseSrvIsFirstVDM(
IN OUT PCSR_API_MSG m,
IN OUT PCSR_REPLY_STATUS ReplyStatus
)
{
PBASE_IS_FIRST_VDM_MSG c = (PBASE_IS_FIRST_VDM_MSG)&m->u.ApiMessageData;
c->FirstVDM = fIsFirstVDM;
if(fIsFirstVDM)
fIsFirstVDM = FALSE;
return STATUS_SUCCESS;
}
ULONG
BaseSrvSetVDMCurDirs(
IN OUT PCSR_API_MSG m,
IN OUT PCSR_REPLY_STATUS ReplyStatus
)
{
NTSTATUS Status;
PBASE_GET_SET_VDM_CUR_DIRS_MSG b = (PBASE_GET_SET_VDM_CUR_DIRS_MSG)&m->u.ApiMessageData;
PCONSOLERECORD pConsoleRecord;
if (b->ConsoleHandle == (HANDLE) -1) {
return (ULONG) STATUS_INVALID_PARAMETER;
}
Status = RtlEnterCriticalSection( &BaseSrvDOSCriticalSection );
ASSERT(NT_SUCCESS(Status));
Status = BaseSrvGetConsoleRecord(b->ConsoleHandle,&pConsoleRecord);
if (!NT_SUCCESS (Status)) {
RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
return ((ULONG)STATUS_INVALID_PARAMETER);
}
if (pConsoleRecord->lpszzCurDirs) {
RtlFreeHeap(BaseSrvHeap, 0, pConsoleRecord->lpszzCurDirs);
pConsoleRecord->lpszzCurDirs = NULL;
pConsoleRecord->cchCurDirs = 0;
}
if (b->cchCurDirs && b->lpszzCurDirs) {
pConsoleRecord->lpszzCurDirs = RtlAllocateHeap(
BaseSrvHeap,
MAKE_TAG( VDM_TAG ),
b->cchCurDirs
);
if (pConsoleRecord->lpszzCurDirs == NULL) {
pConsoleRecord->cchCurDirs = 0;
RtlLeaveCriticalSection(&BaseSrvDOSCriticalSection);
return (ULONG)STATUS_NO_MEMORY;
}
RtlMoveMemory(pConsoleRecord->lpszzCurDirs,
b->lpszzCurDirs,
b->cchCurDirs
);
pConsoleRecord->cchCurDirs = b->cchCurDirs;
RtlLeaveCriticalSection(&BaseSrvDOSCriticalSection);
return (ULONG) STATUS_SUCCESS;
}
RtlLeaveCriticalSection(&BaseSrvDOSCriticalSection);
return (ULONG) STATUS_INVALID_PARAMETER;
}
ULONG
BaseSrvBatNotification(
IN OUT PCSR_API_MSG m,
IN OUT PCSR_REPLY_STATUS ReplyStatus
)
{
NTSTATUS Status;
PBATRECORD pBatRecord;
PBASE_BAT_NOTIFICATION_MSG b = (PBASE_BAT_NOTIFICATION_MSG)&m->u.ApiMessageData;
Status = RtlEnterCriticalSection( &BaseSrvDOSCriticalSection );
ASSERT(NT_SUCCESS(Status));
// If BATRECORD does'nt exist for this console, create one only if
// bat file execution is beginig i.e. fBeginEnd is TRUE.
if ((pBatRecord = BaseSrvGetBatRecord(b->ConsoleHandle)) == NULL) {
if (!(b->fBeginEnd == CMD_BAT_OPERATION_STARTING &&
(pBatRecord = BaseSrvAllocateAndAddBatRecord (b->ConsoleHandle)))) {
RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
return ((ULONG)STATUS_SUCCESS);
}
}
else if (b->fBeginEnd == CMD_BAT_OPERATION_TERMINATING)
BaseSrvFreeAndRemoveBatRecord (pBatRecord);
RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
return ((ULONG)STATUS_SUCCESS);
}
ULONG
BaseSrvRegisterWowExec(
IN OUT PCSR_API_MSG m,
IN OUT PCSR_REPLY_STATUS ReplyStatus
)
{
PBASE_REGISTER_WOWEXEC_MSG b = (PBASE_REGISTER_WOWEXEC_MSG)&m->u.ApiMessageData;
UNICODE_STRING ModuleNameString_U;
PVOID ModuleHandle;
STRING ProcedureNameString;
NTSTATUS Status;
PCSR_PROCESS Process;
Status = RtlEnterCriticalSection( &BaseSrvWOWCriticalSection );
ASSERT( NT_SUCCESS( Status ) );
//
// Do a run-time link to PostMessageA and GetWindowThreadProcessId
// which we'll use to post messages to WowExec.
//
if (!BaseSrvPostMessageA) {
RtlInitUnicodeString( &ModuleNameString_U, L"user32" );
Status = LdrLoadDll( UNICODE_NULL, NULL, &ModuleNameString_U, &ModuleHandle );
if ( !NT_SUCCESS(Status) ) {
goto Cleanup;
}
RtlInitString( &ProcedureNameString, "PostMessageA" );
Status = LdrGetProcedureAddress( ModuleHandle,
&ProcedureNameString,
(ULONG) NULL,
(PVOID *) &BaseSrvPostMessageA
);
if ( !NT_SUCCESS(Status) ) {
LdrUnloadDll( ModuleHandle );
goto Cleanup;
}
RtlInitString( &ProcedureNameString, "GetWindowThreadProcessId" );
Status = LdrGetProcedureAddress( ModuleHandle,
&ProcedureNameString,
(ULONG) NULL,
(PVOID *) &BaseSrvGetWindowThreadProcessId
);
if ( !NT_SUCCESS(Status) ) {
LdrUnloadDll( ModuleHandle );
goto Cleanup;
}
}
hwndWowExec = b->hwndWowExec;
dwWowExecThreadId = BaseSrvGetWindowThreadProcessId( hwndWowExec,
&dwWowExecProcessId
);
//
// Process IDs recycle quickly also, so also save away the CSR_PROCESS
// SequenceNumber, which recycles much more slowly.
//
Status = CsrLockProcessByClientId((HANDLE)dwWowExecProcessId, &Process);
if ( !NT_SUCCESS(Status) ) {
KdPrint(("BaseSrvRegisterWowExec: CsrLockProcessByClientId(0x%x) fails, not registering WowExec.\n",
dwWowExecProcessId));
hwndWowExec = NULL;
goto Cleanup;
}
ulWowExecProcessSequenceNumber = Process->SequenceNumber;
CsrUnlockProcess(Process);
Cleanup:
RtlLeaveCriticalSection( &BaseSrvWOWCriticalSection );
return (ULONG)Status;
}
PBATRECORD
BaseSrvGetBatRecord(
IN HANDLE hConsole
)
{
PBATRECORD pBatRecord = BatRecordHead;
while (pBatRecord && pBatRecord->hConsole != hConsole)
pBatRecord = pBatRecord->BatRecordNext;
return pBatRecord;
}
PBATRECORD
BaseSrvAllocateAndAddBatRecord(
HANDLE hConsole
)
{
PCSR_THREAD t;
PBATRECORD pBatRecord;
if((pBatRecord = RtlAllocateHeap(RtlProcessHeap (),
MAKE_TAG( VDM_TAG ),
sizeof(BATRECORD))) == NULL)
return NULL;
t = CSR_SERVER_QUERYCLIENTTHREAD();
pBatRecord->hConsole = hConsole;
pBatRecord->SequenceNumber = t->Process->SequenceNumber;
pBatRecord->BatRecordNext = BatRecordHead;
BatRecordHead = pBatRecord;
return pBatRecord;
}
VOID
BaseSrvFreeAndRemoveBatRecord(
PBATRECORD pBatRecordToFree
)
{
PBATRECORD pBatRecord = BatRecordHead;
PBATRECORD pBatRecordLast = NULL;
while (pBatRecord && pBatRecord != pBatRecordToFree){
pBatRecordLast = pBatRecord;
pBatRecord = pBatRecord->BatRecordNext;
}
if (pBatRecord == NULL)
return;
if (pBatRecordLast)
pBatRecordLast->BatRecordNext = pBatRecord->BatRecordNext;
else
BatRecordHead = pBatRecord->BatRecordNext;
RtlFreeHeap ( RtlProcessHeap (), 0, pBatRecord);
return;
}
ULONG
BaseSrvGetVDMCurDirs(
IN OUT PCSR_API_MSG m,
IN OUT PCSR_REPLY_STATUS ReplyStatus
)
{
NTSTATUS Status;
PBASE_GET_SET_VDM_CUR_DIRS_MSG b = (PBASE_GET_SET_VDM_CUR_DIRS_MSG)&m->u.ApiMessageData;
PCONSOLERECORD pConsoleRecord;
Status = RtlEnterCriticalSection( &BaseSrvDOSCriticalSection );
ASSERT(NT_SUCCESS(Status));
Status = BaseSrvGetConsoleRecord(b->ConsoleHandle,&pConsoleRecord);
if (!NT_SUCCESS (Status)) {
RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
b->cchCurDirs = 0;
return ((ULONG)STATUS_INVALID_PARAMETER);
}
if (pConsoleRecord->lpszzCurDirs != NULL){
if (b->cchCurDirs < pConsoleRecord->cchCurDirs || b->lpszzCurDirs == NULL)
{
b->cchCurDirs = pConsoleRecord->cchCurDirs;
RtlLeaveCriticalSection(&BaseSrvDOSCriticalSection);
return ((ULONG)STATUS_INVALID_PARAMETER);
}
else {
RtlMoveMemory(b->lpszzCurDirs,
pConsoleRecord->lpszzCurDirs,
pConsoleRecord->cchCurDirs
);
// remove it immediately after the copy. This is done because
// the next command may be a WOW program(got tagged process handle
// as VDM command) and in that case we will return incorrect
//information:
// c:\>
// c:\>d:
// d:\>cd \foo
// d:\foo>dosapp
// d:\foo>c:
// c:\>wowapp
// d:\foo> -- this is wrong if we don't do the following stuff.
RtlFreeHeap(BaseSrvHeap, 0, pConsoleRecord->lpszzCurDirs);
pConsoleRecord->lpszzCurDirs = NULL;
b->cchCurDirs = pConsoleRecord->cchCurDirs;
pConsoleRecord->cchCurDirs = 0;
}
}
else {
b->cchCurDirs = 0;
}
RtlLeaveCriticalSection(&BaseSrvDOSCriticalSection);
return ((ULONG)STATUS_SUCCESS);
}
ULONG
BaseSrvCheckWOW(
IN PBASE_CHECKVDM_MSG b,
IN HANDLE UniqueProcessClientId
)
{
NTSTATUS Status;
HANDLE Handle,TargetHandle;
PWOWRECORD pWOWRecord;
INFORECORD InfoRecord;
USHORT Len;
LUID ClientAuthId;
DWORD dwThreadId, dwProcessId;
ULONG ulProcessSequenceNumber;
PCSR_PROCESS Process;
Status = RtlEnterCriticalSection( &BaseSrvWOWCriticalSection );
ASSERT( NT_SUCCESS( Status ) );
if ( WOWHead ) {
switch (WOWHead->VDMState & VDM_READY) {
case VDM_READY:
//
// Check if caller can start Win16 app in the shared WOW:
//
// The AuthenticationId of the client must match both
// the shared wow and the currently logged on interactive
// user.
//
Status = OkToRunInSharedWOW( UniqueProcessClientId,
&ClientAuthId
);
if (NT_SUCCESS(Status)) {
if (!RtlEqualLuid(&ClientAuthId, &WowAuthId)) {
Status = STATUS_ACCESS_DENIED;
}
}
if (!NT_SUCCESS(Status)) {
RtlLeaveCriticalSection( &BaseSrvWOWCriticalSection );
return ((ULONG)Status);
}
// Allocate a record for this wow task
pWOWRecord = BaseSrvAllocateWOWRecord();
if(pWOWRecord == NULL){
Status = STATUS_NO_MEMORY;
break;
}
InfoRecord.iTag = BINARY_TYPE_WIN16;
InfoRecord.pRecord.pWOWRecord = pWOWRecord;
if(BaseSrvCopyCommand (b,&InfoRecord) == FALSE){
BaseSrvFreeWOWRecord(pWOWRecord);
Status = STATUS_NO_MEMORY;
break;
}
Status = BaseSrvCreatePairWaitHandles (&Handle,&TargetHandle);
if (!NT_SUCCESS(Status) ){
BaseSrvFreeWOWRecord(pWOWRecord);
break;
}
else {
pWOWRecord->hWaitForParent = Handle;
pWOWRecord->hWaitForParentServer = TargetHandle;
b->WaitObjectForParent = TargetHandle;
}
b->VDMState = VDM_PRESENT_AND_READY;
b->iTask = pWOWRecord->iTask;
BaseSrvAddWOWRecord (pWOWRecord);
if (UserNotifyProcessCreate != NULL) {
(*UserNotifyProcessCreate)(pWOWRecord->iTask,
(DWORD)CSR_SERVER_QUERYCLIENTTHREAD()->ClientId.UniqueThread,
(DWORD)TargetHandle, 0x04);
}
if (hwndWowExec) {
//
// Check to see if hwndWowExec still belongs to
// the same thread/process ID before posting.
//
dwThreadId = BaseSrvGetWindowThreadProcessId(
hwndWowExec,
&dwProcessId
);
if (dwThreadId) {
Status = CsrLockProcessByClientId((HANDLE)dwProcessId, &Process);
} else {
Status = STATUS_UNSUCCESSFUL;
}
if ( NT_SUCCESS(Status) ) {
ulProcessSequenceNumber = Process->SequenceNumber;
CsrUnlockProcess(Process);
} else {
KdPrint(("BaseSrvCheckWOW: WowExec hwnd 0x%x not valid, shared WOW is gone.\n"));
// Force the comparison below to fail.
ulProcessSequenceNumber = ulWowExecProcessSequenceNumber + 1;
}
if (dwThreadId == dwWowExecThreadId &&
dwProcessId == dwWowExecProcessId &&
ulProcessSequenceNumber == ulWowExecProcessSequenceNumber) {
BaseSrvPostMessageA((HWND)hwndWowExec,
WM_WOWEXECSTARTAPP,
0, 0);
} else {
//
// Thread/process IDs don't match, so forget about this shared WOW.
//
if ( NT_SUCCESS(Status) ) {
KdPrint(("BaseSrvCheckWOW: Thread/Process IDs don't match, shared WOW is gone.\n"
"Saved PID 0x%x TID 0x%x PSN 0x%x, hwndWowExec (0x%x) maps to \n"
" PID 0x%x TID 0x%x PSN 0x%x.\n",
dwWowExecProcessId, dwWowExecThreadId, ulWowExecProcessSequenceNumber,
hwndWowExec,
dwProcessId, dwThreadId, ulProcessSequenceNumber));
}
//
// BaseSrvFreeWOWHead will zero hwndWowExec as well.
//
BaseSrvFreeWOWHead();
}
}
break;
default:
ASSERT(FALSE);
}
}
if (WOWHead == NULL) {
if (b->CmdLen > MAXIMUM_VDM_COMMAND_LENGTH) {
RtlLeaveCriticalSection( &BaseSrvWOWCriticalSection );
return ((ULONG)STATUS_INVALID_PARAMETER);
}
//
// Only the currently logged on interactive user can start the
// shared wow. Verify if the caller is such, and if it is
// store the Authentication Id of the client which identifies who
// is allowed to run wow apps in the default ntvdm-wow process.
//
//
// if needed, do a run-time link to UserTestTokenForInteractive,
// which is used to verify the client luid.
//
if (!UserTestTokenForInteractive) {
PVOID ModuleHandle;
UNICODE_STRING ModuleName;
ANSI_STRING ProcName;
RtlInitUnicodeString( &ModuleName, L"winsrv");
Status = LdrLoadDll(UNICODE_NULL,
NULL,
&ModuleName,
&ModuleHandle
);
if (!NT_SUCCESS(Status)) {
RtlLeaveCriticalSection( &BaseSrvWOWCriticalSection );
return (ULONG)Status;
}
RtlInitString( &ProcName, "_UserTestTokenForInteractive");
Status = LdrGetProcedureAddress(
ModuleHandle,
&ProcName,
0,
(PVOID *)&UserTestTokenForInteractive
);
if (!NT_SUCCESS(Status)) {
LdrUnloadDll(ModuleHandle);
RtlLeaveCriticalSection( &BaseSrvWOWCriticalSection );
return (ULONG)Status;
}
}
//
// If the caller isn't the currently logged on interactive user,
// OkToRunInSharedWOW will fail with access denied.
//
Status = OkToRunInSharedWOW(
UniqueProcessClientId,
&ClientAuthId
);
if (!NT_SUCCESS(Status)) {
RtlLeaveCriticalSection( &BaseSrvWOWCriticalSection );
return ((ULONG)Status);
}
//
// Store the Autherntication Id since this now is the currently
// logged on interactive user.
//
WowAuthId = ClientAuthId;
WOWHead = BaseSrvAllocateWOWHead();
if (WOWHead == NULL) {
Status = STATUS_NO_MEMORY ;
}
else {
if((WOWHead->WOWRecord = BaseSrvAllocateWOWRecord()) == NULL) {
BaseSrvFreeWOWHead();
RtlLeaveCriticalSection( &BaseSrvWOWCriticalSection );
return ((ULONG) STATUS_NO_MEMORY );
}
InfoRecord.iTag = BINARY_TYPE_WIN16;
InfoRecord.pRecord.pWOWRecord = WOWHead->WOWRecord;
if(!BaseSrvCopyCommand (b, &InfoRecord)){
BaseSrvFreeWOWHead();
RtlLeaveCriticalSection( &BaseSrvWOWCriticalSection );
return ((ULONG) STATUS_NO_MEMORY);
}
WOWHead->VDMState = VDM_READY;
b->VDMState = VDM_NOT_PRESENT;
b->iTask = WOWHead->WOWRecord->iTask;
Status = STATUS_SUCCESS;
}
}
RtlLeaveCriticalSection( &BaseSrvWOWCriticalSection );
return ((ULONG)Status);
}
NTSTATUS
OkToRunInSharedWOW(
IN HANDLE UniqueProcessClientId,
OUT PLUID pAuthenticationId
)
/*
* Verifies that the client thread is in the currently logged on interactive
* user session or is SYSTEM impersonating a thread in the currently logged
* on interactive session.
*
* Also retrieves the the authentication ID (logon session Id) for the
* caller.
*
* if the clients TokenGroups is not part of the currently logged on
* interactive user session STATUS_ACCESS_DENIED is returned.
*
*/
{
NTSTATUS Status;
HANDLE Token;
HANDLE ImpersonationToken;
PCSR_PROCESS Process;
PCSR_THREAD t;
Status = CsrLockProcessByClientId(UniqueProcessClientId,&Process);
if (!NT_SUCCESS(Status))
return Status;
//
// Open a token for the client
//
Status = NtOpenProcessToken(Process->ProcessHandle,
TOKEN_QUERY,
&Token
);
if (!NT_SUCCESS(Status)) {
CsrUnlockProcess(Process);
return Status;
}
//
// Verify the token Group, and see if client's token is the currently
// logged on interactive user. If this fails and it is System
// impersonating, then check if the client being impersonated is the
// currently logged on interactive user.
//
Status = (*UserTestTokenForInteractive)(Token, pAuthenticationId);
if (!NT_SUCCESS(Status)) {
if (IsClientSystem(Token)) {
// get impersonation token
t = CSR_SERVER_QUERYCLIENTTHREAD();
Status = NtOpenThreadToken(t->ThreadHandle,
TOKEN_QUERY,
TRUE,
&ImpersonationToken);
if (NT_SUCCESS(Status)) {
Status = (*UserTestTokenForInteractive)(ImpersonationToken,
pAuthenticationId
);
NtClose(ImpersonationToken);
}
else {
Status = STATUS_ACCESS_DENIED;
}
}
}
NtClose(Token);
CsrUnlockProcess(Process);
return(Status);
}
ULONG
BaseSrvCheckDOS(
IN PBASE_CHECKVDM_MSG b
)
{
NTSTATUS Status;
PCONSOLERECORD pConsoleRecord = NULL;
HANDLE Handle,TargetHandle;
PDOSRECORD pDOSRecord;
INFORECORD InfoRecord;
Status = RtlEnterCriticalSection( &BaseSrvDOSCriticalSection );
ASSERT( NT_SUCCESS( Status ) );
Status = BaseSrvGetConsoleRecord(b->ConsoleHandle,&pConsoleRecord);
if ( NT_SUCCESS(Status) ) {
pDOSRecord = pConsoleRecord->DOSRecord;
ASSERT (pDOSRecord != NULL);
switch( pDOSRecord->VDMState){
case VDM_READY:
case VDM_HAS_RETURNED_ERROR_CODE:
InfoRecord.iTag = BINARY_TYPE_DOS;
InfoRecord.pRecord.pDOSRecord = pDOSRecord;
if(!BaseSrvCopyCommand (b,&InfoRecord)) {
Status = STATUS_NO_MEMORY;
break;
}
if (!NT_SUCCESS ( Status = BaseSrvDupStandardHandles (
pConsoleRecord->hVDM,
pDOSRecord)))
break;
Status = BaseSrvCreatePairWaitHandles (&Handle,&TargetHandle);
if (!NT_SUCCESS(Status) ){
BaseSrvCloseStandardHandles (pConsoleRecord->hVDM, pDOSRecord);
break;
}
else {
b->WaitObjectForParent = TargetHandle;
pDOSRecord->hWaitForParent = TargetHandle;
pDOSRecord->hWaitForParentDup = Handle;
}
pDOSRecord->VDMState = VDM_TO_TAKE_A_COMMAND;
b->VDMState = VDM_PRESENT_AND_READY;
if(pConsoleRecord->hWaitForVDMDup)
NtSetEvent (pConsoleRecord->hWaitForVDMDup,NULL);
break;
case VDM_BUSY:
case VDM_TO_TAKE_A_COMMAND:
if((pDOSRecord = BaseSrvAllocateDOSRecord()) == NULL){
Status = STATUS_NO_MEMORY ;
break;
}
InfoRecord.iTag = BINARY_TYPE_DOS;
InfoRecord.pRecord.pDOSRecord = pDOSRecord;
if(!BaseSrvCopyCommand(b, &InfoRecord)){
Status = STATUS_NO_MEMORY ;
BaseSrvFreeDOSRecord(pDOSRecord);
break;
}
Status = BaseSrvCreatePairWaitHandles(&Handle,&TargetHandle);
if (!NT_SUCCESS(Status) ){
BaseSrvFreeDOSRecord(pDOSRecord);
break;
}
else {
b->WaitObjectForParent = TargetHandle;
pDOSRecord->hWaitForParentDup = Handle;
pDOSRecord->hWaitForParent = TargetHandle;
}
Status = BaseSrvDupStandardHandles(pConsoleRecord->hVDM, pDOSRecord);
if (!NT_SUCCESS(Status)) {
BaseSrvClosePairWaitHandles (pDOSRecord);
BaseSrvFreeDOSRecord(pDOSRecord);
break;
}
BaseSrvAddDOSRecord(pConsoleRecord,pDOSRecord);
b->VDMState = VDM_PRESENT_AND_READY;
if (pConsoleRecord->nReEntrancy) {
if(pConsoleRecord->hWaitForVDMDup)
NtSetEvent (pConsoleRecord->hWaitForVDMDup,NULL);
}
pDOSRecord->VDMState = VDM_TO_TAKE_A_COMMAND;
break;
default:
ASSERT(FALSE);
}
}
if (pConsoleRecord == NULL) {
pConsoleRecord = BaseSrvAllocateConsoleRecord ();
if (pConsoleRecord == NULL)
Status = STATUS_NO_MEMORY ;
else {
pConsoleRecord->DOSRecord = BaseSrvAllocateDOSRecord();
if(!pConsoleRecord->DOSRecord) {
BaseSrvFreeConsoleRecord(pConsoleRecord);
RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
return (ULONG)STATUS_NO_MEMORY;
}
InfoRecord.iTag = b->BinaryType;
InfoRecord.pRecord.pDOSRecord = pConsoleRecord->DOSRecord;
if(!BaseSrvCopyCommand(b, &InfoRecord)) {
BaseSrvFreeConsoleRecord(pConsoleRecord);
RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
return (ULONG)STATUS_NO_MEMORY;
}
pConsoleRecord->hConsole = b->ConsoleHandle;
// if no console for this ntvdm
// get a temporary session ID and pass it to the client
if (!pConsoleRecord->hConsole) {
b->iTask = pConsoleRecord->DosSesId = GetNextDosSesId();
}
else {
b->iTask = pConsoleRecord->DosSesId = 0;
}
pConsoleRecord->DOSRecord->VDMState = VDM_TO_TAKE_A_COMMAND;
BaseSrvAddConsoleRecord(pConsoleRecord);
b->VDMState = VDM_NOT_PRESENT;
Status = STATUS_SUCCESS;
}
}
RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
return Status;
}
BOOL
BaseSrvCopyCommand(
PBASE_CHECKVDM_MSG b,
PINFORECORD pInfoRecord
)
{
PVDMINFO VDMInfo;
if((VDMInfo = RtlAllocateHeap(RtlProcessHeap (), MAKE_TAG( VDM_TAG ),sizeof(VDMINFO))) == NULL){
return FALSE;
}
VDMInfo->CmdLine = RtlAllocateHeap(RtlProcessHeap (), MAKE_TAG( VDM_TAG ),b->CmdLen);
if (b->AppLen) {
VDMInfo->AppName = RtlAllocateHeap(RtlProcessHeap (), MAKE_TAG( VDM_TAG ),b->AppLen);
}
else
VDMInfo->AppName = NULL;
if (b->PifLen)
VDMInfo->PifFile = RtlAllocateHeap(RtlProcessHeap (), MAKE_TAG( VDM_TAG ),b->PifLen);
else
VDMInfo->PifFile = NULL;
if (b->CurDirectoryLen)
VDMInfo->CurDirectory = RtlAllocateHeap(RtlProcessHeap (), MAKE_TAG( VDM_TAG ),b->CurDirectoryLen);
else
VDMInfo->CurDirectory = NULL;
if (b->EnvLen)
VDMInfo->Enviornment = RtlAllocateHeap(RtlProcessHeap (), MAKE_TAG( VDM_TAG ),b->EnvLen);
else
VDMInfo->Enviornment = NULL;
if (b->DesktopLen)
VDMInfo->Desktop = RtlAllocateHeap(RtlProcessHeap (), MAKE_TAG( VDM_TAG ),b->DesktopLen);
else
VDMInfo->Desktop = NULL;
if (b->TitleLen)
VDMInfo->Title = RtlAllocateHeap(RtlProcessHeap (), MAKE_TAG( VDM_TAG ),b->TitleLen);
else
VDMInfo->Title = NULL;
if (b->ReservedLen)
VDMInfo->Reserved = RtlAllocateHeap(RtlProcessHeap (), MAKE_TAG( VDM_TAG ),b->ReservedLen);
else
VDMInfo->Reserved = NULL;
// check that all the allocations were successful
if (VDMInfo->CmdLine == NULL ||
(b->AppLen && VDMInfo->AppName == NULL) ||
(b->PifLen && VDMInfo->PifFile == NULL) ||
(b->CurDirectoryLen && VDMInfo->CurDirectory == NULL) ||
(b->EnvLen && VDMInfo->Enviornment == NULL) ||
(b->DesktopLen && VDMInfo->Desktop == NULL )||
(b->ReservedLen && VDMInfo->Reserved == NULL )||
(b->TitleLen && VDMInfo->Title == NULL)) {
RtlFreeHeap ( RtlProcessHeap (), 0, VDMInfo);
if (VDMInfo->CmdLine != NULL)
RtlFreeHeap ( RtlProcessHeap (), 0, VDMInfo->CmdLine);
if (VDMInfo->AppName != NULL)
RtlFreeHeap ( RtlProcessHeap (), 0, VDMInfo->AppName);
if (VDMInfo->PifFile != NULL)
RtlFreeHeap ( RtlProcessHeap (), 0, VDMInfo->PifFile);
if (VDMInfo->Enviornment != NULL)
RtlFreeHeap ( RtlProcessHeap (), 0, VDMInfo->Enviornment);
if (VDMInfo->CurDirectory != NULL)
RtlFreeHeap ( RtlProcessHeap (), 0, VDMInfo->CurDirectory);
if (VDMInfo->Desktop != NULL)
RtlFreeHeap ( RtlProcessHeap (), 0, VDMInfo->Desktop);
if (VDMInfo->Title != NULL)
RtlFreeHeap ( RtlProcessHeap (), 0, VDMInfo->Title);
if (VDMInfo->Reserved != NULL)
RtlFreeHeap ( RtlProcessHeap (), 0, VDMInfo->Reserved);
return FALSE;
}
RtlMoveMemory(VDMInfo->CmdLine,
b->CmdLine,
b->CmdLen);
VDMInfo->CmdSize = b->CmdLen;
if (b->AppLen) {
RtlMoveMemory(VDMInfo->AppName,
b->AppName,
b->AppLen);
}
VDMInfo->AppLen = b->AppLen;
if (b->PifLen) {
RtlMoveMemory(VDMInfo->PifFile,
b->PifFile,
b->PifLen);
}
VDMInfo->PifLen = b->PifLen;
if (b->CurDirectoryLen) {
RtlMoveMemory(VDMInfo->CurDirectory,
b->CurDirectory,
b->CurDirectoryLen);
}
VDMInfo->CurDirectoryLen = b->CurDirectoryLen;
if (b->EnvLen) {
RtlMoveMemory(VDMInfo->Enviornment,
b->Env,
b->EnvLen);
}
VDMInfo->EnviornmentSize = b->EnvLen;
if (b->DesktopLen) {
RtlMoveMemory(VDMInfo->Desktop,
b->Desktop,
b->DesktopLen);
}
VDMInfo->DesktopLen = b->DesktopLen;
if (b->TitleLen) {
RtlMoveMemory(VDMInfo->Title,
b->Title,
b->TitleLen);
}
VDMInfo->TitleLen = b->TitleLen;
if (b->ReservedLen) {
RtlMoveMemory(VDMInfo->Reserved,
b->Reserved,
b->ReservedLen);
}
VDMInfo->ReservedLen = b->ReservedLen;
if (b->StartupInfo) {
RtlMoveMemory(&VDMInfo->StartupInfo,
b->StartupInfo,
sizeof (STARTUPINFOA));
VDMInfo->VDMState = STARTUP_INFO_RETURNED;
}
else
VDMInfo->VDMState = 0;
VDMInfo->dwCreationFlags = b->dwCreationFlags;
VDMInfo->CurDrive = b->CurDrive;
VDMInfo->CodePage = b->CodePage;
pInfoRecord->pRecord.pWOWRecord->lpVDMInfo = VDMInfo;
VDMInfo->StdIn = VDMInfo->StdOut = VDMInfo->StdErr = 0;
if(pInfoRecord->iTag == BINARY_TYPE_DOS) {
VDMInfo->StdIn = b->StdIn;
VDMInfo->StdOut = b->StdOut;
VDMInfo->StdErr = b->StdErr;
}
else if (pInfoRecord->iTag == BINARY_TYPE_WIN16) {
pInfoRecord->pRecord.pWOWRecord->fDispatched = FALSE;
}
// else if (pInfoRecord->iTag == BINARY_TYPE_SEPWOW)
return TRUE;
}
ULONG
BaseSrvUpdateWOWEntry(
PBASE_UPDATE_VDM_ENTRY_MSG b
)
{
NTSTATUS Status;
PWOWRECORD pWOWRecord;
HANDLE Handle,TargetHandle;
Status = RtlEnterCriticalSection( &BaseSrvWOWCriticalSection );
ASSERT( NT_SUCCESS( Status ) );
Status = BaseSrvGetWOWRecord(b->iTask,&pWOWRecord);
if ( NT_SUCCESS(Status) ) {
switch ( b->EntryIndex ){
case UPDATE_VDM_PROCESS_HANDLE:
Status = STATUS_SUCCESS;
break;
case UPDATE_VDM_UNDO_CREATION:
if( b->VDMCreationState & VDM_BEING_REUSED ||
b->VDMCreationState & VDM_FULLY_CREATED){
NtClose(pWOWRecord->hWaitForParent);
pWOWRecord->hWaitForParent = 0;
}
if( b->VDMCreationState & VDM_PARTIALLY_CREATED ||
b->VDMCreationState & VDM_FULLY_CREATED){
BaseSrvRemoveWOWRecord (pWOWRecord);
BaseSrvFreeWOWRecord (pWOWRecord);
if (WOWHead->WOWRecord == NULL)
BaseSrvFreeWOWHead();
}
break;
default:
ASSERT(FALSE);
}
}
RtlLeaveCriticalSection( &BaseSrvWOWCriticalSection );
if (!NT_SUCCESS(Status) )
return Status;
switch ( b->EntryIndex ){
case UPDATE_VDM_PROCESS_HANDLE:
Status = BaseSrvCreatePairWaitHandles (&Handle,&TargetHandle);
if (!NT_SUCCESS(Status) ){
return Status;
}
else {
pWOWRecord->hWaitForParent = Handle;
pWOWRecord->hWaitForParentServer = TargetHandle;
b->WaitObjectForParent = TargetHandle;
if (UserNotifyProcessCreate != NULL) {
(*UserNotifyProcessCreate)(pWOWRecord->iTask,
(DWORD)CSR_SERVER_QUERYCLIENTTHREAD()->ClientId.UniqueThread,
(DWORD)TargetHandle, 0x04);
}
return STATUS_SUCCESS;
}
case UPDATE_VDM_UNDO_CREATION:
case UPDATE_VDM_HOOKED_CTRLC:
return STATUS_SUCCESS;
default:
ASSERT(FALSE);
}
}
ULONG
BaseSrvUpdateDOSEntry(
PBASE_UPDATE_VDM_ENTRY_MSG b
)
{
NTSTATUS Status;
PDOSRECORD pDOSRecord;
PCONSOLERECORD pConsoleRecord = NULL;
HANDLE Handle,TargetHandle;
PCSR_THREAD t;
Status = RtlEnterCriticalSection( &BaseSrvDOSCriticalSection );
ASSERT( NT_SUCCESS( Status ) );
if (b->iTask)
Status = GetConsoleRecordDosSesId(b->iTask,&pConsoleRecord);
else
Status = BaseSrvGetConsoleRecord(b->ConsoleHandle,&pConsoleRecord);
if ( NT_SUCCESS(Status) ) {
pDOSRecord = pConsoleRecord->DOSRecord;
switch ( b->EntryIndex ){
case UPDATE_VDM_PROCESS_HANDLE:
t = CSR_SERVER_QUERYCLIENTTHREAD();
Status = NtDuplicateObject (
t->Process->ProcessHandle,
b->VDMProcessHandle,
NtCurrentProcess(),
&pConsoleRecord->hVDM,
(ACCESS_MASK)NULL,
FALSE,
DUPLICATE_SAME_ACCESS
);
break;
case UPDATE_VDM_UNDO_CREATION:
if( b->VDMCreationState & VDM_BEING_REUSED ||
b->VDMCreationState & VDM_FULLY_CREATED){
NtClose(pDOSRecord->hWaitForParentDup);
pDOSRecord->hWaitForParentDup = 0;
}
if( b->VDMCreationState & VDM_PARTIALLY_CREATED ||
b->VDMCreationState & VDM_FULLY_CREATED){
BaseSrvRemoveDOSRecord (pConsoleRecord,pDOSRecord);
BaseSrvFreeDOSRecord (pDOSRecord);
if (pConsoleRecord->DOSRecord == NULL) {
if (b->VDMCreationState & VDM_FULLY_CREATED) {
if (pConsoleRecord->hVDM)
NtClose(pConsoleRecord->hVDM);
}
BaseSrvFreeConsoleRecord(pConsoleRecord);
}
}
break;
case UPDATE_VDM_HOOKED_CTRLC:
break;
default:
ASSERT(FALSE);
}
}
RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
if (!NT_SUCCESS(Status) )
return Status;
switch ( b->EntryIndex ){
case UPDATE_VDM_PROCESS_HANDLE:
// williamh, Oct 24, 1996.
// if the ntvdm is runnig on a new console, do NOT subsititue
// the given process handle with event. The caller(CreateProcess)
// will get the real process handle and so does the application
// who calls CreateProcess. When it is time for the application
// to call GetExitCodeProcess, the client side will return the
// right thing(on the server side, we have nothing because
// console and dos record are gone).
//
if (!pConsoleRecord->DosSesId && b->BinaryType == BINARY_TYPE_DOS) {
Status = BaseSrvCreatePairWaitHandles (&Handle,&TargetHandle);
if (!NT_SUCCESS(Status) ){
return Status;
}
else {
if (!NT_SUCCESS ( Status = BaseSrvDupStandardHandles (
pConsoleRecord->hVDM,
pDOSRecord))){
BaseSrvClosePairWaitHandles (pDOSRecord);
return Status;
}
pDOSRecord->hWaitForParent = TargetHandle;
pDOSRecord->hWaitForParentDup = Handle;
b->WaitObjectForParent = TargetHandle;
}
}
else {
pDOSRecord->hWaitForParent = NULL;
pDOSRecord->hWaitForParentDup = NULL;
b->WaitObjectForParent = NULL;
}
return STATUS_SUCCESS;
case UPDATE_VDM_UNDO_CREATION:
case UPDATE_VDM_HOOKED_CTRLC:
return STATUS_SUCCESS;
default:
ASSERT(FALSE);
}
}
PWOWRECORD
BaseSrvCheckAvailableWOWCommand(
)
{
PWOWRECORD pWOWRecord;
if(WOWHead == NULL)
return NULL;
pWOWRecord = WOWHead->WOWRecord;
while(pWOWRecord){
if(pWOWRecord->fDispatched == FALSE)
break;
else
pWOWRecord = pWOWRecord->WOWRecordNext;
}
return pWOWRecord;
}
ULONG
BaseSrvExitWOWTask(
PBASE_EXIT_VDM_MSG b,
HANDLE ProcessId
)
{
NTSTATUS Status;
PCSR_PROCESS Process;
ULONG ThisSequenceNumber;
Status = CsrLockProcessByClientId(ProcessId, &Process);
if ( !NT_SUCCESS(Status) )
return Status;
ThisSequenceNumber = Process->SequenceNumber;
CsrUnlockProcess(Process);
Status = RtlEnterCriticalSection( &BaseSrvWOWCriticalSection );
ASSERT( NT_SUCCESS( Status ) );
if (WOWHead && WOWHead->SequenceNumber == ThisSequenceNumber) {
BaseSrvRemoveWOWRecordByITask(b->iWowTask);
}
RtlLeaveCriticalSection( &BaseSrvWOWCriticalSection );
return Status;
}
ULONG
BaseSrvExitDOSTask(
PBASE_EXIT_VDM_MSG b
)
{
NTSTATUS Status;
PDOSRECORD pDOSRecord;
PCONSOLERECORD pConsoleRecord = NULL;
Status = RtlEnterCriticalSection( &BaseSrvDOSCriticalSection );
ASSERT( NT_SUCCESS( Status ) );
Status = BaseSrvGetConsoleRecord(b->ConsoleHandle,&pConsoleRecord);
if (!NT_SUCCESS (Status)) {
RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
return ((ULONG)STATUS_INVALID_PARAMETER);
}
if (pConsoleRecord->hWaitForVDMDup){
NtClose(pConsoleRecord->hWaitForVDMDup);
pConsoleRecord->hWaitForVDMDup =0;
b->WaitObjectForVDM = pConsoleRecord->hWaitForVDM;
}
pDOSRecord = pConsoleRecord->DOSRecord;
while (pDOSRecord) {
if (pDOSRecord->hWaitForParentDup) {
NtSetEvent (pDOSRecord->hWaitForParentDup,NULL);
NtClose (pDOSRecord->hWaitForParentDup);
pDOSRecord->hWaitForParentDup = 0;
}
pDOSRecord = pDOSRecord->DOSRecordNext;
}
NtClose(pConsoleRecord->hVDM);
BaseSrvFreeConsoleRecord (pConsoleRecord);
RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
return Status;
}
VOID
BaseSrvRemoveWOWRecordByITask(
IN ULONG iWowTask
)
{
PWOWRECORD pWOWRecordLast = NULL, pWOWRecord;
if (WOWHead == NULL)
return;
pWOWRecord = WOWHead->WOWRecord;
if(iWowTask != (ULONG)-1) {
// Find the right WOW record and free it.
while(pWOWRecord){
if(pWOWRecord->iTask == iWowTask){
if(pWOWRecordLast == NULL)
WOWHead->WOWRecord = pWOWRecord->WOWRecordNext;
else
pWOWRecordLast->WOWRecordNext = pWOWRecord->WOWRecordNext;
NtSetEvent (pWOWRecord->hWaitForParent,NULL);
NtClose (pWOWRecord->hWaitForParent);
pWOWRecord->hWaitForParent = 0;
BaseSrvFreeWOWRecord(pWOWRecord);
return;
}
pWOWRecordLast = pWOWRecord;
pWOWRecord = pWOWRecord->WOWRecordNext;
}
}
else{
BaseSrvFreeWOWHead();
}
return;
}
ULONG
BaseSrvGetWOWRecord(
ULONG iTask,
OUT PWOWRECORD *pRecord
)
{
PWOWRECORD pWOWRecord;
if(WOWHead == NULL)
return ((ULONG)STATUS_INVALID_PARAMETER);
pWOWRecord = WOWHead->WOWRecord;
while (pWOWRecord){
if (pWOWRecord->iTask == iTask){
*pRecord = pWOWRecord;
return STATUS_SUCCESS;
}
else
pWOWRecord = pWOWRecord->WOWRecordNext;
}
return ((ULONG)STATUS_INVALID_PARAMETER);
}
ULONG
BaseSrvGetVDMExitCode(
IN OUT PCSR_API_MSG m,
IN OUT PCSR_REPLY_STATUS ReplyStatus
)
{
NTSTATUS Status;
PCONSOLERECORD pConsoleRecord = NULL;
PDOSRECORD pDOSRecord;
PBASE_GET_VDM_EXIT_CODE_MSG b = (PBASE_GET_VDM_EXIT_CODE_MSG)&m->u.ApiMessageData;
if(b->ConsoleHandle == (HANDLE)-1){
b->ExitCode = 0;
}
else{
Status = RtlEnterCriticalSection( &BaseSrvDOSCriticalSection );
ASSERT( NT_SUCCESS( Status ) );
Status = BaseSrvGetConsoleRecord (b->ConsoleHandle,&pConsoleRecord);
if (!NT_SUCCESS(Status)){
b->ExitCode = 0;
RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
return STATUS_SUCCESS;
}
pDOSRecord = pConsoleRecord->DOSRecord;
while (pDOSRecord) {
// sudeepb 05-Oct-1992
// fix for the change markl has made for tagging VDM handles
if (pDOSRecord->hWaitForParent == (HANDLE)((DWORD)b->hParent & ~0x1)) {
if (pDOSRecord->VDMState == VDM_HAS_RETURNED_ERROR_CODE){
b->ExitCode = pDOSRecord->ErrorCode;
if (pDOSRecord == pConsoleRecord->DOSRecord &&
pDOSRecord->DOSRecordNext == NULL)
{
pDOSRecord->VDMState = VDM_READY;
pDOSRecord->hWaitForParent = 0;
}
else {
BaseSrvRemoveDOSRecord (pConsoleRecord,pDOSRecord);
BaseSrvFreeDOSRecord(pDOSRecord);
}
}
else {
if (pDOSRecord->VDMState == VDM_READY)
b->ExitCode = pDOSRecord->ErrorCode;
else
b->ExitCode = STILL_ACTIVE;
}
break;
}
else
pDOSRecord = pDOSRecord->DOSRecordNext;
}
if (pDOSRecord == NULL)
b->ExitCode = 0;
RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
}
return STATUS_SUCCESS;
}
ULONG BaseSrvDupStandardHandles(
IN HANDLE pVDMProc,
IN PDOSRECORD pDOSRecord
)
{
NTSTATUS Status;
HANDLE pSrcProc;
HANDLE StdOutTemp;
PCSR_THREAD t;
PVDMINFO pVDMInfo = pDOSRecord->lpVDMInfo;
t = CSR_SERVER_QUERYCLIENTTHREAD();
pSrcProc = t->Process->ProcessHandle;
if (pVDMInfo->StdIn){
Status = NtDuplicateObject (
pSrcProc,
pVDMInfo->StdIn,
pVDMProc,
&pVDMInfo->StdIn,
(ACCESS_MASK)NULL,
OBJ_INHERIT,
DUPLICATE_SAME_ACCESS
);
if (!NT_SUCCESS (Status))
return Status;
}
if (pVDMInfo->StdOut){
StdOutTemp = pVDMInfo->StdOut;
Status = NtDuplicateObject (
pSrcProc,
pVDMInfo->StdOut,
pVDMProc,
&pVDMInfo->StdOut,
(ACCESS_MASK)NULL,
OBJ_INHERIT,
DUPLICATE_SAME_ACCESS
);
if (!NT_SUCCESS (Status))
return Status;
}
if (pVDMInfo->StdErr){
if(pVDMInfo->StdErr != StdOutTemp){
Status = NtDuplicateObject (
pSrcProc,
pVDMInfo->StdErr,
pVDMProc,
&pVDMInfo->StdErr,
(ACCESS_MASK)NULL,
OBJ_INHERIT,
DUPLICATE_SAME_ACCESS
);
if (!NT_SUCCESS (Status))
return Status;
}
else
pVDMInfo->StdErr = pVDMInfo->StdOut;
}
return STATUS_SUCCESS;
}
// Generates a DosSesId which is unique and nonzero
ULONG GetNextDosSesId(VOID)
{
static BOOLEAN bWrap = FALSE;
static ULONG NextSesId=1;
ULONG ul;
PCONSOLERECORD pConsoleHead;
pConsoleHead = DOSHead;
ul = NextSesId;
if (bWrap) {
while (pConsoleHead) {
if (!pConsoleHead->hConsole && pConsoleHead->DosSesId == ul)
{
pConsoleHead = DOSHead;
ul++;
if (!ul) { // never use zero
bWrap = TRUE;
ul++;
}
}
else {
pConsoleHead = pConsoleHead->Next;
}
}
}
NextSesId = ul + 1;
if (!NextSesId) { // never use zero
bWrap = TRUE;
NextSesId++;
}
return ul;
}
NTSTATUS BaseSrvGetConsoleRecord (
IN HANDLE hConsole,
IN OUT PCONSOLERECORD *pConsoleRecord
)
{
PCONSOLERECORD pConsoleHead;
pConsoleHead = DOSHead;
if (hConsole) {
while (pConsoleHead) {
if (pConsoleHead->hConsole == hConsole){
*pConsoleRecord = pConsoleHead;
return STATUS_SUCCESS;
}
else
pConsoleHead = pConsoleHead->Next;
}
}
return STATUS_INVALID_PARAMETER;
}
NTSTATUS
GetConsoleRecordDosSesId (
IN ULONG DosSesId,
IN OUT PCONSOLERECORD *pConsoleRecord
)
{
PCONSOLERECORD pConsoleHead;
if (!DosSesId)
return STATUS_INVALID_PARAMETER;
pConsoleHead = DOSHead;
while (pConsoleHead) {
if (!pConsoleHead->hConsole &&
pConsoleHead->DosSesId == DosSesId)
{
*pConsoleRecord = pConsoleHead;
return STATUS_SUCCESS;
}
else
pConsoleHead = pConsoleHead->Next;
}
return STATUS_INVALID_PARAMETER;
}
PWOWHEAD BaseSrvAllocateWOWHead (
VOID
)
{
PWOWHEAD pWOWHead;
if((pWOWHead = RtlAllocateHeap ( RtlProcessHeap (), MAKE_TAG( VDM_TAG ),
sizeof (WOWHEAD))) == NULL)
return NULL;
RtlFillMemory ((PVOID)pWOWHead,sizeof(WOWHEAD),'\0');
return pWOWHead;
}
VOID BaseSrvFreeWOWHead (
VOID
)
{
PWOWRECORD pWOWRecord, pWOWRecordLast;
if (WOWHead == NULL)
return;
//
// Free all wow records and wake their parents
//
pWOWRecord = WOWHead->WOWRecord;
while(pWOWRecord){
pWOWRecordLast = pWOWRecord->WOWRecordNext;
NtSetEvent (pWOWRecord->hWaitForParent,NULL);
NtClose (pWOWRecord->hWaitForParent);
pWOWRecord->hWaitForParent = 0;
BaseSrvFreeWOWRecord(pWOWRecord);
pWOWRecord = pWOWRecordLast;
}
RtlFreeHeap(RtlProcessHeap (), 0, WOWHead);
WOWHead = NULL;
WowAuthId = RtlConvertLongToLuid(-1);
hwndWowExec = 0;
}
PWOWRECORD
BaseSrvAllocateWOWRecord(
VOID
)
{
register PWOWRECORD WOWRecord;
WOWRecord = RtlAllocateHeap ( RtlProcessHeap (), MAKE_TAG( VDM_TAG ), sizeof (WOWRECORD));
if (WOWRecord == NULL)
return NULL;
RtlFillMemory ((PVOID)WOWRecord,sizeof(WOWRECORD),'\0');
// if too many tasks, error out.
if ((WOWRecord->iTask = BaseSrvGetWOWTaskId()) == WOWMAXID) {
RtlFreeHeap(RtlProcessHeap(), 0, WOWRecord);
return NULL;
}
else
return WOWRecord;
}
VOID BaseSrvFreeWOWRecord (
PWOWRECORD pWOWRecord
)
{
if (pWOWRecord == NULL)
return;
BaseSrvFreeVDMInfo (pWOWRecord->lpVDMInfo);
RtlFreeHeap(RtlProcessHeap (), 0, pWOWRecord);
}
VOID BaseSrvAddWOWRecord (
PWOWRECORD pWOWRecord
)
{
PWOWRECORD WOWRecordCurrent,WOWRecordLast;
// First WOW app runs first, so add the new ones at the end
if(WOWHead->WOWRecord == NULL){
WOWHead->WOWRecord = pWOWRecord;
return;
}
WOWRecordCurrent = WOWHead->WOWRecord;
while (WOWRecordCurrent){
WOWRecordLast = WOWRecordCurrent;
WOWRecordCurrent = WOWRecordCurrent->WOWRecordNext;
}
WOWRecordLast->WOWRecordNext = pWOWRecord;
return;
}
VOID BaseSrvRemoveWOWRecord (
PWOWRECORD pWOWRecord
)
{
PWOWRECORD WOWRecordCurrent,WOWRecordLast = NULL;
if(WOWHead == NULL)
return;
if(WOWHead->WOWRecord == NULL)
return;
if(WOWHead->WOWRecord == pWOWRecord){
WOWHead->WOWRecord = pWOWRecord->WOWRecordNext;
return;
}
WOWRecordLast = WOWHead->WOWRecord;
WOWRecordCurrent = WOWRecordLast->WOWRecordNext;
while (WOWRecordCurrent && WOWRecordCurrent != pWOWRecord){
WOWRecordLast = WOWRecordCurrent;
WOWRecordCurrent = WOWRecordCurrent->WOWRecordNext;
}
if (WOWRecordCurrent != NULL)
WOWRecordLast->WOWRecordNext = pWOWRecord->WOWRecordNext;
return;
}
PCONSOLERECORD BaseSrvAllocateConsoleRecord (
VOID
)
{
PCONSOLERECORD pConsoleRecord;
if((pConsoleRecord = RtlAllocateHeap ( RtlProcessHeap (), MAKE_TAG( VDM_TAG ),
sizeof (CONSOLERECORD))) == NULL)
return NULL;
pConsoleRecord->hConsole = 0;
pConsoleRecord->hVDM = 0;
pConsoleRecord->SequenceNumber = 0;
pConsoleRecord->DosSesId = 0;
pConsoleRecord->DOSRecord = 0;
pConsoleRecord->hWaitForVDM = 0;
pConsoleRecord->hWaitForVDMDup = 0;
pConsoleRecord->nReEntrancy = 0;
pConsoleRecord->Next = NULL;
pConsoleRecord->cchCurDirs = 0;
pConsoleRecord->lpszzCurDirs = NULL;
return pConsoleRecord;
}
VOID BaseSrvFreeConsoleRecord (
PCONSOLERECORD pConsoleRecord
)
{
PDOSRECORD pDOSRecord;
if (pConsoleRecord == NULL)
return;
while (pDOSRecord = pConsoleRecord->DOSRecord){
pConsoleRecord->DOSRecord = pDOSRecord->DOSRecordNext;
BaseSrvFreeDOSRecord (pDOSRecord);
}
if (pConsoleRecord->lpszzCurDirs)
RtlFreeHeap(BaseSrvHeap, 0, pConsoleRecord->lpszzCurDirs);
BaseSrvRemoveConsoleRecord (pConsoleRecord);
RtlFreeHeap (RtlProcessHeap (), 0, pConsoleRecord );
}
VOID BaseSrvRemoveConsoleRecord (
PCONSOLERECORD pConsoleRecord
)
{
PCONSOLERECORD pTempLast,pTemp;
if (DOSHead == NULL)
return;
if(DOSHead == pConsoleRecord) {
DOSHead = pConsoleRecord->Next;
return;
}
pTempLast = DOSHead;
pTemp = DOSHead->Next;
while (pTemp && pTemp != pConsoleRecord){
pTempLast = pTemp;
pTemp = pTemp->Next;
}
if (pTemp)
pTempLast->Next = pTemp->Next;
return;
}
PDOSRECORD
BaseSrvAllocateDOSRecord(
VOID
)
{
PDOSRECORD DOSRecord;
DOSRecord = RtlAllocateHeap ( RtlProcessHeap (), MAKE_TAG( VDM_TAG ), sizeof (DOSRECORD));
if (DOSRecord == NULL)
return NULL;
RtlFillMemory ((PVOID)DOSRecord,sizeof(DOSRECORD),'\0');
return DOSRecord;
}
VOID BaseSrvFreeDOSRecord (
PDOSRECORD pDOSRecord
)
{
BaseSrvFreeVDMInfo (pDOSRecord->lpVDMInfo);
RtlFreeHeap(RtlProcessHeap (), 0, pDOSRecord);
return;
}
VOID BaseSrvAddDOSRecord (
PCONSOLERECORD pConsoleRecord,
PDOSRECORD pDOSRecord
)
{
PDOSRECORD pDOSRecordTemp;
pDOSRecord->DOSRecordNext = NULL;
if(pConsoleRecord->DOSRecord == NULL){
pConsoleRecord->DOSRecord = pDOSRecord;
return;
}
pDOSRecordTemp = pConsoleRecord->DOSRecord;
while (pDOSRecordTemp->DOSRecordNext)
pDOSRecordTemp = pDOSRecordTemp->DOSRecordNext;
pDOSRecordTemp->DOSRecordNext = pDOSRecord;
return;
}
VOID
BaseSrvRemoveDOSRecord (
PCONSOLERECORD pConsoleRecord,
PDOSRECORD pDOSRecord
)
{
PDOSRECORD DOSRecordCurrent,DOSRecordLast = NULL;
if( pConsoleRecord == NULL)
return;
if(pConsoleRecord->DOSRecord == pDOSRecord){
pConsoleRecord->DOSRecord = pDOSRecord->DOSRecordNext;
return;
}
DOSRecordLast = pConsoleRecord->DOSRecord;
if (DOSRecordLast)
DOSRecordCurrent = DOSRecordLast->DOSRecordNext;
else
return;
while (DOSRecordCurrent && DOSRecordCurrent != pDOSRecord){
DOSRecordLast = DOSRecordCurrent;
DOSRecordCurrent = DOSRecordCurrent->DOSRecordNext;
}
if (DOSRecordCurrent == NULL)
return;
else
DOSRecordLast->DOSRecordNext = pDOSRecord->DOSRecordNext;
return;
}
VOID
BaseSrvFreeVDMInfo(
IN PVDMINFO lpVDMInfo
)
{
if (lpVDMInfo == NULL)
return;
if (lpVDMInfo->CmdLine)
RtlFreeHeap(RtlProcessHeap (), 0,lpVDMInfo->CmdLine);
if(lpVDMInfo->Enviornment)
RtlFreeHeap(RtlProcessHeap (), 0,lpVDMInfo->Enviornment);
if(lpVDMInfo->Desktop)
RtlFreeHeap(RtlProcessHeap (), 0,lpVDMInfo->Desktop);
if(lpVDMInfo->Title)
RtlFreeHeap(RtlProcessHeap (), 0,lpVDMInfo->Title);
if(lpVDMInfo->Reserved)
RtlFreeHeap(RtlProcessHeap (), 0,lpVDMInfo->Reserved);
if(lpVDMInfo->CurDirectory)
RtlFreeHeap(RtlProcessHeap (), 0,lpVDMInfo->CurDirectory);
RtlFreeHeap(RtlProcessHeap (), 0,lpVDMInfo);
return;
}
ULONG BaseSrvCreatePairWaitHandles (ServerHandle, ClientHandle)
HANDLE *ServerHandle;
HANDLE *ClientHandle;
{
NTSTATUS Status;
PCSR_THREAD t;
Status = NtCreateEvent(
ServerHandle,
EVENT_ALL_ACCESS,
NULL,
NotificationEvent,
FALSE
);
if (!NT_SUCCESS(Status) )
return Status;
t = CSR_SERVER_QUERYCLIENTTHREAD();
Status = NtDuplicateObject (
NtCurrentProcess(),
*ServerHandle,
t->Process->ProcessHandle,
ClientHandle,
(ACCESS_MASK)NULL,
FALSE,
DUPLICATE_SAME_ACCESS
);
if ( NT_SUCCESS(Status) ){
return STATUS_SUCCESS;
}
else {
NtClose (*ServerHandle);
return Status;
}
}
ULONG
BaseSrvGetWOWTaskId(
VOID
)
{
PWOWRECORD pWOWRecord;
static BOOL fWrapped = FALSE;
if (WOWTaskIdNext == WOWMAXID) {
fWrapped = TRUE;
WOWTaskIdNext = WOWMINID;
}
if (fWrapped && WOWHead != NULL) {
pWOWRecord = WOWHead->WOWRecord;
while (pWOWRecord) {
if (pWOWRecord->iTask == WOWTaskIdNext) {
WOWTaskIdNext++;
if (WOWTaskIdNext == WOWMAXID) {
WOWTaskIdNext = WOWMINID;
}
pWOWRecord = WOWHead->WOWRecord;
} else {
pWOWRecord = pWOWRecord->WOWRecordNext;
}
}
}
return WOWTaskIdNext++;
}
#ifdef NOT_NEEDED
ULONG
BaseSrvGetWOWRecordByHandle(
HANDLE hParent,
OUT PWOWRECORD *pRecord
)
{
PWOWRECORD pWOWRecord;
if(WOWHead == NULL)
return STATUS_INVALID_PARAMETER;
pWOWRecord = WOWHead->WOWRecord;
while (pWOWRecord){
if (pWOWRecord->hWaitForParentServer == hParent){
*pRecord = pWOWRecord;
return STATUS_SUCCESS;
}
else
pWOWRecord = pWOWRecord->WOWRecordNext;
}
return STATUS_INVALID_PARAMETER;
}
#endif
VOID
BaseSrvAddConsoleRecord(
IN PCONSOLERECORD pConsoleRecord
)
{
pConsoleRecord->Next = DOSHead;
DOSHead = pConsoleRecord;
}
VOID BaseSrvCloseStandardHandles (HANDLE hVDM, PDOSRECORD pDOSRecord)
{
PVDMINFO pVDMInfo = pDOSRecord->lpVDMInfo;
if (pVDMInfo == NULL)
return;
if (pVDMInfo->StdIn)
NtDuplicateObject (hVDM,
pVDMInfo->StdIn,
NULL,
NULL,
(ACCESS_MASK)NULL,
0,
DUPLICATE_CLOSE_SOURCE);
if (pVDMInfo->StdOut)
NtDuplicateObject (hVDM,
pVDMInfo->StdOut,
NULL,
NULL,
(ACCESS_MASK)NULL,
0,
DUPLICATE_CLOSE_SOURCE);
if (pVDMInfo->StdErr)
NtDuplicateObject (hVDM,
pVDMInfo->StdErr,
NULL,
NULL,
(ACCESS_MASK)NULL,
0,
DUPLICATE_CLOSE_SOURCE);
pVDMInfo->StdIn = 0;
pVDMInfo->StdOut = 0;
pVDMInfo->StdErr = 0;
return;
}
VOID BaseSrvClosePairWaitHandles (PDOSRECORD pDOSRecord)
{
PCSR_THREAD t;
if (pDOSRecord->hWaitForParentDup)
NtClose (pDOSRecord->hWaitForParentDup);
t = CSR_SERVER_QUERYCLIENTTHREAD();
if (pDOSRecord->hWaitForParent)
NtDuplicateObject (t->Process->ProcessHandle,
pDOSRecord->hWaitForParent,
NULL,
NULL,
(ACCESS_MASK)NULL,
0,
DUPLICATE_CLOSE_SOURCE);
pDOSRecord->hWaitForParentDup = 0;
pDOSRecord->hWaitForParent = 0;
return;
}
ULONG
BaseSrvSetReenterCount (
IN OUT PCSR_API_MSG m,
IN OUT PCSR_REPLY_STATUS ReplyStatus
)
{
PBASE_SET_REENTER_COUNT_MSG b = (PBASE_SET_REENTER_COUNT_MSG)&m->u.ApiMessageData;
NTSTATUS Status;
PCONSOLERECORD pConsoleRecord;
Status = RtlEnterCriticalSection( &BaseSrvDOSCriticalSection );
ASSERT(NT_SUCCESS(Status));
Status = BaseSrvGetConsoleRecord(b->ConsoleHandle,&pConsoleRecord);
if (!NT_SUCCESS (Status)) {
RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
return ((ULONG)STATUS_INVALID_PARAMETER);
}
if (b->fIncDec == INCREMENT_REENTER_COUNT)
pConsoleRecord->nReEntrancy++;
else {
pConsoleRecord->nReEntrancy--;
if(pConsoleRecord->hWaitForVDMDup)
NtSetEvent (pConsoleRecord->hWaitForVDMDup,NULL);
}
RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
return TRUE;
}
/*
* Spawn of ntvdm failed before CreateProcessW finished.
* delete the console record.
*/
VOID
BaseSrvVDMTerminated (
IN HANDLE hVDM,
IN ULONG DosSesId
)
{
NTSTATUS Status;
PCONSOLERECORD pConsoleRecord;
RtlEnterCriticalSection( &BaseSrvDOSCriticalSection );
if (!hVDM) // no-console-handle case
Status = GetConsoleRecordDosSesId(DosSesId,&pConsoleRecord);
else
Status = BaseSrvGetConsoleRecord(hVDM,&pConsoleRecord);
if (NT_SUCCESS (Status)) {
BaseSrvExitVDMWorker(pConsoleRecord);
}
RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
}
VOID
BaseSrvUpdateVDMSequenceNumber (
IN HANDLE hVDM,
IN ULONG VDMSequenceNumber,
IN ULONG DosSesId
)
{
NTSTATUS Status;
PCONSOLERECORD pConsoleRecord;
if (hVDM == (HANDLE) -1) {
if (WOWHead == NULL || WOWHead->SequenceNumber != 0) {
#if DEVL
DbgPrint( "BASESRV: WOW is in inconsistent state. Contact DOS Team\n");
#endif
return;
}
WOWHead->SequenceNumber = VDMSequenceNumber;
return;
}
else {
Status = RtlEnterCriticalSection( &BaseSrvDOSCriticalSection );
ASSERT( NT_SUCCESS( Status ) );
if (!hVDM) // no-console-handle case
Status = GetConsoleRecordDosSesId(DosSesId,&pConsoleRecord);
else
Status = BaseSrvGetConsoleRecord(hVDM,&pConsoleRecord);
if (!NT_SUCCESS (Status) || pConsoleRecord->SequenceNumber != 0) {
#if DEVL
DbgPrint( "BASESRV: DOS is in inconsistent state. Contact DOS Team\n");
#endif
RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
return;
}
pConsoleRecord->SequenceNumber = VDMSequenceNumber;
RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
}
return;
}
VOID
BaseSrvCleanupVDMResources (
IN PCSR_PROCESS Process
)
{
PCONSOLERECORD pConsoleHead;
NTSTATUS Status;
PBATRECORD pBatRecord;
if (!Process->fVDM) {
Status = RtlEnterCriticalSection( &BaseSrvDOSCriticalSection );
ASSERT(NT_SUCCESS(Status));
pBatRecord = BatRecordHead;
while (pBatRecord &&
pBatRecord->SequenceNumber != Process->SequenceNumber)
pBatRecord = pBatRecord->BatRecordNext;
if (pBatRecord)
BaseSrvFreeAndRemoveBatRecord(pBatRecord);
RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
return;
}
// Test WOW Head first
Status = RtlEnterCriticalSection( &BaseSrvWOWCriticalSection );
ASSERT( NT_SUCCESS( Status ) );
if (WOWHead) {
if (WOWHead->SequenceNumber == Process->SequenceNumber){
BaseSrvRemoveWOWRecordByITask((ULONG)-1);
hwndWowExec = NULL;
dwWowExecThreadId = dwWowExecProcessId = 0;
ulWowExecProcessSequenceNumber = 0;
RtlLeaveCriticalSection( &BaseSrvWOWCriticalSection );
return;
}
}
RtlLeaveCriticalSection( &BaseSrvWOWCriticalSection );
// Test all DOS Heads
Status = RtlEnterCriticalSection( &BaseSrvDOSCriticalSection );
ASSERT(NT_SUCCESS(Status));
pConsoleHead = DOSHead;
while (pConsoleHead) {
if (pConsoleHead->SequenceNumber == Process->SequenceNumber){
BaseSrvExitVDMWorker (pConsoleHead);
break;
}
else
pConsoleHead = pConsoleHead->Next;
}
RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
return;
}
VOID
BaseSrvExitVDMWorker (
PCONSOLERECORD pConsoleRecord
)
{
PDOSRECORD pDOSRecord;
if (pConsoleRecord->hWaitForVDMDup){
NtClose(pConsoleRecord->hWaitForVDMDup);
pConsoleRecord->hWaitForVDMDup =0;
}
pDOSRecord = pConsoleRecord->DOSRecord;
while (pDOSRecord) {
if (pDOSRecord->hWaitForParentDup) {
NtSetEvent (pDOSRecord->hWaitForParentDup,NULL);
NtClose (pDOSRecord->hWaitForParentDup);
pDOSRecord->hWaitForParentDup = 0;
}
pDOSRecord = pDOSRecord->DOSRecordNext;
}
NtClose(pConsoleRecord->hVDM);
BaseSrvFreeConsoleRecord (pConsoleRecord);
return;
}
NTSTATUS
BaseSrvFillPifInfo (
PVDMINFO lpVDMInfo,
PBASE_GET_NEXT_VDM_COMMAND_MSG b
)
{
LPSTR Title;
ULONG TitleLen;
NTSTATUS Status;
Status = STATUS_INVALID_PARAMETER;
if (!lpVDMInfo)
return Status;
/*
* Get the title for the window in precedence order
*/
// startupinfo title
if (lpVDMInfo->TitleLen && lpVDMInfo->Title)
{
Title = lpVDMInfo->Title;
TitleLen = lpVDMInfo->TitleLen;
}
// App Name
else if (lpVDMInfo->AppName && lpVDMInfo->AppLen)
{
Title = lpVDMInfo->AppName;
TitleLen = lpVDMInfo->AppLen;
}
// hopeless
else {
Title = NULL;
TitleLen = 0;
}
try {
if (b->PifLen) {
*b->PifFile = '\0';
}
if (b->TitleLen) {
*b->Title = '\0';
}
if (b->CurDirectoryLen) {
*b->CurDirectory = '\0';
}
if ( (!b->TitleLen || TitleLen <= b->TitleLen) &&
(!b->PifLen || lpVDMInfo->PifLen <= b->PifLen) &&
(!b->CurDirectoryLen ||
lpVDMInfo->CurDirectoryLen <= b->CurDirectoryLen) &&
(!b->ReservedLen || lpVDMInfo->ReservedLen <= b->ReservedLen))
{
if (b->TitleLen) {
if (Title && TitleLen) {
RtlMoveMemory(b->Title, Title, TitleLen);
*((LPSTR)b->Title + TitleLen - 1) = '\0';
}
else {
*b->Title = '\0';
}
}
if (lpVDMInfo->PifLen && b->PifLen)
RtlMoveMemory(b->PifFile,
lpVDMInfo->PifFile,
lpVDMInfo->PifLen);
if (lpVDMInfo->CurDirectoryLen && b->CurDirectoryLen)
RtlMoveMemory(b->CurDirectory,
lpVDMInfo->CurDirectory,
lpVDMInfo->CurDirectoryLen
);
if (lpVDMInfo->Reserved && b->ReservedLen)
RtlMoveMemory(b->Reserved,
lpVDMInfo->Reserved,
lpVDMInfo->ReservedLen
);
Status = STATUS_SUCCESS;
}
}
except(EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
}
/* fill out the size for each field */
b->PifLen = (USHORT)lpVDMInfo->PifLen;
b->CurDirectoryLen = lpVDMInfo->CurDirectoryLen;
b->TitleLen = TitleLen;
b->ReservedLen = lpVDMInfo->ReservedLen;
return Status;
}
/***************************************************************************\
* IsClientSystem
*
* Determines if caller is SYSTEM
*
* Returns TRUE is caller is system, FALSE if not (or error)
*
* History:
* 12-May-94 AndyH Created
\***************************************************************************/
BOOL
IsClientSystem(
HANDLE hUserToken
)
{
BYTE achBuffer[100];
PTOKEN_USER pUser = (PTOKEN_USER) &achBuffer;
DWORD dwBytesRequired;
NTSTATUS NtStatus;
BOOL fAllocatedBuffer = FALSE;
BOOL fSystem;
SID_IDENTIFIER_AUTHORITY SidIdAuth = SECURITY_NT_AUTHORITY;
static PSID pSystemSid = NULL;
if (!pSystemSid) {
// Create a sid for local system
NtStatus = RtlAllocateAndInitializeSid(
&SidIdAuth,
1, // SubAuthorityCount, 1 for local system
SECURITY_LOCAL_SYSTEM_RID,
0,0,0,0,0,0,0,
&pSystemSid
);
if (!NT_SUCCESS(NtStatus)) {
pSystemSid = NULL;
return FALSE;
}
}
NtStatus = NtQueryInformationToken(
hUserToken, // Handle
TokenUser, // TokenInformationClass
pUser, // TokenInformation
sizeof(achBuffer), // TokenInformationLength
&dwBytesRequired // ReturnLength
);
if (!NT_SUCCESS(NtStatus))
{
if (NtStatus != STATUS_BUFFER_TOO_SMALL)
{
return FALSE;
}
//
// Allocate space for the user info
//
pUser = (PTOKEN_USER) RtlAllocateHeap(BaseSrvHeap, MAKE_TAG( VDM_TAG ), dwBytesRequired);
if (pUser == NULL)
{
return FALSE;
}
fAllocatedBuffer = TRUE;
//
// Read in the UserInfo
//
NtStatus = NtQueryInformationToken(
hUserToken, // Handle
TokenUser, // TokenInformationClass
pUser, // TokenInformation
dwBytesRequired, // TokenInformationLength
&dwBytesRequired // ReturnLength
);
if (!NT_SUCCESS(NtStatus))
{
RtlFreeHeap(BaseSrvHeap, 0, pUser);
return FALSE;
}
}
// Compare callers SID with SystemSid
fSystem = RtlEqualSid(pSystemSid, pUser->User.Sid);
if (fAllocatedBuffer)
{
RtlFreeHeap(BaseSrvHeap, 0, pUser);
}
return (fSystem);
}