/*++ 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); }