Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4854 lines
141 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. srvvdm.c
  5. Abstract:
  6. This module implements windows server functions for VDMs
  7. Author:
  8. Sudeep Bharati (sudeepb) 03-Sep-1991
  9. Revision History:
  10. Sudeepb 18-Sep-1992
  11. Added code to make VDM termination and resource cleanup robust.
  12. AndyH 23-May-1994
  13. Added Code to allow the Shared WOW to run if client is Interactive or SYSTEM
  14. impersonating Interactive.
  15. VadimB Sep-Dec 1996
  16. Added code to allow for multiple default wows. Dispatching to an appropriate wow
  17. is based upon the desktop name. It is still not possible to have multiple shared
  18. wows on the same desktop (although technically trivial to implement) -- which would
  19. be the level of OS/2 functionality
  20. --*/
  21. #include "basesrv.h"
  22. #include "vdm.h"
  23. #include "vdmdbg.h"
  24. /*
  25. * VadimB: Work to allow for multiple ntvdms
  26. * - Add linked list of hwndWowExec's
  27. * - The list should contain dwWowExecThreadId
  28. * - dwWowExecProcessId
  29. * - dwWowExecProcessSequenceNumber
  30. *
  31. * List is not completely dynamic - the first entry is static
  32. * as the case with 1 shared vdm would be the most common one
  33. *
  34. */
  35. // record that reflects winstas with corresponding downlinks for desktops
  36. // there could be only one wowexec per desktop (the default one, I mean)
  37. // there could be many desktops per winsta as well as multiple winstas
  38. //
  39. // We have made a decision to simplify handling of wow vdms by introducing
  40. // a single-level list of wowexecs [as opposed to 2-level so searching for the particular
  41. // winsta would have been improved greatly]. The reason is purely practical: we do not
  42. // anticipate having a large number of desktops/winsta
  43. BOOL fIsFirstVDM = TRUE;
  44. PCONSOLERECORD DOSHead = NULL; // Head Of DOS tasks with a valid Console
  45. PBATRECORD BatRecordHead = NULL;
  46. RTL_CRITICAL_SECTION BaseSrvDOSCriticalSection;
  47. RTL_CRITICAL_SECTION BaseSrvWOWCriticalSection;
  48. ULONG WOWTaskIdNext = WOWMINID; // This is global for all the wows in the system
  49. typedef struct tagSharedWOWHead {
  50. PSHAREDWOWRECORD pSharedWowRecord; // points to the list of shared wows
  51. // other wow-related information is stored here
  52. } SHAREDWOWRECORDHEAD, *PSHAREDWOWRECORDHEAD;
  53. SHAREDWOWRECORDHEAD gWowHead;
  54. ////////////////////////////////////////////////////////////////////////////////////////
  55. //
  56. // Synch macros and functions
  57. //
  58. // DOSCriticalSection -- protects CONSOLERECORD list (DOSHead)
  59. // WOWCriticalSection -- protects SHAREDWOWRECORD list (gpSharedWowRecordHead)
  60. // each shared wow has it's very own critical section
  61. // function to access console queue for modification
  62. /////////////////////////////////////////////////////////////////////////////////////////
  63. //
  64. // Macros
  65. //
  66. //
  67. // use these macros when manipulating shared wow items (adding, removing) or console
  68. // records (adding, removing)
  69. #define ENTER_WOW_CRITICAL() \
  70. RtlEnterCriticalSection(&BaseSrvWOWCriticalSection)
  71. #define LEAVE_WOW_CRITICAL() \
  72. RtlLeaveCriticalSection(&BaseSrvWOWCriticalSection)
  73. /////////////////////////////////////////////////////////////////////////////////////////
  74. //
  75. // Dynamic linking to system and import api stuff
  76. //
  77. //
  78. typedef BOOL (WINAPI *POSTMESSAGEPROC)(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
  79. POSTMESSAGEPROC BaseSrvPostMessageA;
  80. typedef BOOL (WINAPI *GETWINDOWTHREADPROCESSIDPROC)(HWND hWnd, LPDWORD lpdwProcessId);
  81. GETWINDOWTHREADPROCESSIDPROC BaseSrvGetWindowThreadProcessId;
  82. typedef NTSTATUS (*USERTESTTOKENFORINTERACTIVE)(HANDLE Token, PLUID pluidCaller);
  83. USERTESTTOKENFORINTERACTIVE UserTestTokenForInteractive = NULL;
  84. typedef NTSTATUS (*USERRESOLVEDESKTOPFORWOW)(PUNICODE_STRING);
  85. USERRESOLVEDESKTOPFORWOW BaseSrvUserResolveDesktopForWow = NULL;
  86. typedef struct tagBaseSrvApiImportRecord {
  87. PCHAR pszProcedureName;
  88. PVOID *ppProcAddress;
  89. } BASESRVAPIIMPORTRECORD, *PBASESRVAPIIMPORTRECORD;
  90. typedef struct tagBaseSrvModuleImportRecord {
  91. PWCHAR pwszModuleName;
  92. PBASESRVAPIIMPORTRECORD pApiImportRecord;
  93. UINT nApiImportRecordCount;
  94. HANDLE ModuleHandle;
  95. } BASESRVMODULEIMPORTRECORD, *PBASESRVMODULEIMPORTRECORD;
  96. // prototypes
  97. NTSTATUS
  98. BaseSrvFindSharedWowRecordByDesktop(
  99. PSHAREDWOWRECORDHEAD pSharedWowRecordHead,
  100. PUNICODE_STRING pDesktopName,
  101. PSHAREDWOWRECORD* ppSharedWowRecord
  102. );
  103. VOID BaseSrvAddWOWRecord (
  104. PSHAREDWOWRECORD pSharedWow,
  105. PWOWRECORD pWOWRecord
  106. );
  107. VOID BaseSrvRemoveWOWRecord (
  108. PSHAREDWOWRECORD pSharedWow,
  109. PWOWRECORD pWOWRecord
  110. );
  111. VOID
  112. BaseSrvFreeSharedWowRecord(
  113. PSHAREDWOWRECORD pSharedWowRecord
  114. );
  115. ULONG
  116. BaseSrvGetWOWTaskId(
  117. PSHAREDWOWRECORDHEAD pSharedWowHead // (->pSharedWowRecord)
  118. );
  119. NTSTATUS
  120. BaseSrvRemoveWOWRecordByTaskId (
  121. IN PSHAREDWOWRECORD pSharedWow,
  122. IN ULONG iWowTask
  123. );
  124. PWOWRECORD
  125. BaseSrvCheckAvailableWOWCommand(
  126. PSHAREDWOWRECORD pSharedWow
  127. );
  128. PWOWRECORD
  129. BaseSrvAllocateWOWRecord(
  130. PSHAREDWOWRECORDHEAD pSharedWowRecordHead
  131. );
  132. NTSTATUS
  133. BaseSrvAddWowTask (
  134. PCSR_API_MSG m,
  135. ULONG SequenceNumber
  136. );
  137. NTSTATUS
  138. BaseSrvEnumWowTask (
  139. PBASE_GET_NEXT_VDM_COMMAND_MSG b
  140. );
  141. NTSTATUS
  142. BaseSrvEnumWowProcess(
  143. PBASE_GET_NEXT_VDM_COMMAND_MSG b
  144. );
  145. //////////////////////////////////////////////////////////////////////////////////////////////////
  146. //
  147. // Api import definitions
  148. //
  149. //
  150. WCHAR wszUser32ModName[] = L"user32";
  151. WCHAR wszWinSrvModName[] = L"winsrv";
  152. BASESRVAPIIMPORTRECORD rgUser32ApiImport[] = {
  153. { "PostMessageA", (PVOID*)&BaseSrvPostMessageA }
  154. , { "GetWindowThreadProcessId", (PVOID*)&BaseSrvGetWindowThreadProcessId }
  155. , { "ResolveDesktopForWOW", (PVOID*)&BaseSrvUserResolveDesktopForWow }
  156. };
  157. BASESRVAPIIMPORTRECORD rgWinsrvApiImport[] = {
  158. { "_UserTestTokenForInteractive", (PVOID*)&UserTestTokenForInteractive }
  159. };
  160. BASESRVMODULEIMPORTRECORD rgBaseSrvModuleImport[] = {
  161. { wszUser32ModName, rgUser32ApiImport, sizeof(rgUser32ApiImport) / sizeof(rgUser32ApiImport[0]), NULL },
  162. { wszWinSrvModName, rgWinsrvApiImport, sizeof(rgWinsrvApiImport) / sizeof(rgWinsrvApiImport[0]), NULL }
  163. };
  164. // import all the necessary apis at once
  165. // This procedure should execute just once and then the appropriate components just
  166. // hang around
  167. // call this with
  168. // Status = BaseSrvImportApis(rgBaseSrvModuleImport,
  169. // sizeof(rgBaseSrvModuleImport)/sizeof(rgBaseSrvModuleImport[0]))
  170. //
  171. NTSTATUS
  172. BaseSrvImportApis(
  173. PBASESRVMODULEIMPORTRECORD pModuleImport,
  174. UINT nModules
  175. )
  176. {
  177. NTSTATUS Status;
  178. UINT uModule, uProcedure;
  179. PBASESRVAPIIMPORTRECORD pApiImport;
  180. STRING ProcedureName; // procedure name or module name
  181. UNICODE_STRING ModuleName;
  182. HANDLE ModuleHandle;
  183. for (uModule = 0; uModule < nModules; ++uModule, ++pModuleImport) {
  184. // see if we can load this particular dll
  185. RtlInitUnicodeString(&ModuleName, pModuleImport->pwszModuleName);
  186. Status = LdrLoadDll(NULL,
  187. NULL,
  188. &ModuleName, // module name string
  189. &ModuleHandle);
  190. if (!NT_SUCCESS(Status)) {
  191. // we may have linked to a few dlls at this point - we have to unlink from all of those
  192. // by unloading the dll which is really a useless exersise.
  193. // so just abandon and return -- BUGBUG - cleanup later
  194. KdPrint(("BaseSrvImportApis: Failed to load %ls\n",
  195. pModuleImport->pwszModuleName));
  196. goto ErrorCleanup;
  197. }
  198. pModuleImport->ModuleHandle = ModuleHandle;
  199. pApiImport = pModuleImport->pApiImportRecord;
  200. for (uProcedure = 0, pApiImport = pModuleImport->pApiImportRecord;
  201. uProcedure < pModuleImport->nApiImportRecordCount;
  202. ++uProcedure, ++pApiImport) {
  203. RtlInitString(&ProcedureName, pApiImport->pszProcedureName);
  204. Status = LdrGetProcedureAddress(ModuleHandle,
  205. &ProcedureName, // procedure name string
  206. 0,
  207. pApiImport->ppProcAddress);
  208. if (!NT_SUCCESS(Status)) {
  209. // we have failed to get this procedure - something is wrong
  210. // perform a cleanup
  211. KdPrint(("BaseSrvImportApis: Failed to link %s from %ls\n",
  212. pApiImport->pszProcedureName,
  213. pModuleImport->pwszModuleName));
  214. goto ErrorCleanup;
  215. }
  216. }
  217. }
  218. return (STATUS_SUCCESS);
  219. ErrorCleanup:
  220. // here we engage into a messy cleanup procedure by returning things back to the way
  221. // they were before we have started
  222. for (; uModule > 0; --uModule, --pModuleImport) {
  223. // reset all the apis
  224. for (uProcedure = 0, pApiImport = pModuleImport->pApiImportRecord;
  225. uProcedure < pModuleImport->nApiImportRecordCount;
  226. ++uProcedure, ++pApiImport) {
  227. *pApiImport->ppProcAddress = NULL;
  228. }
  229. if (NULL != pModuleImport->ModuleHandle) {
  230. LdrUnloadDll(pModuleImport->ModuleHandle);
  231. pModuleImport->ModuleHandle = NULL;
  232. }
  233. }
  234. return (Status);
  235. }
  236. //////////////////////////////////////////////////////////////////////////////
  237. //
  238. // Manipulating shared wows
  239. //
  240. //
  241. // assumes pDesktopName != NULL
  242. // without the explicit checking
  243. PSHAREDWOWRECORD BaseSrvAllocateSharedWowRecord (
  244. PUNICODE_STRING pDesktopName
  245. )
  246. {
  247. PSHAREDWOWRECORD pSharedWow;
  248. DWORD dwSharedWowRecordSize = sizeof(SHAREDWOWRECORD) +
  249. pDesktopName->Length +
  250. sizeof(WCHAR);
  251. pSharedWow = RtlAllocateHeap(RtlProcessHeap (),
  252. MAKE_TAG( VDM_TAG ),
  253. dwSharedWowRecordSize);
  254. if (NULL != pSharedWow) {
  255. RtlZeroMemory ((PVOID)pSharedWow, dwSharedWowRecordSize);
  256. // initialize desktop name
  257. pSharedWow->WowExecDesktopName.MaximumLength = pDesktopName->Length + sizeof(WCHAR);
  258. pSharedWow->WowExecDesktopName.Buffer = (PWCHAR)(pSharedWow + 1);
  259. RtlCopyUnicodeString(&pSharedWow->WowExecDesktopName, pDesktopName);
  260. pSharedWow->WowAuthId = RtlConvertLongToLuid(-1);
  261. }
  262. return pSharedWow;
  263. }
  264. // this function completely removes the given shared wow vdm
  265. // from our accounting
  266. //
  267. // removes the record from the list of shared wow records
  268. //
  269. // This function also frees the associated memory
  270. //
  271. //
  272. NTSTATUS
  273. BaseSrvDeleteSharedWowRecord (
  274. PSHAREDWOWRECORDHEAD pSharedWowRecordHead,
  275. PSHAREDWOWRECORD pSharedWowRecord
  276. )
  277. {
  278. PSHAREDWOWRECORD pSharedWowRecordPrev = NULL;
  279. PSHAREDWOWRECORD pSharedWowRecordCur;
  280. if (NULL == pSharedWowRecord) { // this is dumb
  281. return STATUS_NOT_FOUND;
  282. }
  283. pSharedWowRecordCur = pSharedWowRecordHead->pSharedWowRecord;
  284. while (NULL != pSharedWowRecordCur) {
  285. if (pSharedWowRecordCur == pSharedWowRecord) {
  286. break;
  287. }
  288. pSharedWowRecordPrev = pSharedWowRecordCur;
  289. pSharedWowRecordCur = pSharedWowRecordCur->pNextSharedWow;
  290. }
  291. if (NULL == pSharedWowRecordCur) {
  292. KdPrint(("BaseSrvDeleteSharedWowRecord: invalid pointer to Shared WOW\n"));
  293. ASSERT(FALSE);
  294. return STATUS_NOT_FOUND;
  295. }
  296. // unlink here
  297. if (NULL == pSharedWowRecordPrev) {
  298. pSharedWowRecordHead->pSharedWowRecord = pSharedWowRecord->pNextSharedWow;
  299. }
  300. else {
  301. pSharedWowRecordPrev->pNextSharedWow = pSharedWowRecord->pNextSharedWow;
  302. }
  303. BaseSrvFreeSharedWowRecord(pSharedWowRecord);
  304. return STATUS_SUCCESS;
  305. }
  306. // assumes no cs is held -- self-contained
  307. // assoc console record should have been removed by now
  308. // nukes all tasks associated with this particular shared wow
  309. VOID
  310. BaseSrvFreeSharedWowRecord(
  311. PSHAREDWOWRECORD pSharedWowRecord)
  312. {
  313. PWOWRECORD pWOWRecord,
  314. pWOWRecordLast;
  315. if(pSharedWowRecord->WOWUserToken) {
  316. NtClose(pSharedWowRecord->WOWUserToken);
  317. }
  318. pWOWRecord = pSharedWowRecord->pWOWRecord;
  319. while (NULL != pWOWRecord) {
  320. pWOWRecordLast = pWOWRecord->WOWRecordNext;
  321. if(pWOWRecord->hWaitForParent) {
  322. NtSetEvent (pWOWRecord->hWaitForParent,NULL);
  323. NtClose (pWOWRecord->hWaitForParent);
  324. pWOWRecord->hWaitForParent = 0;
  325. }
  326. BaseSrvFreeWOWRecord(pWOWRecord);
  327. pWOWRecord = pWOWRecordLast;
  328. }
  329. RtlFreeHeap(RtlProcessHeap (), 0, pSharedWowRecord);
  330. }
  331. // assumes: global wow crit sec is held
  332. NTSTATUS
  333. BaseSrvFindSharedWowRecordByDesktop(
  334. PSHAREDWOWRECORDHEAD pSharedWowRecordHead,
  335. PUNICODE_STRING pDesktopName,
  336. PSHAREDWOWRECORD* ppSharedWowRecord)
  337. {
  338. PSHAREDWOWRECORD pSharedWowRecord = pSharedWowRecordHead->pSharedWowRecord;
  339. while (NULL != pSharedWowRecord) {
  340. if (0 == RtlCompareUnicodeString(&pSharedWowRecord->WowExecDesktopName,
  341. pDesktopName,
  342. TRUE)) {
  343. break;
  344. }
  345. pSharedWowRecord = pSharedWowRecord->pNextSharedWow;
  346. }
  347. if (NULL != pSharedWowRecord) {
  348. *ppSharedWowRecord = pSharedWowRecord;
  349. return STATUS_SUCCESS;
  350. }
  351. return STATUS_NOT_FOUND; // bummer, this is not found
  352. }
  353. // Vadimb : modify this to handle sorted list properly
  354. // then find should be moded to work a little faster - BUGBUG
  355. // assumes: pSharedWowRecord->pNextSharedWow is inited to NULL
  356. VOID
  357. BaseSrvAddSharedWowRecord(
  358. PSHAREDWOWRECORDHEAD pSharedWowRecordHead,
  359. PSHAREDWOWRECORD pSharedWowRecord)
  360. {
  361. PSHAREDWOWRECORD pSharedWowRecordCur = pSharedWowRecordHead->pSharedWowRecord;
  362. if (NULL == pSharedWowRecordCur) {
  363. pSharedWowRecordHead->pSharedWowRecord = pSharedWowRecord;
  364. }
  365. else {
  366. PSHAREDWOWRECORD pSharedWowRecordPrev = NULL;
  367. LONG lCompare;
  368. while (NULL != pSharedWowRecordCur) {
  369. lCompare = RtlCompareUnicodeString(&pSharedWowRecordCur->WowExecDesktopName,
  370. &pSharedWowRecord->WowExecDesktopName,
  371. TRUE);
  372. if (lCompare > 0) {
  373. break;
  374. }
  375. pSharedWowRecordPrev = pSharedWowRecordCur;
  376. pSharedWowRecordCur = pSharedWowRecordCur->pNextSharedWow;
  377. }
  378. pSharedWowRecord->pNextSharedWow = pSharedWowRecordCur;
  379. if (NULL == pSharedWowRecordPrev) { // goes to the head
  380. pSharedWowRecordHead->pSharedWowRecord = pSharedWowRecord;
  381. }
  382. else {
  383. pSharedWowRecordPrev->pNextSharedWow = pSharedWowRecord;
  384. }
  385. }
  386. }
  387. NTSTATUS
  388. BaseSrvFindSharedWowRecordByConsoleHandle(
  389. PSHAREDWOWRECORDHEAD pSharedWowRecordHead,
  390. HANDLE hConsole,
  391. PSHAREDWOWRECORD *ppSharedWowRecord)
  392. {
  393. PSHAREDWOWRECORD pSharedWow = pSharedWowRecordHead->pSharedWowRecord;
  394. while (NULL != pSharedWow) {
  395. // see if same hConsole
  396. if (pSharedWow->hConsole == hConsole) {
  397. *ppSharedWowRecord = pSharedWow;
  398. return STATUS_SUCCESS;
  399. }
  400. pSharedWow = pSharedWow->pNextSharedWow;
  401. }
  402. return STATUS_NOT_FOUND;
  403. }
  404. NTSTATUS
  405. BaseSrvFindSharedWowRecordByTaskId(
  406. PSHAREDWOWRECORDHEAD pSharedWowRecordHead,
  407. ULONG TaskId, // task id
  408. PSHAREDWOWRECORD *ppSharedWowRecord,
  409. PWOWRECORD *ppWowRecord) // optional
  410. {
  411. PSHAREDWOWRECORD pSharedWow = pSharedWowRecordHead->pSharedWowRecord;
  412. PWOWRECORD pWowRecord;
  413. ASSERT(0 != TaskId); // this is a pre-condition
  414. while (NULL != pSharedWow) {
  415. pWowRecord = pSharedWow->pWOWRecord;
  416. while (NULL != pWowRecord) {
  417. if (pWowRecord->iTask == TaskId) {
  418. ASSERT(NULL != ppWowRecord);
  419. // this is wow task
  420. *ppSharedWowRecord = pSharedWow;
  421. if (NULL != ppWowRecord) {
  422. *ppWowRecord = pWowRecord;
  423. }
  424. return STATUS_SUCCESS;
  425. }
  426. pWowRecord = pWowRecord->WOWRecordNext;
  427. }
  428. pSharedWow = pSharedWow->pNextSharedWow;
  429. }
  430. return STATUS_NOT_FOUND;
  431. }
  432. NTSTATUS
  433. BaseSrvGetVdmSequence(
  434. HANDLE hProcess,
  435. PULONG pSequenceNumber)
  436. {
  437. NTSTATUS Status;
  438. PCSR_PROCESS pCsrProcess;
  439. Status = CsrLockProcessByClientId(hProcess, &pCsrProcess);
  440. if ( !NT_SUCCESS(Status) ) {
  441. return Status;
  442. }
  443. *pSequenceNumber = pCsrProcess->SequenceNumber;
  444. CsrUnlockProcess(pCsrProcess);
  445. Status = STATUS_SUCCESS;
  446. return Status;
  447. }
  448. ////////////////////////////////////////////// End new code
  449. // internal prototypes
  450. ULONG
  451. GetNextDosSesId(VOID);
  452. NTSTATUS
  453. GetConsoleRecordDosSesId (
  454. IN ULONG DosSesId,
  455. IN OUT PCONSOLERECORD *pConsoleRecord
  456. );
  457. NTSTATUS
  458. OkToRunInSharedWOW(
  459. IN HANDLE UniqueProcessClientId,
  460. OUT PLUID pAuthenticationId,
  461. OUT PHANDLE pWOWUserToken
  462. );
  463. BOOL
  464. IsClientSystem(
  465. HANDLE hUserToken
  466. );
  467. VOID
  468. BaseSrvVDMInit(VOID)
  469. {
  470. NTSTATUS Status;
  471. Status = RtlInitializeCriticalSection( &BaseSrvDOSCriticalSection );
  472. ASSERT( NT_SUCCESS( Status ) );
  473. Status = RtlInitializeCriticalSection( &BaseSrvWOWCriticalSection );
  474. ASSERT( NT_SUCCESS( Status ) );
  475. return;
  476. }
  477. ULONG
  478. BaseSrvCheckVDM(
  479. IN OUT PCSR_API_MSG m,
  480. IN OUT PCSR_REPLY_STATUS ReplyStatus
  481. )
  482. {
  483. NTSTATUS Status;
  484. PBASE_CHECKVDM_MSG b = (PBASE_CHECKVDM_MSG)&m->u.ApiMessageData;
  485. if (BaseSrvIsVdmAllowed() == FALSE) {
  486. return STATUS_VDM_DISALLOWED;
  487. }
  488. if (!CsrValidateMessageBuffer(m, &b->CmdLine, b->CmdLen, sizeof(BYTE))) {
  489. return STATUS_INVALID_PARAMETER;
  490. }
  491. if (!CsrValidateMessageBuffer(m, &b->AppName, b->AppLen, sizeof(BYTE))) {
  492. return STATUS_INVALID_PARAMETER;
  493. }
  494. if (!CsrValidateMessageBuffer(m, &b->Env, b->EnvLen, sizeof(BYTE))) {
  495. return STATUS_INVALID_PARAMETER;
  496. }
  497. if (!CsrValidateMessageBuffer(m, &b->PifFile, b->PifLen, sizeof(BYTE))) {
  498. return STATUS_INVALID_PARAMETER;
  499. }
  500. if (!CsrValidateMessageBuffer(m, &b->CurDirectory, b->CurDirectoryLen, sizeof(BYTE))) {
  501. return STATUS_INVALID_PARAMETER;
  502. }
  503. if (!CsrValidateMessageBuffer(m, &b->Title, b->TitleLen, sizeof(BYTE))) {
  504. return STATUS_INVALID_PARAMETER;
  505. }
  506. if (!CsrValidateMessageBuffer(m, &b->Reserved, b->ReservedLen, sizeof(BYTE))) {
  507. return STATUS_INVALID_PARAMETER;
  508. }
  509. if (!CsrValidateMessageBuffer(m, &b->Desktop, b->DesktopLen, sizeof(BYTE))) {
  510. return STATUS_INVALID_PARAMETER;
  511. }
  512. if (!CsrValidateMessageBuffer(m, &b->StartupInfo, sizeof(STARTUPINFO), sizeof(BYTE))) {
  513. return STATUS_INVALID_PARAMETER;
  514. }
  515. if (b->UserLuid && !CsrValidateMessageBuffer(m, &b->UserLuid, sizeof(LUID), sizeof(BYTE))) {
  516. return STATUS_INVALID_PARAMETER;
  517. }
  518. if(b->BinaryType == BINARY_TYPE_WIN16) {
  519. Status = BaseSrvCheckWOW (b, m->h.ClientId.UniqueProcess);
  520. }
  521. else {
  522. Status = BaseSrvCheckDOS (b, m->h.ClientId.UniqueProcess);
  523. }
  524. return ((ULONG)Status);
  525. }
  526. ULONG
  527. BaseSrvUpdateVDMEntry(
  528. IN OUT PCSR_API_MSG m,
  529. IN OUT PCSR_REPLY_STATUS ReplyStatus
  530. )
  531. {
  532. PBASE_UPDATE_VDM_ENTRY_MSG b = (PBASE_UPDATE_VDM_ENTRY_MSG)&m->u.ApiMessageData;
  533. ULONG SequenceNumber;
  534. if(!NT_SUCCESS(BaseSrvGetVdmSequence(m->h.ClientId.UniqueProcess, &SequenceNumber))) {
  535. return (ULONG)STATUS_INVALID_PARAMETER;
  536. }
  537. if (BINARY_TYPE_WIN16 == b->BinaryType)
  538. return (BaseSrvUpdateWOWEntry (b, SequenceNumber));
  539. else
  540. return (BaseSrvUpdateDOSEntry (b, SequenceNumber));
  541. }
  542. //
  543. // This call makes an explicit assumption that the very first time ntvdm is accessed --
  544. //
  545. //
  546. //
  547. //
  548. //
  549. ULONG
  550. BaseSrvGetNextVDMCommand(
  551. IN OUT PCSR_API_MSG m,
  552. IN OUT PCSR_REPLY_STATUS ReplyStatus
  553. )
  554. {
  555. NTSTATUS Status;
  556. PBASE_GET_NEXT_VDM_COMMAND_MSG b = (PBASE_GET_NEXT_VDM_COMMAND_MSG)&m->u.ApiMessageData;
  557. PDOSRECORD pDOSRecord,pDOSRecordTemp=NULL;
  558. PWOWRECORD pWOWRecord;
  559. PCONSOLERECORD pConsoleRecord;
  560. PVDMINFO lpVDMInfo;
  561. HANDLE Handle,TargetHandle;
  562. LONG WaitState;
  563. PBATRECORD pBatRecord;
  564. PSHAREDWOWRECORD pSharedWow = NULL;
  565. BOOL bWowApp = b->VDMState & ASKING_FOR_WOW_BINARY;
  566. BOOL bSepWow = b->VDMState & ASKING_FOR_SEPWOW_BINARY;
  567. ULONG SequenceNumber;
  568. if(!NT_SUCCESS(BaseSrvGetVdmSequence(m->h.ClientId.UniqueProcess, &SequenceNumber))) {
  569. return (ULONG)STATUS_INVALID_PARAMETER;
  570. }
  571. if (!CsrValidateMessageBuffer(m, &b->Env, b->EnvLen, sizeof(BYTE))) {
  572. return STATUS_INVALID_PARAMETER;
  573. }
  574. if(b->VDMState & ASKING_FOR_WOWPROCLIST) {
  575. return BaseSrvEnumWowProcess(b);
  576. }
  577. else if(b->VDMState & ASKING_FOR_WOWTASKLIST) {
  578. return BaseSrvEnumWowTask(b);
  579. }
  580. else if(b->VDMState & ASKING_TO_ADD_WOWTASK) {
  581. return BaseSrvAddWowTask (m, SequenceNumber);
  582. }
  583. if (!CsrValidateMessageBuffer(m, &b->CmdLine, b->CmdLen, sizeof(BYTE))) {
  584. return STATUS_INVALID_PARAMETER;
  585. }
  586. if (!CsrValidateMessageBuffer(m, &b->AppName, b->AppLen, sizeof(BYTE))) {
  587. return STATUS_INVALID_PARAMETER;
  588. }
  589. if (!CsrValidateMessageBuffer(m, &b->PifFile, b->PifLen, sizeof(BYTE))) {
  590. return STATUS_INVALID_PARAMETER;
  591. }
  592. if (!CsrValidateMessageBuffer(m, &b->CurDirectory, b->CurDirectoryLen, sizeof(BYTE))) {
  593. return STATUS_INVALID_PARAMETER;
  594. }
  595. if (!CsrValidateMessageBuffer(m, &b->Title, b->TitleLen, sizeof(BYTE))) {
  596. return STATUS_INVALID_PARAMETER;
  597. }
  598. if (!CsrValidateMessageBuffer(m, &b->Reserved, b->ReservedLen, sizeof(BYTE))) {
  599. return STATUS_INVALID_PARAMETER;
  600. }
  601. if (!CsrValidateMessageBuffer(m, &b->Desktop, b->DesktopLen, sizeof(BYTE))) {
  602. return STATUS_INVALID_PARAMETER;
  603. }
  604. if (!CsrValidateMessageBuffer(m, &b->StartupInfo, sizeof(STARTUPINFO), sizeof(BYTE))) {
  605. return STATUS_INVALID_PARAMETER;
  606. }
  607. if (bWowApp) { // wow call please
  608. BOOL bPif = b->VDMState & ASKING_FOR_PIF;
  609. // find the shared wow record that we are calling
  610. // to do that we look at iTask which (in case of shared wow
  611. // this could have been the very first call that we've made in so far
  612. // the iTask in this context procides us with
  613. // look for our beloved shared wow using the [supplied] task id
  614. Status = ENTER_WOW_CRITICAL();
  615. ASSERT(NT_SUCCESS(Status));
  616. // grab crit section for read access
  617. if (bPif && b->iTask) {
  618. // this is probably the very first call -- update session handles first
  619. Status = BaseSrvFindSharedWowRecordByTaskId(&gWowHead,
  620. b->iTask,
  621. &pSharedWow,
  622. &pWOWRecord);
  623. pSharedWow->hConsole = b->ConsoleHandle;
  624. }
  625. else { // this is not a pif -- find by a console handle then
  626. Status = BaseSrvFindSharedWowRecordByConsoleHandle(&gWowHead,
  627. b->ConsoleHandle,
  628. &pSharedWow);
  629. }
  630. // now if we have the share wow - party!
  631. if (!NT_SUCCESS(Status)) {
  632. KdPrint(("BaseSrvGetNextVDMCommand: Shared Wow has not been found. Console : 0x%x\n", b->ConsoleHandle));
  633. LEAVE_WOW_CRITICAL();
  634. return Status;
  635. }
  636. if (SequenceNumber != pSharedWow->SequenceNumber) {
  637. KdPrint(("BaseSrvGetNextVdmCommand: Shared wow sequence number doesn't match\n"));
  638. LEAVE_WOW_CRITICAL();
  639. return STATUS_INVALID_PARAMETER;
  640. }
  641. ASSERT(NULL != pSharedWow);
  642. //
  643. // WowExec is asking for a command. We never block when
  644. // asking for a WOW binary, since WOW no longer has a thread
  645. // blocked in GetNextVDMCommand. Instead, WowExec gets a
  646. // message posted to it by BaseSrv when there are command(s)
  647. // waiting for it, and it loops calling GetNextVDMCommand
  648. // until it fails -- but it must not block.
  649. //
  650. b->WaitObjectForVDM = 0;
  651. // Vadimb: this call should uniquelly identify the caller as this is
  652. // the task running on a particular winsta/desktop
  653. // thus, as such it should be picked up from the appropriate queue
  654. if (NULL == (pWOWRecord = BaseSrvCheckAvailableWOWCommand(pSharedWow))) {
  655. //
  656. // There's no command waiting for WOW, so just return.
  657. // This is where we used to cause blocking.
  658. //
  659. b->TitleLen =
  660. b->EnvLen =
  661. b->DesktopLen =
  662. b->ReservedLen =
  663. b->CmdLen =
  664. b->AppLen =
  665. b->PifLen =
  666. b->CurDirectoryLen = 0;
  667. LEAVE_WOW_CRITICAL();
  668. return ((ULONG)STATUS_SUCCESS);
  669. }
  670. lpVDMInfo = pWOWRecord->lpVDMInfo;
  671. if (bPif) { // this is initial call made by ntvdm
  672. Status = BaseSrvFillPifInfo (lpVDMInfo,b);
  673. LEAVE_WOW_CRITICAL();
  674. return (Status);
  675. }
  676. }
  677. else {
  678. //
  679. // DOS VDM or Separate WOW is asking for next command.
  680. //
  681. Status = RtlEnterCriticalSection( &BaseSrvDOSCriticalSection );
  682. ASSERT(NT_SUCCESS(Status));
  683. if (b->VDMState & ASKING_FOR_PIF && b->iTask)
  684. Status = GetConsoleRecordDosSesId(b->iTask,&pConsoleRecord);
  685. else
  686. Status = BaseSrvGetConsoleRecord(b->ConsoleHandle,&pConsoleRecord);
  687. if (!NT_SUCCESS (Status) || SequenceNumber != pConsoleRecord->SequenceNumber) {
  688. RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
  689. KdPrint(("BaseSrvGetNextVdmCommand: Couldn't find dos record or sequence numbers don't match\n"));
  690. return ((ULONG)STATUS_INVALID_PARAMETER);
  691. }
  692. pDOSRecord = pConsoleRecord->DOSRecord;
  693. if (b->VDMState & ASKING_FOR_PIF) {
  694. if (pDOSRecord) {
  695. Status = BaseSrvFillPifInfo (pDOSRecord->lpVDMInfo,b);
  696. if (b->iTask) {
  697. if (!pConsoleRecord->hConsole) {
  698. pConsoleRecord->hConsole = b->ConsoleHandle;
  699. pConsoleRecord->DosSesId = 0;
  700. }
  701. else {
  702. Status = STATUS_INVALID_PARAMETER;
  703. }
  704. }
  705. }
  706. else {
  707. Status = STATUS_INVALID_PARAMETER;
  708. }
  709. RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
  710. return (Status);
  711. }
  712. if (!bSepWow) {
  713. if (!(b->VDMState & (ASKING_FOR_FIRST_COMMAND |
  714. ASKING_FOR_SECOND_TIME |
  715. NO_PARENT_TO_WAKE))
  716. || (b->VDMState & ASKING_FOR_SECOND_TIME && b->ExitCode != 0))
  717. {
  718. // Search first VDM_TO_TAKE_A_COMMAND or last VDM_BUSY record as
  719. // per the case.
  720. if (b->VDMState & ASKING_FOR_SECOND_TIME){
  721. while(pDOSRecord && pDOSRecord->VDMState != VDM_TO_TAKE_A_COMMAND)
  722. pDOSRecord = pDOSRecord->DOSRecordNext;
  723. }
  724. else {
  725. while(pDOSRecord){
  726. if(pDOSRecord->VDMState == VDM_BUSY)
  727. pDOSRecordTemp = pDOSRecord;
  728. pDOSRecord = pDOSRecord->DOSRecordNext;
  729. }
  730. pDOSRecord = pDOSRecordTemp;
  731. }
  732. if (pDOSRecord == NULL) {
  733. RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
  734. return STATUS_SUCCESS;
  735. }
  736. pDOSRecord->ErrorCode = b->ExitCode;
  737. pDOSRecord->VDMState = VDM_HAS_RETURNED_ERROR_CODE;
  738. NtSetEvent (pDOSRecord->hWaitForParentDup,NULL);
  739. NtClose (pDOSRecord->hWaitForParentDup);
  740. pDOSRecord->hWaitForParentDup = 0;
  741. pDOSRecord = pDOSRecord->DOSRecordNext;
  742. }
  743. }
  744. while (pDOSRecord && pDOSRecord->VDMState != VDM_TO_TAKE_A_COMMAND)
  745. pDOSRecord = pDOSRecord->DOSRecordNext;
  746. if (pDOSRecord == NULL) {
  747. if (bSepWow ||
  748. (b->VDMState & RETURN_ON_NO_COMMAND && b->VDMState & ASKING_FOR_SECOND_TIME))
  749. {
  750. b->WaitObjectForVDM = 0;
  751. RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
  752. return ((ULONG)STATUS_NO_MEMORY);
  753. }
  754. if(pConsoleRecord->hWaitForVDMDup == 0 ){
  755. if(NT_SUCCESS(BaseSrvCreatePairWaitHandles (&Handle,
  756. &TargetHandle))){
  757. pConsoleRecord->hWaitForVDMDup = Handle;
  758. pConsoleRecord->hWaitForVDM = TargetHandle;
  759. }
  760. else {
  761. b->WaitObjectForVDM = 0;
  762. RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
  763. return ((ULONG)STATUS_NO_MEMORY);
  764. }
  765. }
  766. else {
  767. NtResetEvent(pConsoleRecord->hWaitForVDMDup,&WaitState);
  768. }
  769. b->WaitObjectForVDM = pConsoleRecord->hWaitForVDM;
  770. RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
  771. return STATUS_SUCCESS;
  772. }
  773. b->WaitObjectForVDM = 0;
  774. lpVDMInfo = pDOSRecord->lpVDMInfo;
  775. }
  776. //
  777. // ASKING_FOR_ENVIRONMENT
  778. // Return the information but DO NOT delete the lpVDMInfo
  779. // associated with the DOS record
  780. // ONLY DOS APPS NEED THIS
  781. //
  782. if (b->VDMState & ASKING_FOR_ENVIRONMENT) {
  783. if (lpVDMInfo->EnviornmentSize <= b->EnvLen) {
  784. RtlMoveMemory(b->Env,
  785. lpVDMInfo->Enviornment,
  786. lpVDMInfo->EnviornmentSize);
  787. Status = STATUS_SUCCESS;
  788. }
  789. else {
  790. Status = STATUS_INVALID_PARAMETER;
  791. }
  792. b->EnvLen = lpVDMInfo->EnviornmentSize;
  793. if (bWowApp) {
  794. LEAVE_WOW_CRITICAL();
  795. }
  796. else {
  797. RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
  798. }
  799. return Status;
  800. }
  801. //
  802. // check buffer sizes, CmdLine is mandatory!
  803. //
  804. if (!b->CmdLine || lpVDMInfo->CmdSize > b->CmdLen ||
  805. (b->AppName && lpVDMInfo->AppLen > b->AppLen) ||
  806. (b->Env && lpVDMInfo->EnviornmentSize > b->EnvLen) ||
  807. (b->PifFile && lpVDMInfo->PifLen > b->PifLen) ||
  808. (b->CurDirectory && lpVDMInfo->CurDirectoryLen > b->CurDirectoryLen) ||
  809. (b->Title && lpVDMInfo->TitleLen > b->TitleLen) ||
  810. (b->Reserved && lpVDMInfo->ReservedLen > b->ReservedLen) ||
  811. (b->Desktop && lpVDMInfo->DesktopLen > b->DesktopLen)) {
  812. Status = STATUS_INVALID_PARAMETER;
  813. }
  814. else {
  815. Status = STATUS_SUCCESS;
  816. }
  817. b->CmdLen = lpVDMInfo->CmdSize;
  818. b->AppLen = lpVDMInfo->AppLen;
  819. b->PifLen = lpVDMInfo->PifLen;
  820. b->EnvLen = lpVDMInfo->EnviornmentSize;
  821. b->CurDirectoryLen = lpVDMInfo->CurDirectoryLen;
  822. b->DesktopLen = lpVDMInfo->DesktopLen;
  823. b->TitleLen = lpVDMInfo->TitleLen;
  824. b->ReservedLen = lpVDMInfo->ReservedLen;
  825. if (!NT_SUCCESS(Status)) {
  826. if (bWowApp) {
  827. LEAVE_WOW_CRITICAL();
  828. }
  829. else {
  830. RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
  831. }
  832. return (Status);
  833. }
  834. if (lpVDMInfo->CmdLine && b->CmdLine)
  835. RtlMoveMemory(b->CmdLine,
  836. lpVDMInfo->CmdLine,
  837. lpVDMInfo->CmdSize);
  838. if (lpVDMInfo->AppName && b->AppName)
  839. RtlMoveMemory(b->AppName,
  840. lpVDMInfo->AppName,
  841. lpVDMInfo->AppLen);
  842. if (lpVDMInfo->PifFile && b->PifFile)
  843. RtlMoveMemory(b->PifFile,
  844. lpVDMInfo->PifFile,
  845. lpVDMInfo->PifLen);
  846. if (lpVDMInfo->CurDirectory && b->CurDirectory)
  847. RtlMoveMemory(b->CurDirectory,
  848. lpVDMInfo->CurDirectory,
  849. lpVDMInfo->CurDirectoryLen);
  850. if (lpVDMInfo->Title && b->Title)
  851. RtlMoveMemory(b->Title,
  852. lpVDMInfo->Title,
  853. lpVDMInfo->TitleLen);
  854. if (lpVDMInfo->Reserved && b->Reserved)
  855. RtlMoveMemory(b->Reserved,
  856. lpVDMInfo->Reserved,
  857. lpVDMInfo->ReservedLen);
  858. if (lpVDMInfo->Enviornment && b->Env)
  859. RtlMoveMemory(b->Env,
  860. lpVDMInfo->Enviornment,
  861. lpVDMInfo->EnviornmentSize);
  862. if (lpVDMInfo->VDMState & STARTUP_INFO_RETURNED)
  863. RtlMoveMemory(b->StartupInfo,
  864. &lpVDMInfo->StartupInfo,
  865. sizeof (STARTUPINFOA));
  866. if (lpVDMInfo->Desktop && b->Desktop)
  867. RtlMoveMemory(b->Desktop,
  868. lpVDMInfo->Desktop,
  869. lpVDMInfo->DesktopLen);
  870. if ((pBatRecord = BaseSrvGetBatRecord (b->ConsoleHandle)) != NULL)
  871. b->fComingFromBat = TRUE;
  872. else
  873. b->fComingFromBat = FALSE;
  874. b->CurrentDrive = lpVDMInfo->CurDrive;
  875. b->CodePage = lpVDMInfo->CodePage;
  876. b->dwCreationFlags = lpVDMInfo->dwCreationFlags;
  877. b->VDMState = lpVDMInfo->VDMState;
  878. if (bWowApp) {
  879. b->iTask = pWOWRecord->iTask;
  880. pWOWRecord->fDispatched = TRUE;
  881. }
  882. else {
  883. pDOSRecord->VDMState = VDM_BUSY;
  884. }
  885. b->StdIn = lpVDMInfo->StdIn;
  886. b->StdOut = lpVDMInfo->StdOut;
  887. b->StdErr = lpVDMInfo->StdErr;
  888. if (bSepWow) {
  889. // this was a sep wow request -- we have done this only record that is to
  890. // be dispatched to this particular wow -- now just remove every trace of
  891. // this wow on the server side...
  892. NtClose( pConsoleRecord->hVDM );
  893. BaseSrvFreeConsoleRecord(pConsoleRecord); // unwire as well
  894. RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
  895. }
  896. else {
  897. // this is shared wow or dos app -- free vdm info and release the
  898. // appropriate sync object
  899. BaseSrvFreeVDMInfo (lpVDMInfo);
  900. // BUGBUG -- fixed
  901. if (bWowApp) {
  902. pWOWRecord->lpVDMInfo = NULL;
  903. LEAVE_WOW_CRITICAL();
  904. }
  905. else {
  906. pDOSRecord->lpVDMInfo = NULL;
  907. RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
  908. }
  909. }
  910. return Status;
  911. } // END of GetNextVdmCommand
  912. ULONG
  913. BaseSrvExitVDM(
  914. IN OUT PCSR_API_MSG m,
  915. IN OUT PCSR_REPLY_STATUS ReplyStatus
  916. )
  917. {
  918. PBASE_EXIT_VDM_MSG b = (PBASE_EXIT_VDM_MSG)&m->u.ApiMessageData;
  919. NTSTATUS Status;
  920. ULONG SequenceNumber;
  921. if(!NT_SUCCESS(BaseSrvGetVdmSequence(m->h.ClientId.UniqueProcess, &SequenceNumber))) {
  922. return (ULONG)STATUS_INVALID_PARAMETER;
  923. }
  924. if (b->iWowTask) {
  925. Status = BaseSrvExitWOWTask(b, SequenceNumber);
  926. }
  927. else {
  928. Status = BaseSrvExitDOSTask(b, SequenceNumber);
  929. }
  930. return Status;
  931. }
  932. ULONG
  933. BaseSrvIsFirstVDM(
  934. IN OUT PCSR_API_MSG m,
  935. IN OUT PCSR_REPLY_STATUS ReplyStatus
  936. )
  937. {
  938. PBASE_IS_FIRST_VDM_MSG c = (PBASE_IS_FIRST_VDM_MSG)&m->u.ApiMessageData;
  939. if(!NT_SUCCESS(BaseSrvIsClientVdm(m->h.ClientId.UniqueProcess))) {
  940. return STATUS_ACCESS_DENIED;
  941. }
  942. c->FirstVDM = fIsFirstVDM;
  943. if(fIsFirstVDM)
  944. fIsFirstVDM = FALSE;
  945. return STATUS_SUCCESS;
  946. }
  947. //
  948. // This call should only be used for DOS apps and not for wow apps
  949. // hence we don't remove ConsoleHandle == -1 condition here as it is
  950. // only a validation check
  951. //
  952. //
  953. ULONG
  954. BaseSrvSetVDMCurDirs(
  955. IN OUT PCSR_API_MSG m,
  956. IN OUT PCSR_REPLY_STATUS ReplyStatus
  957. )
  958. {
  959. NTSTATUS Status;
  960. PBASE_GET_SET_VDM_CUR_DIRS_MSG b = (PBASE_GET_SET_VDM_CUR_DIRS_MSG)&m->u.ApiMessageData;
  961. PCONSOLERECORD pConsoleRecord;
  962. ULONG SequenceNumber;
  963. if (b->ConsoleHandle == (HANDLE) -1) {
  964. return (ULONG) STATUS_INVALID_PARAMETER;
  965. }
  966. if (!CsrValidateMessageBuffer(m, &b->lpszzCurDirs, b->cchCurDirs, sizeof(BYTE))) {
  967. return STATUS_INVALID_PARAMETER;
  968. }
  969. if(!NT_SUCCESS(BaseSrvGetVdmSequence(m->h.ClientId.UniqueProcess, &SequenceNumber))) {
  970. return (ULONG)STATUS_INVALID_PARAMETER;
  971. }
  972. Status = RtlEnterCriticalSection( &BaseSrvDOSCriticalSection );
  973. ASSERT(NT_SUCCESS(Status));
  974. Status = BaseSrvGetConsoleRecord(b->ConsoleHandle,&pConsoleRecord);
  975. if (!NT_SUCCESS (Status) || SequenceNumber != pConsoleRecord->SequenceNumber) {
  976. RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
  977. return ((ULONG)STATUS_INVALID_PARAMETER);
  978. }
  979. if (pConsoleRecord->lpszzCurDirs) {
  980. RtlFreeHeap(BaseSrvHeap, 0, pConsoleRecord->lpszzCurDirs);
  981. pConsoleRecord->lpszzCurDirs = NULL;
  982. pConsoleRecord->cchCurDirs = 0;
  983. }
  984. if (b->cchCurDirs && b->lpszzCurDirs) {
  985. pConsoleRecord->lpszzCurDirs = RtlAllocateHeap(
  986. BaseSrvHeap,
  987. MAKE_TAG( VDM_TAG ),
  988. b->cchCurDirs
  989. );
  990. if (pConsoleRecord->lpszzCurDirs == NULL) {
  991. pConsoleRecord->cchCurDirs = 0;
  992. RtlLeaveCriticalSection(&BaseSrvDOSCriticalSection);
  993. return (ULONG)STATUS_NO_MEMORY;
  994. }
  995. RtlMoveMemory(pConsoleRecord->lpszzCurDirs,
  996. b->lpszzCurDirs,
  997. b->cchCurDirs
  998. );
  999. pConsoleRecord->cchCurDirs = b->cchCurDirs;
  1000. RtlLeaveCriticalSection(&BaseSrvDOSCriticalSection);
  1001. return (ULONG) STATUS_SUCCESS;
  1002. }
  1003. RtlLeaveCriticalSection(&BaseSrvDOSCriticalSection);
  1004. return (ULONG) STATUS_INVALID_PARAMETER;
  1005. }
  1006. ULONG
  1007. BaseSrvBatNotification(
  1008. IN OUT PCSR_API_MSG m,
  1009. IN OUT PCSR_REPLY_STATUS ReplyStatus
  1010. )
  1011. {
  1012. NTSTATUS Status;
  1013. PBATRECORD pBatRecord;
  1014. PBASE_BAT_NOTIFICATION_MSG b = (PBASE_BAT_NOTIFICATION_MSG)&m->u.ApiMessageData;
  1015. Status = RtlEnterCriticalSection( &BaseSrvDOSCriticalSection );
  1016. ASSERT(NT_SUCCESS(Status));
  1017. // If BATRECORD does'nt exist for this console, create one only if
  1018. // bat file execution is beginig i.e. fBeginEnd is TRUE.
  1019. if ((pBatRecord = BaseSrvGetBatRecord(b->ConsoleHandle)) == NULL) {
  1020. if (!(b->fBeginEnd == CMD_BAT_OPERATION_STARTING &&
  1021. (pBatRecord = BaseSrvAllocateAndAddBatRecord (b->ConsoleHandle)))) {
  1022. RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
  1023. return ((ULONG)STATUS_SUCCESS);
  1024. }
  1025. }
  1026. else if (b->fBeginEnd == CMD_BAT_OPERATION_TERMINATING)
  1027. BaseSrvFreeAndRemoveBatRecord (pBatRecord);
  1028. RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
  1029. return ((ULONG)STATUS_SUCCESS);
  1030. }
  1031. ULONG
  1032. BaseSrvRegisterWowExec(
  1033. IN OUT PCSR_API_MSG m,
  1034. IN OUT PCSR_REPLY_STATUS ReplyStatus
  1035. )
  1036. {
  1037. PBASE_REGISTER_WOWEXEC_MSG b = (PBASE_REGISTER_WOWEXEC_MSG)&m->u.ApiMessageData;
  1038. UNICODE_STRING ModuleNameString_U;
  1039. PVOID ModuleHandle;
  1040. STRING ProcedureNameString;
  1041. NTSTATUS Status;
  1042. PCSR_PROCESS Process;
  1043. PSHAREDWOWRECORD pSharedWow;
  1044. ULONG SequenceNumber;
  1045. Status = ENTER_WOW_CRITICAL();
  1046. ASSERT( NT_SUCCESS( Status ) );
  1047. //
  1048. // Do a run-time link to PostMessageA and GetWindowThreadProcessId
  1049. // which we'll use to post messages to WowExec.
  1050. //
  1051. if (NULL == BaseSrvPostMessageA) {
  1052. // this is an impossible event as all the imports are inited at once
  1053. KdPrint(("BaseSrvRegisterWowExec: Api PostMessage is not available to BaseSrv\n"));
  1054. ASSERT(FALSE);
  1055. Status = STATUS_INVALID_PARAMETER;
  1056. goto Cleanup;
  1057. }
  1058. Status = BaseSrvFindSharedWowRecordByConsoleHandle(&gWowHead,
  1059. b->ConsoleHandle,
  1060. &pSharedWow);
  1061. if (!NT_SUCCESS(Status)) {
  1062. KdPrint(("BaseSrvRegisterWowExec: Could not find record for wow console handle 0x%lx\n", b->ConsoleHandle));
  1063. goto Cleanup;
  1064. }
  1065. if(!NT_SUCCESS(BaseSrvGetVdmSequence(m->h.ClientId.UniqueProcess, &SequenceNumber)) ||
  1066. SequenceNumber != pSharedWow->SequenceNumber) {
  1067. Status = STATUS_INVALID_PARAMETER;
  1068. KdPrint(("BaseSrvRegisterWowExec: SequenceNumber didn't match\n"));
  1069. goto Cleanup;
  1070. }
  1071. ASSERT(NULL != pSharedWow);
  1072. // see what the window handle is -- special "die wow, die" case
  1073. if (NULL == b->hwndWowExec) {
  1074. //
  1075. // Shared WOW is calling to de-register itself as part of shutdown.
  1076. // Protocol is we check for pending commands for this shared WOW,
  1077. // if there are any we fail this call, otherwise we set our
  1078. // hwndWowExec to NULL and succeed the call, ensuring no more
  1079. // commands will be added to this queue.
  1080. //
  1081. if (NULL != pSharedWow->pWOWRecord) {
  1082. Status = STATUS_MORE_PROCESSING_REQUIRED;
  1083. }
  1084. else { // no tasks for this wow
  1085. // it goes KABOOOOOOM!!!!!
  1086. Status = BaseSrvDeleteSharedWowRecord(&gWowHead, pSharedWow);
  1087. }
  1088. goto Cleanup;
  1089. }
  1090. if (pSharedWow->hwndWowExec) {
  1091. // Shared WOW windows was already registered
  1092. // someone else is trying to overwrite it, so don't allow it
  1093. Status = STATUS_INVALID_PARAMETER;
  1094. goto Cleanup;
  1095. }
  1096. // set the window handle
  1097. pSharedWow->hwndWowExec = b->hwndWowExec;
  1098. // rettrieve thread and process id of the calling process
  1099. pSharedWow->dwWowExecThreadId = BaseSrvGetWindowThreadProcessId(
  1100. pSharedWow->hwndWowExec,
  1101. &pSharedWow->dwWowExecProcessId);
  1102. Cleanup:
  1103. LEAVE_WOW_CRITICAL();
  1104. return (ULONG)Status;
  1105. }
  1106. PBATRECORD
  1107. BaseSrvGetBatRecord(
  1108. IN HANDLE hConsole
  1109. )
  1110. {
  1111. PBATRECORD pBatRecord = BatRecordHead;
  1112. while (pBatRecord && pBatRecord->hConsole != hConsole)
  1113. pBatRecord = pBatRecord->BatRecordNext;
  1114. return pBatRecord;
  1115. }
  1116. PBATRECORD
  1117. BaseSrvAllocateAndAddBatRecord(
  1118. HANDLE hConsole
  1119. )
  1120. {
  1121. PCSR_THREAD t;
  1122. PBATRECORD pBatRecord;
  1123. if((pBatRecord = RtlAllocateHeap(RtlProcessHeap (),
  1124. MAKE_TAG( VDM_TAG ),
  1125. sizeof(BATRECORD))) == NULL)
  1126. return NULL;
  1127. t = CSR_SERVER_QUERYCLIENTTHREAD();
  1128. pBatRecord->hConsole = hConsole;
  1129. pBatRecord->SequenceNumber = t->Process->SequenceNumber;
  1130. pBatRecord->BatRecordNext = BatRecordHead;
  1131. BatRecordHead = pBatRecord;
  1132. return pBatRecord;
  1133. }
  1134. VOID
  1135. BaseSrvFreeAndRemoveBatRecord(
  1136. PBATRECORD pBatRecordToFree
  1137. )
  1138. {
  1139. PBATRECORD pBatRecord = BatRecordHead;
  1140. PBATRECORD pBatRecordLast = NULL;
  1141. while (pBatRecord && pBatRecord != pBatRecordToFree){
  1142. pBatRecordLast = pBatRecord;
  1143. pBatRecord = pBatRecord->BatRecordNext;
  1144. }
  1145. if (pBatRecord == NULL)
  1146. return;
  1147. if (pBatRecordLast)
  1148. pBatRecordLast->BatRecordNext = pBatRecord->BatRecordNext;
  1149. else
  1150. BatRecordHead = pBatRecord->BatRecordNext;
  1151. RtlFreeHeap ( RtlProcessHeap (), 0, pBatRecord);
  1152. return;
  1153. }
  1154. ULONG
  1155. BaseSrvGetVDMCurDirs(
  1156. IN OUT PCSR_API_MSG m,
  1157. IN OUT PCSR_REPLY_STATUS ReplyStatus
  1158. )
  1159. {
  1160. NTSTATUS Status;
  1161. PBASE_GET_SET_VDM_CUR_DIRS_MSG b = (PBASE_GET_SET_VDM_CUR_DIRS_MSG)&m->u.ApiMessageData;
  1162. PCONSOLERECORD pConsoleRecord;
  1163. if (!CsrValidateMessageBuffer(m, &b->lpszzCurDirs, b->cchCurDirs, sizeof(BYTE))) {
  1164. return STATUS_INVALID_PARAMETER;
  1165. }
  1166. Status = RtlEnterCriticalSection( &BaseSrvDOSCriticalSection );
  1167. ASSERT(NT_SUCCESS(Status));
  1168. Status = BaseSrvGetConsoleRecord(b->ConsoleHandle,&pConsoleRecord);
  1169. if (!NT_SUCCESS (Status)) {
  1170. RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
  1171. b->cchCurDirs = 0;
  1172. return ((ULONG)STATUS_INVALID_PARAMETER);
  1173. }
  1174. if (pConsoleRecord->lpszzCurDirs != NULL){
  1175. if (b->cchCurDirs < pConsoleRecord->cchCurDirs || b->lpszzCurDirs == NULL)
  1176. {
  1177. b->cchCurDirs = pConsoleRecord->cchCurDirs;
  1178. RtlLeaveCriticalSection(&BaseSrvDOSCriticalSection);
  1179. return ((ULONG)STATUS_INVALID_PARAMETER);
  1180. }
  1181. else {
  1182. RtlMoveMemory(b->lpszzCurDirs,
  1183. pConsoleRecord->lpszzCurDirs,
  1184. pConsoleRecord->cchCurDirs
  1185. );
  1186. // remove it immediately after the copy. This is done because
  1187. // the next command may be a WOW program(got tagged process handle
  1188. // as VDM command) and in that case we will return incorrect
  1189. //information:
  1190. // c:\>
  1191. // c:\>d:
  1192. // d:\>cd \foo
  1193. // d:\foo>dosapp
  1194. // d:\foo>c:
  1195. // c:\>wowapp
  1196. // d:\foo> -- this is wrong if we don't do the following stuff.
  1197. RtlFreeHeap(BaseSrvHeap, 0, pConsoleRecord->lpszzCurDirs);
  1198. pConsoleRecord->lpszzCurDirs = NULL;
  1199. b->cchCurDirs = pConsoleRecord->cchCurDirs;
  1200. pConsoleRecord->cchCurDirs = 0;
  1201. }
  1202. }
  1203. else {
  1204. b->cchCurDirs = 0;
  1205. }
  1206. RtlLeaveCriticalSection(&BaseSrvDOSCriticalSection);
  1207. return ((ULONG)STATUS_SUCCESS);
  1208. }
  1209. //
  1210. // temporary static desktop name buffer
  1211. // BUGBUG -- change when User gives me better return values
  1212. //
  1213. WCHAR wszDesktopName[MAX_PATH];
  1214. //
  1215. // This call produces a desktop name and optionally a shared wow running in the context
  1216. // of this particular desktop.
  1217. // extra bad: making conversion Uni->Ansi in client/vdm.c and ansi->Uni here
  1218. // this is BUGBUG -- look into it later
  1219. //
  1220. // this function returns success in all the cases (including when wow is not found)
  1221. // and fails only if under-layers return failures
  1222. NTSTATUS
  1223. BaseSrvFindSharedWow(
  1224. IN PBASE_CHECKVDM_MSG b,
  1225. IN HANDLE UniqueProcessClientId,
  1226. IN OUT PUNICODE_STRING pDesktopName,
  1227. IN OUT PSHAREDWOWRECORD* ppSharedWowRecord)
  1228. {
  1229. ANSI_STRING DesktopNameAnsi;
  1230. BOOLEAN fRevertToSelf;
  1231. NTSTATUS Status;
  1232. // the first time out, we have not dyna-linked NtUserResolveDesktopForWow, so
  1233. // as an optimization, check to see if the list of shared wows is empty
  1234. // see if we need to dyna-link
  1235. if (NULL == BaseSrvUserResolveDesktopForWow) {
  1236. Status = BaseSrvImportApis(rgBaseSrvModuleImport,
  1237. sizeof(rgBaseSrvModuleImport)/sizeof(rgBaseSrvModuleImport[0]));
  1238. if (!NT_SUCCESS(Status)) {
  1239. KdPrint(("BaseSrvFindSharedWow: Failed to dyna-link apis\n"));
  1240. return Status;
  1241. }
  1242. }
  1243. if (b->DesktopLen == 0) {
  1244. return STATUS_INVALID_PARAMETER;
  1245. }
  1246. ASSERT(NULL != BaseSrvUserResolveDesktopForWow);
  1247. pDesktopName->Buffer = wszDesktopName;
  1248. pDesktopName->MaximumLength = sizeof(wszDesktopName);
  1249. DesktopNameAnsi.Buffer = b->Desktop;
  1250. DesktopNameAnsi.Length = (USHORT)(b->DesktopLen - 1);
  1251. DesktopNameAnsi.MaximumLength = (USHORT)(b->DesktopLen);
  1252. RtlAnsiStringToUnicodeString(pDesktopName, &DesktopNameAnsi, FALSE);
  1253. // now get the real desktop name there
  1254. // impersonate
  1255. fRevertToSelf = CsrImpersonateClient(NULL);
  1256. if (!fRevertToSelf) {
  1257. return STATUS_BAD_IMPERSONATION_LEVEL;
  1258. }
  1259. Status = BaseSrvUserResolveDesktopForWow(pDesktopName);
  1260. CsrRevertToSelf();
  1261. if (!NT_SUCCESS(Status)) {
  1262. // show that desktop is not valid name here by invalidating the pointer to buffer
  1263. pDesktopName->Buffer = NULL;
  1264. pDesktopName->MaximumLength = 0;
  1265. pDesktopName->Length = 0;
  1266. return Status;
  1267. }
  1268. // now look for this dektop in our task list
  1269. Status = BaseSrvFindSharedWowRecordByDesktop(&gWowHead,
  1270. pDesktopName,
  1271. ppSharedWowRecord);
  1272. if (!NT_SUCCESS(Status)) {
  1273. *ppSharedWowRecord = NULL;
  1274. }
  1275. return STATUS_SUCCESS;
  1276. }
  1277. ULONG
  1278. BaseSrvCheckWOW( //////////////////////////////////// NEW IMP
  1279. IN PBASE_CHECKVDM_MSG b,
  1280. IN HANDLE UniqueProcessClientId
  1281. )
  1282. {
  1283. NTSTATUS Status;
  1284. HANDLE Handle,TargetHandle;
  1285. PWOWRECORD pWOWRecord;
  1286. INFORECORD InfoRecord;
  1287. USHORT Len;
  1288. LUID ClientAuthId;
  1289. DWORD dwThreadId, dwProcessId;
  1290. PCSR_PROCESS Process;
  1291. PSHAREDWOWRECORD pSharedWow = NULL;
  1292. PSHAREDWOWRECORD pSharedWowPrev;
  1293. UNICODE_STRING DesktopName;
  1294. PCSR_PROCESS ParentProcess;
  1295. HANDLE WOWUserToken = NULL;
  1296. Status = ENTER_WOW_CRITICAL();
  1297. ASSERT( NT_SUCCESS( Status ) );
  1298. // see if what we have in startup info matches any of the existing wow vdms
  1299. DesktopName.Buffer = NULL;
  1300. Status = BaseSrvFindSharedWow(b,
  1301. UniqueProcessClientId,
  1302. &DesktopName,
  1303. &pSharedWow);
  1304. if (!NT_SUCCESS(Status)) {
  1305. ASSERT(FALSE); // this is some sort of a system error
  1306. b->DesktopLen = 0; // indicate desktop access was denied/not existing
  1307. LEAVE_WOW_CRITICAL();
  1308. return Status;
  1309. }
  1310. //
  1311. // here we could either have succeeded and have a shared wow or not -
  1312. // and hence have a desktop name in a global buffer pointed to by DesktopName.Buffer
  1313. //
  1314. if (NULL != pSharedWow) {
  1315. BOOLEAN fEqual;
  1316. switch(pSharedWow->VDMState & VDM_READY) {
  1317. case VDM_READY:
  1318. // meaning: vdm ready to take a command
  1319. // verify if the currently logged-on interactive user will be able to take out task
  1320. //
  1321. Status = OkToRunInSharedWOW( UniqueProcessClientId,
  1322. &ClientAuthId,
  1323. &WOWUserToken
  1324. );
  1325. if (NT_SUCCESS(Status)) {
  1326. if (!RtlEqualLuid(&ClientAuthId, &pSharedWow->WowAuthId)) {
  1327. Status = STATUS_ACCESS_DENIED;
  1328. }
  1329. else if (b->UserLuid && !RtlEqualLuid(&ClientAuthId, b->UserLuid)) {
  1330. Status = STATUS_ACCESS_DENIED;
  1331. }
  1332. else if(!NT_SUCCESS(NtCompareTokens(WOWUserToken,pSharedWow->WOWUserToken,&fEqual) || !fEqual)) {
  1333. Status = STATUS_ACCESS_DENIED;
  1334. }
  1335. }
  1336. if(WOWUserToken) {
  1337. NtClose(WOWUserToken);
  1338. }
  1339. if (!NT_SUCCESS(Status)) {
  1340. LEAVE_WOW_CRITICAL();
  1341. return ((ULONG)Status);
  1342. }
  1343. // now we have verified that user 1) has access to this desktop
  1344. // 2) is a currently logged-on interactive user
  1345. // Allocate a record for this wow task
  1346. if (NULL == (pWOWRecord = BaseSrvAllocateWOWRecord(&gWowHead))) {
  1347. Status = STATUS_NO_MEMORY;
  1348. break; // failed with mem alloc -- still holding task critical
  1349. }
  1350. // copy the command parameters
  1351. InfoRecord.iTag = BINARY_TYPE_WIN16;
  1352. InfoRecord.pRecord.pWOWRecord = pWOWRecord;
  1353. if (BaseSrvCopyCommand (b,&InfoRecord) == FALSE){
  1354. BaseSrvFreeWOWRecord(pWOWRecord);
  1355. Status = STATUS_NO_MEMORY;
  1356. break; // holding task critical
  1357. }
  1358. // create pseudo handles
  1359. Status = BaseSrvCreatePairWaitHandles (&Handle,&TargetHandle);
  1360. if (!NT_SUCCESS(Status) ){
  1361. BaseSrvFreeWOWRecord(pWOWRecord);
  1362. break;
  1363. }
  1364. else {
  1365. pWOWRecord->hWaitForParent = Handle;
  1366. pWOWRecord->hWaitForParentServer = TargetHandle;
  1367. b->WaitObjectForParent = TargetHandle; // give the handle back to the client
  1368. }
  1369. // set the state and task id, task id is allocated in BaseSrvAllocateWowRecord
  1370. b->VDMState = VDM_PRESENT_AND_READY;
  1371. b->iTask = pWOWRecord->iTask;
  1372. // add wow record to this shared wow list
  1373. BaseSrvAddWOWRecord (pSharedWow, pWOWRecord);
  1374. // let User know we have been started
  1375. if (NULL != UserNotifyProcessCreate) {
  1376. (*UserNotifyProcessCreate)(pWOWRecord->iTask,
  1377. (DWORD)((ULONG_PTR)CSR_SERVER_QUERYCLIENTTHREAD()->ClientId.UniqueThread),
  1378. (DWORD)((ULONG_PTR)TargetHandle),
  1379. 0x04);
  1380. }
  1381. // see if the wowexec window exists and is valid
  1382. if (NULL != pSharedWow->hwndWowExec) {
  1383. //
  1384. // Check to see if hwndWowExec still belongs to
  1385. // the same thread/process ID before posting.
  1386. //
  1387. // BUGBUG -- debug code here -- not really needed
  1388. dwThreadId = BaseSrvGetWindowThreadProcessId(pSharedWow->hwndWowExec,
  1389. &dwProcessId);
  1390. if (dwThreadId) {
  1391. ULONG SequenceNumber;
  1392. Status = BaseSrvGetVdmSequence((HANDLE)LongToPtr(dwProcessId), &SequenceNumber);
  1393. if (!NT_SUCCESS(Status) || SequenceNumber != pSharedWow->SequenceNumber) {
  1394. Status = STATUS_INVALID_PARAMETER;
  1395. }
  1396. }
  1397. else {
  1398. Status = STATUS_UNSUCCESSFUL;
  1399. KdPrint(("BaseSrvCheckWOW: Not authentic wow by process seq number\n"));
  1400. //
  1401. // Spurious assert was here. The wow process has died while the message was incoming.
  1402. // The code below will cleanup appropriately
  1403. //
  1404. }
  1405. if (dwThreadId == pSharedWow->dwWowExecThreadId &&
  1406. dwProcessId == pSharedWow->dwWowExecProcessId &&
  1407. NT_SUCCESS(Status)) {
  1408. HANDLE ThreadId;
  1409. /*
  1410. * Set the csr thread's desktop temporarily to the client
  1411. * it is servicing
  1412. */
  1413. BaseSrvPostMessageA((HWND)pSharedWow->hwndWowExec,
  1414. WM_WOWEXECSTARTAPP,
  1415. 0,
  1416. 0);
  1417. }
  1418. else {
  1419. //
  1420. // Thread/process IDs don't match, so forget about this shared WOW.
  1421. //
  1422. if ( NT_SUCCESS(Status) ) {
  1423. KdPrint(("BaseSrvCheckWOW: Thread/Process IDs don't match, shared WOW is gone.\n"
  1424. "Saved PID 0x%x TID 0x%x hwndWowExec (0x%x) maps to \n"
  1425. " PID 0x%x TID 0x%x\n",
  1426. pSharedWow->dwWowExecProcessId,
  1427. pSharedWow->dwWowExecThreadId,
  1428. pSharedWow->hwndWowExec,
  1429. dwProcessId,
  1430. dwThreadId));
  1431. }
  1432. // okay, panic! our internal list is in fact corrupted - remove the offending
  1433. // entry
  1434. // to do this we must have access -- relinquish control
  1435. // and then re-aquire it
  1436. BaseSrvDeleteSharedWowRecord(&gWowHead, pSharedWow);
  1437. // reset these values so that new shared wow is created
  1438. pSharedWow = NULL;
  1439. }
  1440. }
  1441. // ELSE
  1442. // if pSharedWow->hwndWowExec == NULL our shared wow doesn't have a window yet.
  1443. // however, it is ok to attach new wowrecord because we know shared wow's ntvdm is
  1444. // still alive. if it wasn't it would have been cleaned up by the process clean-up
  1445. // routine BaseSrvCleanupVDMResources.
  1446. break; // case VDM_READY
  1447. default:
  1448. KdPrint(("BaseSrvCheckWOW: bad vdm state: 0x%lx\n", pSharedWow->VDMState));
  1449. ASSERT(FALSE); // how did I get into this mess ?
  1450. break;
  1451. } // end switch
  1452. }
  1453. // if we are here then either :
  1454. // -- the first take on a shared wow failed
  1455. // -- the app was successfully handed off to wowexec for execution
  1456. // if pSharedWow is NULL, then we have to start shared wow in this environment
  1457. // as it was either not present or nuked due to seq number/id conflics
  1458. //
  1459. if (NULL == pSharedWow) {
  1460. //
  1461. // this check verifies command line for not being too long
  1462. //
  1463. if (b->CmdLen > MAXIMUM_VDM_COMMAND_LENGTH) {
  1464. LEAVE_WOW_CRITICAL();
  1465. return ((ULONG)STATUS_INVALID_PARAMETER);
  1466. }
  1467. //
  1468. // Only the currently logged on interactive user can start the
  1469. // shared wow. Verify if the caller is such, and if it is
  1470. // store the Authentication Id of the client which identifies who
  1471. // is allowed to run wow apps in the default ntvdm-wow process.
  1472. //
  1473. //
  1474. // if needed, do a run-time link to UserTestTokenForInteractive,
  1475. // which is used to verify the client luid.
  1476. //
  1477. // this dynalink is performed automatically using our all-out api
  1478. // see above for dynalink source
  1479. ASSERT (NULL != UserTestTokenForInteractive);
  1480. ASSERT (NULL != DesktopName.Buffer); // yes, it should be valid
  1481. //
  1482. // see if we had desktop there. if not (the first time around!) - get it now
  1483. // by calling FindSharedWow (which retrieves desktop as well)
  1484. //
  1485. //
  1486. // If the caller isn't the currently logged on interactive user,
  1487. // OkToRunInSharedWOW will fail with access denied.
  1488. Status = OkToRunInSharedWOW(UniqueProcessClientId,
  1489. &ClientAuthId,
  1490. &WOWUserToken);
  1491. if (NT_SUCCESS(Status)) {
  1492. if (b->UserLuid && !RtlEqualLuid(&ClientAuthId, b->UserLuid)) {
  1493. Status = STATUS_ACCESS_DENIED;
  1494. }
  1495. }
  1496. if (!NT_SUCCESS(Status)) {
  1497. if(WOWUserToken) {
  1498. NtClose(WOWUserToken);
  1499. }
  1500. LEAVE_WOW_CRITICAL();
  1501. return ((ULONG)Status);
  1502. }
  1503. //
  1504. // Store the Autherntication Id since this now is the currently
  1505. // logged on interactive user.
  1506. //
  1507. // produce a viable shared wow record
  1508. // this process consists of 2 parts : producing a wow record and producing a
  1509. // console record. the reason for this is to be able to identify this record
  1510. // when the wow process had been created and is calling to update a record with it's
  1511. // own handle (this is twise confusing, but just bear with me for a while).
  1512. //
  1513. // just as a dos program, we might need a temporary session id or a console id for the
  1514. // creating process.
  1515. pSharedWow = BaseSrvAllocateSharedWowRecord(&DesktopName);
  1516. if (NULL == pSharedWow) {
  1517. Status = STATUS_NO_MEMORY;
  1518. }
  1519. //
  1520. // Store the WOWUserToken since this gives better granularity then just user id
  1521. //
  1522. pSharedWow->WOWUserToken = WOWUserToken;
  1523. //
  1524. // Store parent process sequence number until ntvdm
  1525. // comes and gives its sequence number
  1526. //
  1527. Status = CsrLockProcessByClientId(UniqueProcessClientId,
  1528. &ParentProcess);
  1529. if (NT_SUCCESS(Status)) {
  1530. pSharedWow->ParentSequenceNumber = ParentProcess->SequenceNumber;
  1531. CsrUnlockProcess(ParentProcess);
  1532. }
  1533. if (NT_SUCCESS(Status)) {
  1534. pSharedWow->pWOWRecord = BaseSrvAllocateWOWRecord(&gWowHead); // this is a new shared wow
  1535. if (NULL == pSharedWow->pWOWRecord) {
  1536. Status = STATUS_NO_MEMORY;
  1537. }
  1538. }
  1539. if (NT_SUCCESS(Status)) {
  1540. // here we have [successfully] allocated shared struct and a console record
  1541. // and a wow record for the task
  1542. // copy the command parameters
  1543. InfoRecord.iTag = BINARY_TYPE_WIN16;
  1544. InfoRecord.pRecord.pWOWRecord = pSharedWow->pWOWRecord;
  1545. if(!BaseSrvCopyCommand (b, &InfoRecord)) {
  1546. Status = STATUS_NO_MEMORY;
  1547. }
  1548. }
  1549. if (NT_SUCCESS(Status)) {
  1550. #if 0
  1551. pSharedWow->WowSessionId = BaseSrvGetWOWTaskId(&gWowHead); // wow task id
  1552. #endif
  1553. // store the retrieved auth id
  1554. pSharedWow->WowAuthId = ClientAuthId;
  1555. // link shared wow to the console...
  1556. // set wow state to be ready
  1557. pSharedWow->VDMState = VDM_READY;
  1558. b->VDMState = VDM_NOT_PRESENT;
  1559. b->iTask = pSharedWow->pWOWRecord->iTask;
  1560. // now add this shared wow in --
  1561. BaseSrvAddSharedWowRecord(&gWowHead, pSharedWow);
  1562. }
  1563. else {
  1564. // this has not succeeded. cleanup
  1565. if (NULL != pSharedWow) {
  1566. BaseSrvFreeSharedWowRecord(pSharedWow);
  1567. }
  1568. }
  1569. }
  1570. LEAVE_WOW_CRITICAL();
  1571. return (ULONG)Status;
  1572. }
  1573. NTSTATUS
  1574. OkToRunInSharedWOW(
  1575. IN HANDLE UniqueProcessClientId,
  1576. OUT PLUID pAuthenticationId,
  1577. OUT PHANDLE pWOWUserToken
  1578. )
  1579. /*
  1580. * Verifies that the client thread is in the currently logged on interactive
  1581. * user session or is SYSTEM impersonating a thread in the currently logged
  1582. * on interactive session.
  1583. *
  1584. * Also retrieves the the authentication ID (logon session Id) for the
  1585. * caller.
  1586. *
  1587. * if the clients TokenGroups is not part of the currently logged on
  1588. * interactive user session STATUS_ACCESS_DENIED is returned.
  1589. *
  1590. */
  1591. {
  1592. NTSTATUS Status;
  1593. PCSR_PROCESS Process;
  1594. PCSR_THREAD t;
  1595. BOOL fRevertToSelf;
  1596. Status = CsrLockProcessByClientId(UniqueProcessClientId,&Process);
  1597. if (!NT_SUCCESS(Status))
  1598. return Status;
  1599. //
  1600. // Open a token for the client
  1601. //
  1602. Status = NtOpenProcessToken(Process->ProcessHandle,
  1603. TOKEN_QUERY,
  1604. pWOWUserToken
  1605. );
  1606. if (!NT_SUCCESS(Status)) {
  1607. CsrUnlockProcess(Process);
  1608. return Status;
  1609. }
  1610. //
  1611. // Verify the token Group, and see if client's token is the currently
  1612. // logged on interactive user. If this fails and it is System
  1613. // impersonating, then check if the client being impersonated is the
  1614. // currently logged on interactive user.
  1615. //
  1616. Status = (*UserTestTokenForInteractive)(*pWOWUserToken, pAuthenticationId);
  1617. if (!NT_SUCCESS(Status)) {
  1618. if (IsClientSystem(*pWOWUserToken)) {
  1619. NtClose(*pWOWUserToken);
  1620. *pWOWUserToken = NULL;
  1621. // get impersonation token
  1622. fRevertToSelf = CsrImpersonateClient(NULL);
  1623. if(!fRevertToSelf) {
  1624. Status = STATUS_BAD_IMPERSONATION_LEVEL;
  1625. }
  1626. else {
  1627. t = CSR_SERVER_QUERYCLIENTTHREAD();
  1628. Status = NtOpenThreadToken(t->ThreadHandle,
  1629. TOKEN_QUERY,
  1630. TRUE,
  1631. pWOWUserToken);
  1632. CsrRevertToSelf();
  1633. if (NT_SUCCESS(Status)) {
  1634. Status = (*UserTestTokenForInteractive)(*pWOWUserToken,
  1635. pAuthenticationId);
  1636. }
  1637. else {
  1638. Status = STATUS_ACCESS_DENIED;
  1639. }
  1640. }
  1641. }
  1642. }
  1643. CsrUnlockProcess(Process);
  1644. return(Status);
  1645. }
  1646. NTSTATUS
  1647. BaseSrvGetUserToken(
  1648. IN HANDLE UniqueProcessClientId,
  1649. OUT PHANDLE pUserToken
  1650. )
  1651. /*
  1652. *
  1653. * retrieves the the authentication ID (logon session Id) for the
  1654. * caller.
  1655. *
  1656. */
  1657. {
  1658. NTSTATUS Status;
  1659. PCSR_PROCESS Process;
  1660. PCSR_THREAD tCsr;
  1661. BOOL fRevertToSelf;
  1662. Status = CsrLockProcessByClientId(UniqueProcessClientId,&Process);
  1663. if (!NT_SUCCESS(Status))
  1664. return Status;
  1665. fRevertToSelf = CsrImpersonateClient(NULL);
  1666. if (!fRevertToSelf) {
  1667. Status = STATUS_BAD_IMPERSONATION_LEVEL;
  1668. }
  1669. else {
  1670. tCsr = CSR_SERVER_QUERYCLIENTTHREAD();
  1671. Status = NtOpenThreadToken(tCsr->ThreadHandle,
  1672. TOKEN_QUERY,
  1673. TRUE,
  1674. pUserToken);
  1675. CsrRevertToSelf();
  1676. }
  1677. if(Status == STATUS_NO_TOKEN) {
  1678. //
  1679. // Open a token for the client
  1680. //
  1681. Status = NtOpenProcessToken(Process->ProcessHandle,
  1682. TOKEN_QUERY,
  1683. pUserToken
  1684. );
  1685. }
  1686. CsrUnlockProcess(Process);
  1687. return(Status);
  1688. }
  1689. ULONG
  1690. BaseSrvCheckDOS(
  1691. IN PBASE_CHECKVDM_MSG b,
  1692. IN HANDLE UniqueProcessClientId
  1693. )
  1694. {
  1695. NTSTATUS Status;
  1696. PCONSOLERECORD pConsoleRecord = NULL;
  1697. HANDLE Handle,TargetHandle;
  1698. PDOSRECORD pDOSRecord;
  1699. INFORECORD InfoRecord;
  1700. PCSR_PROCESS ParentProcess;
  1701. HANDLE UserToken;
  1702. BOOLEAN fEqual;
  1703. if (!NT_SUCCESS(BaseSrvGetUserToken(UniqueProcessClientId,&UserToken))) {
  1704. return STATUS_INVALID_PARAMETER;
  1705. }
  1706. Status = RtlEnterCriticalSection( &BaseSrvDOSCriticalSection );
  1707. ASSERT( NT_SUCCESS( Status ) );
  1708. Status = BaseSrvGetConsoleRecord(b->ConsoleHandle,&pConsoleRecord);
  1709. if ( NT_SUCCESS(Status) ) {
  1710. Status = NtCompareTokens(UserToken,pConsoleRecord->DosUserToken,&fEqual);
  1711. NtClose(UserToken);
  1712. if(!NT_SUCCESS(Status) || !fEqual) {
  1713. RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
  1714. return STATUS_INVALID_PARAMETER;
  1715. }
  1716. pDOSRecord = pConsoleRecord->DOSRecord;
  1717. ASSERT (pDOSRecord != NULL);
  1718. switch( pDOSRecord->VDMState){
  1719. case VDM_READY:
  1720. case VDM_HAS_RETURNED_ERROR_CODE:
  1721. InfoRecord.iTag = BINARY_TYPE_DOS;
  1722. InfoRecord.pRecord.pDOSRecord = pDOSRecord;
  1723. if(!BaseSrvCopyCommand (b,&InfoRecord)) {
  1724. Status = STATUS_NO_MEMORY;
  1725. break;
  1726. }
  1727. if (!NT_SUCCESS ( Status = BaseSrvDupStandardHandles (
  1728. pConsoleRecord->hVDM,
  1729. pDOSRecord)))
  1730. break;
  1731. Status = BaseSrvCreatePairWaitHandles (&Handle,&TargetHandle);
  1732. if (!NT_SUCCESS(Status) ){
  1733. BaseSrvCloseStandardHandles (pConsoleRecord->hVDM, pDOSRecord);
  1734. break;
  1735. }
  1736. else {
  1737. b->WaitObjectForParent = TargetHandle;
  1738. pDOSRecord->hWaitForParent = TargetHandle;
  1739. pDOSRecord->hWaitForParentDup = Handle;
  1740. }
  1741. pDOSRecord->VDMState = VDM_TO_TAKE_A_COMMAND;
  1742. b->VDMState = VDM_PRESENT_AND_READY;
  1743. if(pConsoleRecord->hWaitForVDMDup)
  1744. NtSetEvent (pConsoleRecord->hWaitForVDMDup,NULL);
  1745. break;
  1746. case VDM_BUSY:
  1747. case VDM_TO_TAKE_A_COMMAND:
  1748. if((pDOSRecord = BaseSrvAllocateDOSRecord()) == NULL){
  1749. Status = STATUS_NO_MEMORY ;
  1750. break;
  1751. }
  1752. InfoRecord.iTag = BINARY_TYPE_DOS;
  1753. InfoRecord.pRecord.pDOSRecord = pDOSRecord;
  1754. if(!BaseSrvCopyCommand(b, &InfoRecord)){
  1755. Status = STATUS_NO_MEMORY ;
  1756. BaseSrvFreeDOSRecord(pDOSRecord);
  1757. break;
  1758. }
  1759. Status = BaseSrvCreatePairWaitHandles(&Handle,&TargetHandle);
  1760. if (!NT_SUCCESS(Status) ){
  1761. BaseSrvFreeDOSRecord(pDOSRecord);
  1762. break;
  1763. }
  1764. else {
  1765. b->WaitObjectForParent = TargetHandle;
  1766. pDOSRecord->hWaitForParentDup = Handle;
  1767. pDOSRecord->hWaitForParent = TargetHandle;
  1768. }
  1769. Status = BaseSrvDupStandardHandles(pConsoleRecord->hVDM, pDOSRecord);
  1770. if (!NT_SUCCESS(Status)) {
  1771. BaseSrvClosePairWaitHandles (pDOSRecord);
  1772. BaseSrvFreeDOSRecord(pDOSRecord);
  1773. break;
  1774. }
  1775. BaseSrvAddDOSRecord(pConsoleRecord,pDOSRecord);
  1776. b->VDMState = VDM_PRESENT_AND_READY;
  1777. if (pConsoleRecord->nReEntrancy) {
  1778. if(pConsoleRecord->hWaitForVDMDup)
  1779. NtSetEvent (pConsoleRecord->hWaitForVDMDup,NULL);
  1780. }
  1781. pDOSRecord->VDMState = VDM_TO_TAKE_A_COMMAND;
  1782. break;
  1783. default:
  1784. ASSERT(FALSE);
  1785. }
  1786. }
  1787. if (pConsoleRecord == NULL) {
  1788. pConsoleRecord = BaseSrvAllocateConsoleRecord ();
  1789. if (pConsoleRecord == NULL)
  1790. Status = STATUS_NO_MEMORY ;
  1791. else {
  1792. pConsoleRecord->DOSRecord = BaseSrvAllocateDOSRecord();
  1793. if(!pConsoleRecord->DOSRecord) {
  1794. BaseSrvFreeConsoleRecord(pConsoleRecord);
  1795. RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
  1796. return (ULONG)STATUS_NO_MEMORY;
  1797. }
  1798. Status = CsrLockProcessByClientId(UniqueProcessClientId,
  1799. &ParentProcess);
  1800. if (!NT_SUCCESS(Status)) {
  1801. BaseSrvFreeConsoleRecord(pConsoleRecord);
  1802. RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
  1803. return Status;
  1804. }
  1805. pConsoleRecord->ParentSequenceNumber = ParentProcess->SequenceNumber;
  1806. CsrUnlockProcess(ParentProcess);
  1807. pConsoleRecord->DosUserToken = UserToken;
  1808. InfoRecord.iTag = b->BinaryType;
  1809. InfoRecord.pRecord.pDOSRecord = pConsoleRecord->DOSRecord;
  1810. if(!BaseSrvCopyCommand(b, &InfoRecord)) {
  1811. BaseSrvFreeConsoleRecord(pConsoleRecord);
  1812. RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
  1813. return (ULONG)STATUS_NO_MEMORY;
  1814. }
  1815. pConsoleRecord->hConsole = b->ConsoleHandle;
  1816. // if no console for this ntvdm
  1817. // get a temporary session ID and pass it to the client
  1818. if (!pConsoleRecord->hConsole) {
  1819. b->iTask = pConsoleRecord->DosSesId = GetNextDosSesId();
  1820. }
  1821. else {
  1822. b->iTask = pConsoleRecord->DosSesId = 0;
  1823. }
  1824. pConsoleRecord->DOSRecord->VDMState = VDM_TO_TAKE_A_COMMAND;
  1825. BaseSrvAddConsoleRecord(pConsoleRecord);
  1826. b->VDMState = VDM_NOT_PRESENT;
  1827. Status = STATUS_SUCCESS;
  1828. }
  1829. }
  1830. RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
  1831. return Status;
  1832. }
  1833. BOOL
  1834. BaseSrvCopyCommand(
  1835. PBASE_CHECKVDM_MSG b,
  1836. PINFORECORD pInfoRecord
  1837. )
  1838. {
  1839. PVDMINFO VDMInfo;
  1840. if((VDMInfo = RtlAllocateHeap(RtlProcessHeap (), MAKE_TAG( VDM_TAG ),sizeof(VDMINFO))) == NULL){
  1841. return FALSE;
  1842. }
  1843. VDMInfo->CmdLine = RtlAllocateHeap(RtlProcessHeap (), MAKE_TAG( VDM_TAG ),b->CmdLen);
  1844. if (b->AppLen) {
  1845. VDMInfo->AppName = RtlAllocateHeap(RtlProcessHeap (), MAKE_TAG( VDM_TAG ),b->AppLen);
  1846. }
  1847. else
  1848. VDMInfo->AppName = NULL;
  1849. if (b->PifLen)
  1850. VDMInfo->PifFile = RtlAllocateHeap(RtlProcessHeap (), MAKE_TAG( VDM_TAG ),b->PifLen);
  1851. else
  1852. VDMInfo->PifFile = NULL;
  1853. if (b->CurDirectoryLen)
  1854. VDMInfo->CurDirectory = RtlAllocateHeap(RtlProcessHeap (), MAKE_TAG( VDM_TAG ),b->CurDirectoryLen);
  1855. else
  1856. VDMInfo->CurDirectory = NULL;
  1857. if (b->EnvLen)
  1858. VDMInfo->Enviornment = RtlAllocateHeap(RtlProcessHeap (), MAKE_TAG( VDM_TAG ),b->EnvLen);
  1859. else
  1860. VDMInfo->Enviornment = NULL;
  1861. if (b->DesktopLen)
  1862. VDMInfo->Desktop = RtlAllocateHeap(RtlProcessHeap (), MAKE_TAG( VDM_TAG ),b->DesktopLen);
  1863. else
  1864. VDMInfo->Desktop = NULL;
  1865. if (b->TitleLen)
  1866. VDMInfo->Title = RtlAllocateHeap(RtlProcessHeap (), MAKE_TAG( VDM_TAG ),b->TitleLen);
  1867. else
  1868. VDMInfo->Title = NULL;
  1869. if (b->ReservedLen)
  1870. VDMInfo->Reserved = RtlAllocateHeap(RtlProcessHeap (), MAKE_TAG( VDM_TAG ),b->ReservedLen);
  1871. else
  1872. VDMInfo->Reserved = NULL;
  1873. // check that all the allocations were successful
  1874. if (VDMInfo->CmdLine == NULL ||
  1875. (b->AppLen && VDMInfo->AppName == NULL) ||
  1876. (b->PifLen && VDMInfo->PifFile == NULL) ||
  1877. (b->CurDirectoryLen && VDMInfo->CurDirectory == NULL) ||
  1878. (b->EnvLen && VDMInfo->Enviornment == NULL) ||
  1879. (b->DesktopLen && VDMInfo->Desktop == NULL )||
  1880. (b->ReservedLen && VDMInfo->Reserved == NULL )||
  1881. (b->TitleLen && VDMInfo->Title == NULL)) {
  1882. BaseSrvFreeVDMInfo(VDMInfo);
  1883. return FALSE;
  1884. }
  1885. RtlMoveMemory(VDMInfo->CmdLine,
  1886. b->CmdLine,
  1887. b->CmdLen);
  1888. VDMInfo->CmdSize = b->CmdLen;
  1889. if (b->AppLen) {
  1890. RtlMoveMemory(VDMInfo->AppName,
  1891. b->AppName,
  1892. b->AppLen);
  1893. }
  1894. VDMInfo->AppLen = b->AppLen;
  1895. if (b->PifLen) {
  1896. RtlMoveMemory(VDMInfo->PifFile,
  1897. b->PifFile,
  1898. b->PifLen);
  1899. }
  1900. VDMInfo->PifLen = b->PifLen;
  1901. if (b->CurDirectoryLen) {
  1902. RtlMoveMemory(VDMInfo->CurDirectory,
  1903. b->CurDirectory,
  1904. b->CurDirectoryLen);
  1905. }
  1906. VDMInfo->CurDirectoryLen = b->CurDirectoryLen;
  1907. if (b->EnvLen) {
  1908. RtlMoveMemory(VDMInfo->Enviornment,
  1909. b->Env,
  1910. b->EnvLen);
  1911. }
  1912. VDMInfo->EnviornmentSize = b->EnvLen;
  1913. if (b->DesktopLen) {
  1914. RtlMoveMemory(VDMInfo->Desktop,
  1915. b->Desktop,
  1916. b->DesktopLen);
  1917. }
  1918. VDMInfo->DesktopLen = b->DesktopLen;
  1919. if (b->TitleLen) {
  1920. RtlMoveMemory(VDMInfo->Title,
  1921. b->Title,
  1922. b->TitleLen);
  1923. }
  1924. VDMInfo->TitleLen = b->TitleLen;
  1925. if (b->ReservedLen) {
  1926. RtlMoveMemory(VDMInfo->Reserved,
  1927. b->Reserved,
  1928. b->ReservedLen);
  1929. }
  1930. VDMInfo->ReservedLen = b->ReservedLen;
  1931. if (b->StartupInfo) {
  1932. RtlMoveMemory(&VDMInfo->StartupInfo,
  1933. b->StartupInfo,
  1934. sizeof (STARTUPINFOA));
  1935. VDMInfo->VDMState = STARTUP_INFO_RETURNED;
  1936. }
  1937. else
  1938. VDMInfo->VDMState = 0;
  1939. VDMInfo->dwCreationFlags = b->dwCreationFlags;
  1940. VDMInfo->CurDrive = b->CurDrive;
  1941. VDMInfo->CodePage = b->CodePage;
  1942. // ATTENTION THIS CODE ASSUMES THAT WOWRECORD AND DOSRECORD HAVE THE SAME LAYOUT
  1943. // THIS IS BAD BAD BAD -- fix later BUGBUG
  1944. //
  1945. if (pInfoRecord->iTag == BINARY_TYPE_WIN16) {
  1946. pInfoRecord->pRecord.pWOWRecord->lpVDMInfo = VDMInfo;
  1947. }
  1948. else {
  1949. pInfoRecord->pRecord.pDOSRecord->lpVDMInfo = VDMInfo;
  1950. }
  1951. VDMInfo->StdIn = VDMInfo->StdOut = VDMInfo->StdErr = 0;
  1952. if(pInfoRecord->iTag == BINARY_TYPE_DOS) {
  1953. VDMInfo->StdIn = b->StdIn;
  1954. VDMInfo->StdOut = b->StdOut;
  1955. VDMInfo->StdErr = b->StdErr;
  1956. }
  1957. else if (pInfoRecord->iTag == BINARY_TYPE_WIN16) {
  1958. pInfoRecord->pRecord.pWOWRecord->fDispatched = FALSE;
  1959. }
  1960. // else if (pInfoRecord->iTag == BINARY_TYPE_SEPWOW)
  1961. return TRUE;
  1962. }
  1963. ULONG
  1964. BaseSrvUpdateWOWEntry(
  1965. PBASE_UPDATE_VDM_ENTRY_MSG b,
  1966. ULONG ParentSequenceNumber
  1967. )
  1968. {
  1969. NTSTATUS Status;
  1970. PSHAREDWOWRECORD pSharedWow;
  1971. PWOWRECORD pWOWRecord;
  1972. HANDLE Handle,TargetHandle;
  1973. Status = ENTER_WOW_CRITICAL();
  1974. ASSERT( NT_SUCCESS( Status ) );
  1975. // this is fun -- we get the the record using the task id
  1976. // reason: the call is made from the context of a creator process
  1977. // hence console handle means nothing
  1978. Status = BaseSrvFindSharedWowRecordByTaskId(&gWowHead,
  1979. b->iTask,
  1980. &pSharedWow,
  1981. &pWOWRecord);
  1982. // this returns us the shared wow record and wow record
  1983. if ( NT_SUCCESS(Status) ) {
  1984. if (ParentSequenceNumber != pSharedWow->ParentSequenceNumber) {
  1985. Status = STATUS_INVALID_PARAMETER;
  1986. goto UpdateWowEntryExit;
  1987. }
  1988. switch ( b->EntryIndex ){
  1989. case UPDATE_VDM_PROCESS_HANDLE:
  1990. Status = STATUS_SUCCESS;
  1991. break;
  1992. case UPDATE_VDM_UNDO_CREATION:
  1993. if( b->VDMCreationState & VDM_BEING_REUSED ||
  1994. b->VDMCreationState & VDM_FULLY_CREATED){
  1995. NtClose(pWOWRecord->hWaitForParent);
  1996. pWOWRecord->hWaitForParent = 0;
  1997. }
  1998. if( b->VDMCreationState & VDM_PARTIALLY_CREATED ||
  1999. b->VDMCreationState & VDM_FULLY_CREATED){
  2000. BaseSrvRemoveWOWRecord (pSharedWow, pWOWRecord);
  2001. BaseSrvFreeWOWRecord (pWOWRecord);
  2002. if (NULL == pSharedWow->pWOWRecord) {
  2003. Status = BaseSrvDeleteSharedWowRecord(&gWowHead, pSharedWow);
  2004. }
  2005. }
  2006. break;
  2007. default:
  2008. ASSERT(FALSE);
  2009. }
  2010. }
  2011. if (!NT_SUCCESS(Status) )
  2012. goto UpdateWowEntryExit;
  2013. switch ( b->EntryIndex ){
  2014. case UPDATE_VDM_PROCESS_HANDLE:
  2015. Status = BaseSrvCreatePairWaitHandles (&Handle,&TargetHandle);
  2016. if (NT_SUCCESS(Status) ){
  2017. pWOWRecord->hWaitForParent = Handle;
  2018. pWOWRecord->hWaitForParentServer = TargetHandle;
  2019. b->WaitObjectForParent = TargetHandle;
  2020. if (UserNotifyProcessCreate != NULL) {
  2021. (*UserNotifyProcessCreate)(pWOWRecord->iTask,
  2022. (DWORD)((ULONG_PTR)CSR_SERVER_QUERYCLIENTTHREAD()->ClientId.UniqueThread),
  2023. (DWORD)((ULONG_PTR)TargetHandle),
  2024. 0x04);
  2025. }
  2026. }
  2027. break;
  2028. case UPDATE_VDM_UNDO_CREATION:
  2029. case UPDATE_VDM_HOOKED_CTRLC:
  2030. break;
  2031. default:
  2032. ASSERT(FALSE);
  2033. break;
  2034. }
  2035. UpdateWowEntryExit:
  2036. LEAVE_WOW_CRITICAL();
  2037. return Status;
  2038. }
  2039. ULONG
  2040. BaseSrvUpdateDOSEntry(
  2041. PBASE_UPDATE_VDM_ENTRY_MSG b,
  2042. ULONG ParentSequenceNumber
  2043. )
  2044. {
  2045. NTSTATUS Status;
  2046. PDOSRECORD pDOSRecord;
  2047. PCONSOLERECORD pConsoleRecord = NULL;
  2048. HANDLE Handle,TargetHandle;
  2049. PCSR_THREAD t;
  2050. Status = RtlEnterCriticalSection( &BaseSrvDOSCriticalSection );
  2051. ASSERT( NT_SUCCESS( Status ) );
  2052. if (b->iTask)
  2053. Status = GetConsoleRecordDosSesId(b->iTask,&pConsoleRecord);
  2054. else
  2055. Status = BaseSrvGetConsoleRecord(b->ConsoleHandle,&pConsoleRecord);
  2056. if ( NT_SUCCESS(Status) ) {
  2057. if (ParentSequenceNumber != pConsoleRecord->ParentSequenceNumber) {
  2058. Status = STATUS_INVALID_PARAMETER;
  2059. goto UpdateDosEntryExit;
  2060. }
  2061. pDOSRecord = pConsoleRecord->DOSRecord;
  2062. switch ( b->EntryIndex ){
  2063. case UPDATE_VDM_PROCESS_HANDLE:
  2064. t = CSR_SERVER_QUERYCLIENTTHREAD();
  2065. Status = NtDuplicateObject (
  2066. t->Process->ProcessHandle,
  2067. b->VDMProcessHandle,
  2068. NtCurrentProcess(),
  2069. &pConsoleRecord->hVDM,
  2070. 0,
  2071. FALSE,
  2072. DUPLICATE_SAME_ACCESS
  2073. );
  2074. break;
  2075. case UPDATE_VDM_UNDO_CREATION:
  2076. if( b->VDMCreationState & VDM_BEING_REUSED ||
  2077. b->VDMCreationState & VDM_FULLY_CREATED){
  2078. NtClose(pDOSRecord->hWaitForParentDup);
  2079. pDOSRecord->hWaitForParentDup = 0;
  2080. }
  2081. if( b->VDMCreationState & VDM_PARTIALLY_CREATED ||
  2082. b->VDMCreationState & VDM_FULLY_CREATED){
  2083. BaseSrvRemoveDOSRecord (pConsoleRecord,pDOSRecord);
  2084. BaseSrvFreeDOSRecord (pDOSRecord);
  2085. if (pConsoleRecord->DOSRecord == NULL) {
  2086. if (b->VDMCreationState & VDM_FULLY_CREATED) {
  2087. if (pConsoleRecord->hVDM)
  2088. NtClose(pConsoleRecord->hVDM);
  2089. }
  2090. BaseSrvFreeConsoleRecord(pConsoleRecord);
  2091. }
  2092. }
  2093. break;
  2094. case UPDATE_VDM_HOOKED_CTRLC:
  2095. break;
  2096. default:
  2097. ASSERT(FALSE);
  2098. }
  2099. }
  2100. if (!NT_SUCCESS(Status) )
  2101. goto UpdateDosEntryExit;
  2102. switch ( b->EntryIndex ){
  2103. case UPDATE_VDM_PROCESS_HANDLE:
  2104. // williamh, Oct 24, 1996.
  2105. // if the ntvdm is runnig on a new console, do NOT subsititue
  2106. // the given process handle with event. The caller(CreateProcess)
  2107. // will get the real process handle and so does the application
  2108. // who calls CreateProcess. When it is time for the application
  2109. // to call GetExitCodeProcess, the client side will return the
  2110. // right thing(on the server side, we have nothing because
  2111. // console and dos record are gone).
  2112. //
  2113. // VadimB: this code fixes the problem with GetExitCodeProcess
  2114. // in a way that is not too consistent. We should review
  2115. // TerminateProcess code along with the code that deletes
  2116. // pseudo-handles for processes (in this file) to account for
  2117. // outstanding handle references. For now this code also
  2118. // makes terminateprocess work on the handle we return
  2119. //
  2120. if ((!pConsoleRecord->DosSesId && b->BinaryType == BINARY_TYPE_DOS)) {
  2121. Status = BaseSrvCreatePairWaitHandles (&Handle,&TargetHandle);
  2122. if (NT_SUCCESS(Status) ){
  2123. if (NT_SUCCESS ( Status = BaseSrvDupStandardHandles (
  2124. pConsoleRecord->hVDM,
  2125. pDOSRecord))){
  2126. pDOSRecord->hWaitForParent = TargetHandle;
  2127. pDOSRecord->hWaitForParentDup = Handle;
  2128. b->WaitObjectForParent = TargetHandle;
  2129. }
  2130. else{
  2131. BaseSrvClosePairWaitHandles (pDOSRecord);
  2132. }
  2133. }
  2134. }
  2135. else {
  2136. pDOSRecord->hWaitForParent = NULL;
  2137. pDOSRecord->hWaitForParentDup = NULL;
  2138. b->WaitObjectForParent = NULL;
  2139. }
  2140. break;
  2141. case UPDATE_VDM_UNDO_CREATION:
  2142. case UPDATE_VDM_HOOKED_CTRLC:
  2143. break;
  2144. default:
  2145. ASSERT(FALSE);
  2146. break;
  2147. }
  2148. UpdateDosEntryExit:
  2149. RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
  2150. return Status;
  2151. }
  2152. PWOWRECORD
  2153. BaseSrvCheckAvailableWOWCommand(
  2154. PSHAREDWOWRECORD pSharedWow
  2155. )
  2156. {
  2157. PWOWRECORD pWOWRecord;
  2158. if (NULL == pSharedWow)
  2159. return NULL;
  2160. pWOWRecord = pSharedWow->pWOWRecord;
  2161. while(NULL != pWOWRecord) {
  2162. if (pWOWRecord->fDispatched == FALSE) {
  2163. break;
  2164. }
  2165. pWOWRecord = pWOWRecord->WOWRecordNext;
  2166. }
  2167. return pWOWRecord;
  2168. }
  2169. // this function exits given wow task running in a given shared wow
  2170. //
  2171. NTSTATUS
  2172. BaseSrvExitWOWTask(
  2173. PBASE_EXIT_VDM_MSG b,
  2174. ULONG SequenceNumber
  2175. )
  2176. {
  2177. NTSTATUS Status;
  2178. PSHAREDWOWRECORD pSharedWow;
  2179. // now we might get burned here -- although unlikely
  2180. // find shared wow first
  2181. Status = ENTER_WOW_CRITICAL();
  2182. ASSERT(NT_SUCCESS(Status));
  2183. Status = BaseSrvFindSharedWowRecordByConsoleHandle(&gWowHead,
  2184. b->ConsoleHandle,
  2185. &pSharedWow);
  2186. if (NT_SUCCESS(Status)) {
  2187. if(SequenceNumber != pSharedWow->SequenceNumber) {
  2188. Status = STATUS_INVALID_PARAMETER;
  2189. }
  2190. else if (-1 == b->iWowTask) { // the entire vdm goes
  2191. // remove from the chain first
  2192. Status = BaseSrvDeleteSharedWowRecord(&gWowHead,
  2193. pSharedWow);
  2194. }
  2195. else {
  2196. Status = BaseSrvRemoveWOWRecordByTaskId(pSharedWow,
  2197. b->iWowTask);
  2198. }
  2199. }
  2200. LEAVE_WOW_CRITICAL();
  2201. return Status;
  2202. }
  2203. NTSTATUS
  2204. BaseSrvExitDOSTask(
  2205. PBASE_EXIT_VDM_MSG b,
  2206. ULONG SequenceNumber
  2207. )
  2208. {
  2209. NTSTATUS Status;
  2210. PDOSRECORD pDOSRecord;
  2211. PCONSOLERECORD pConsoleRecord = NULL;
  2212. Status = RtlEnterCriticalSection( &BaseSrvDOSCriticalSection );
  2213. ASSERT( NT_SUCCESS( Status ) );
  2214. Status = BaseSrvGetConsoleRecord(b->ConsoleHandle,&pConsoleRecord);
  2215. if (!NT_SUCCESS (Status) || SequenceNumber != pConsoleRecord->SequenceNumber) {
  2216. RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
  2217. return ((ULONG)STATUS_INVALID_PARAMETER);
  2218. }
  2219. if (pConsoleRecord->hWaitForVDMDup){
  2220. NtClose(pConsoleRecord->hWaitForVDMDup);
  2221. pConsoleRecord->hWaitForVDMDup =0;
  2222. b->WaitObjectForVDM = pConsoleRecord->hWaitForVDM;
  2223. }
  2224. pDOSRecord = pConsoleRecord->DOSRecord;
  2225. while (pDOSRecord) {
  2226. if (pDOSRecord->hWaitForParentDup) {
  2227. NtSetEvent (pDOSRecord->hWaitForParentDup,NULL);
  2228. NtClose (pDOSRecord->hWaitForParentDup);
  2229. pDOSRecord->hWaitForParentDup = 0;
  2230. }
  2231. pDOSRecord = pDOSRecord->DOSRecordNext;
  2232. }
  2233. NtClose(pConsoleRecord->hVDM);
  2234. BaseSrvFreeConsoleRecord (pConsoleRecord);
  2235. RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
  2236. return Status;
  2237. }
  2238. // assumes: shared wow cs is being held
  2239. // iWowTask is valid
  2240. NTSTATUS
  2241. BaseSrvRemoveWOWRecordByTaskId (
  2242. IN PSHAREDWOWRECORD pSharedWow,
  2243. IN ULONG iWowTask
  2244. )
  2245. {
  2246. PWOWRECORD pWOWRecordLast = NULL, pWOWRecord;
  2247. if (pSharedWow == NULL) {
  2248. return STATUS_INVALID_PARAMETER;
  2249. }
  2250. pWOWRecord = pSharedWow->pWOWRecord;
  2251. // Find the right WOW record and free it.
  2252. while (NULL != pWOWRecord) {
  2253. if (pWOWRecord->iTask == iWowTask) {
  2254. if (NULL == pWOWRecordLast) {
  2255. pSharedWow->pWOWRecord = pWOWRecord->WOWRecordNext;
  2256. }
  2257. else {
  2258. pWOWRecordLast->WOWRecordNext = pWOWRecord->WOWRecordNext;
  2259. }
  2260. if(pWOWRecord->hWaitForParent) {
  2261. NtSetEvent (pWOWRecord->hWaitForParent,NULL);
  2262. NtClose (pWOWRecord->hWaitForParent);
  2263. pWOWRecord->hWaitForParent = 0;
  2264. }
  2265. BaseSrvFreeWOWRecord(pWOWRecord);
  2266. return STATUS_SUCCESS;
  2267. }
  2268. pWOWRecordLast = pWOWRecord;
  2269. pWOWRecord = pWOWRecord->WOWRecordNext;
  2270. }
  2271. return STATUS_NOT_FOUND;
  2272. }
  2273. ULONG
  2274. BaseSrvGetVDMExitCode( ///////// BUGBUG -- fixme
  2275. IN OUT PCSR_API_MSG m,
  2276. IN OUT PCSR_REPLY_STATUS ReplyStatus
  2277. )
  2278. {
  2279. NTSTATUS Status;
  2280. PCONSOLERECORD pConsoleRecord = NULL;
  2281. PDOSRECORD pDOSRecord;
  2282. PBASE_GET_VDM_EXIT_CODE_MSG b = (PBASE_GET_VDM_EXIT_CODE_MSG)&m->u.ApiMessageData;
  2283. if (b->ConsoleHandle == (HANDLE)-1){
  2284. b->ExitCode = 0;
  2285. }
  2286. else{
  2287. Status = RtlEnterCriticalSection( &BaseSrvDOSCriticalSection );
  2288. ASSERT( NT_SUCCESS( Status ) );
  2289. Status = BaseSrvGetConsoleRecord (b->ConsoleHandle,&pConsoleRecord);
  2290. if (!NT_SUCCESS(Status)){
  2291. b->ExitCode = 0;
  2292. RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
  2293. return STATUS_SUCCESS;
  2294. }
  2295. pDOSRecord = pConsoleRecord->DOSRecord;
  2296. while (pDOSRecord) {
  2297. // sudeepb 05-Oct-1992
  2298. // fix for the change markl has made for tagging VDM handles
  2299. if (pDOSRecord->hWaitForParent == (HANDLE)((ULONG_PTR)b->hParent & ~0x1)) {
  2300. if (pDOSRecord->VDMState == VDM_HAS_RETURNED_ERROR_CODE){
  2301. b->ExitCode = pDOSRecord->ErrorCode;
  2302. if (pDOSRecord == pConsoleRecord->DOSRecord &&
  2303. pDOSRecord->DOSRecordNext == NULL)
  2304. {
  2305. pDOSRecord->VDMState = VDM_READY;
  2306. pDOSRecord->hWaitForParent = 0;
  2307. }
  2308. else {
  2309. BaseSrvRemoveDOSRecord (pConsoleRecord,pDOSRecord);
  2310. BaseSrvFreeDOSRecord(pDOSRecord);
  2311. }
  2312. }
  2313. else {
  2314. if (pDOSRecord->VDMState == VDM_READY)
  2315. b->ExitCode = pDOSRecord->ErrorCode;
  2316. else
  2317. b->ExitCode = STILL_ACTIVE;
  2318. }
  2319. break;
  2320. }
  2321. else
  2322. pDOSRecord = pDOSRecord->DOSRecordNext;
  2323. }
  2324. if (pDOSRecord == NULL)
  2325. b->ExitCode = 0;
  2326. RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
  2327. }
  2328. return STATUS_SUCCESS;
  2329. }
  2330. ULONG BaseSrvDupStandardHandles(
  2331. IN HANDLE pVDMProc,
  2332. IN PDOSRECORD pDOSRecord
  2333. )
  2334. {
  2335. NTSTATUS Status;
  2336. HANDLE pSrcProc;
  2337. HANDLE StdOutTemp = NULL;
  2338. PCSR_THREAD t;
  2339. PVDMINFO pVDMInfo = pDOSRecord->lpVDMInfo;
  2340. t = CSR_SERVER_QUERYCLIENTTHREAD();
  2341. pSrcProc = t->Process->ProcessHandle;
  2342. if (pVDMInfo->StdIn){
  2343. Status = NtDuplicateObject (
  2344. pSrcProc,
  2345. pVDMInfo->StdIn,
  2346. pVDMProc,
  2347. &pVDMInfo->StdIn,
  2348. 0,
  2349. OBJ_INHERIT,
  2350. DUPLICATE_SAME_ACCESS
  2351. );
  2352. if (!NT_SUCCESS (Status))
  2353. return Status;
  2354. }
  2355. if (pVDMInfo->StdOut){
  2356. StdOutTemp = pVDMInfo->StdOut;
  2357. Status = NtDuplicateObject (
  2358. pSrcProc,
  2359. pVDMInfo->StdOut,
  2360. pVDMProc,
  2361. &pVDMInfo->StdOut,
  2362. 0,
  2363. OBJ_INHERIT,
  2364. DUPLICATE_SAME_ACCESS
  2365. );
  2366. if (!NT_SUCCESS (Status))
  2367. return Status;
  2368. }
  2369. if (pVDMInfo->StdErr){
  2370. if(pVDMInfo->StdErr != StdOutTemp){
  2371. Status = NtDuplicateObject (
  2372. pSrcProc,
  2373. pVDMInfo->StdErr,
  2374. pVDMProc,
  2375. &pVDMInfo->StdErr,
  2376. 0,
  2377. OBJ_INHERIT,
  2378. DUPLICATE_SAME_ACCESS
  2379. );
  2380. if (!NT_SUCCESS (Status))
  2381. return Status;
  2382. }
  2383. else
  2384. pVDMInfo->StdErr = pVDMInfo->StdOut;
  2385. }
  2386. return STATUS_SUCCESS;
  2387. }
  2388. // Generates a DosSesId which is unique and nonzero
  2389. ULONG GetNextDosSesId(VOID)
  2390. {
  2391. static BOOLEAN bWrap = FALSE;
  2392. static ULONG NextSesId=1;
  2393. ULONG ul;
  2394. PCONSOLERECORD pConsoleHead;
  2395. pConsoleHead = DOSHead;
  2396. ul = NextSesId;
  2397. if (bWrap) {
  2398. while (pConsoleHead) {
  2399. if (!pConsoleHead->hConsole && pConsoleHead->DosSesId == ul)
  2400. {
  2401. pConsoleHead = DOSHead;
  2402. ul++;
  2403. if (!ul) { // never use zero
  2404. bWrap = TRUE;
  2405. ul++;
  2406. }
  2407. }
  2408. else {
  2409. pConsoleHead = pConsoleHead->Next;
  2410. }
  2411. }
  2412. }
  2413. NextSesId = ul + 1;
  2414. if (!NextSesId) { // never use zero
  2415. bWrap = TRUE;
  2416. NextSesId++;
  2417. }
  2418. return ul;
  2419. }
  2420. NTSTATUS BaseSrvGetConsoleRecord (
  2421. IN HANDLE hConsole,
  2422. IN OUT PCONSOLERECORD *pConsoleRecord
  2423. )
  2424. {
  2425. PCONSOLERECORD pConsoleHead;
  2426. pConsoleHead = DOSHead;
  2427. if (hConsole) {
  2428. while (pConsoleHead) {
  2429. if (pConsoleHead->hConsole == hConsole){
  2430. *pConsoleRecord = pConsoleHead;
  2431. return STATUS_SUCCESS;
  2432. }
  2433. else
  2434. pConsoleHead = pConsoleHead->Next;
  2435. }
  2436. }
  2437. return STATUS_INVALID_PARAMETER;
  2438. }
  2439. NTSTATUS
  2440. GetConsoleRecordDosSesId (
  2441. IN ULONG DosSesId,
  2442. IN OUT PCONSOLERECORD *pConsoleRecord
  2443. )
  2444. {
  2445. PCONSOLERECORD pConsoleHead;
  2446. if (!DosSesId)
  2447. return STATUS_INVALID_PARAMETER;
  2448. pConsoleHead = DOSHead;
  2449. while (pConsoleHead) {
  2450. if (!pConsoleHead->hConsole &&
  2451. pConsoleHead->DosSesId == DosSesId)
  2452. {
  2453. *pConsoleRecord = pConsoleHead;
  2454. return STATUS_SUCCESS;
  2455. }
  2456. else
  2457. pConsoleHead = pConsoleHead->Next;
  2458. }
  2459. return STATUS_INVALID_PARAMETER;
  2460. }
  2461. PWOWRECORD
  2462. BaseSrvAllocateWOWRecord(
  2463. PSHAREDWOWRECORDHEAD pSharedWowRecordHead
  2464. )
  2465. {
  2466. register PWOWRECORD WOWRecord;
  2467. WOWRecord = RtlAllocateHeap ( RtlProcessHeap (), MAKE_TAG( VDM_TAG ), sizeof (WOWRECORD));
  2468. if (WOWRecord == NULL)
  2469. return NULL;
  2470. RtlZeroMemory ((PVOID)WOWRecord,sizeof(WOWRECORD));
  2471. // if too many tasks, error out.
  2472. if ((WOWRecord->iTask = BaseSrvGetWOWTaskId(pSharedWowRecordHead)) == WOWMAXID) {
  2473. RtlFreeHeap(RtlProcessHeap(), 0, WOWRecord);
  2474. return NULL;
  2475. }
  2476. return WOWRecord;
  2477. }
  2478. VOID BaseSrvFreeWOWRecord (
  2479. PWOWRECORD pWOWRecord
  2480. )
  2481. {
  2482. if (pWOWRecord == NULL)
  2483. return;
  2484. if (pWOWRecord->pFilePath) {
  2485. RtlFreeHeap(RtlProcessHeap (), 0, pWOWRecord->pFilePath);
  2486. }
  2487. BaseSrvFreeVDMInfo (pWOWRecord->lpVDMInfo);
  2488. RtlFreeHeap(RtlProcessHeap (), 0, pWOWRecord);
  2489. }
  2490. VOID BaseSrvAddWOWRecord (
  2491. PSHAREDWOWRECORD pSharedWow,
  2492. PWOWRECORD pWOWRecord
  2493. )
  2494. {
  2495. PWOWRECORD WOWRecordCurrent,WOWRecordLast;
  2496. // First WOW app runs first, so add the new ones at the end
  2497. if (NULL == pSharedWow->pWOWRecord) {
  2498. pSharedWow->pWOWRecord = pWOWRecord;
  2499. return;
  2500. }
  2501. WOWRecordCurrent = pSharedWow->pWOWRecord;
  2502. while (NULL != WOWRecordCurrent){
  2503. WOWRecordLast = WOWRecordCurrent;
  2504. WOWRecordCurrent = WOWRecordCurrent->WOWRecordNext;
  2505. }
  2506. WOWRecordLast->WOWRecordNext = pWOWRecord;
  2507. return;
  2508. }
  2509. VOID BaseSrvRemoveWOWRecord (
  2510. PSHAREDWOWRECORD pSharedWow,
  2511. PWOWRECORD pWOWRecord
  2512. )
  2513. {
  2514. PWOWRECORD WOWRecordCurrent,WOWRecordLast = NULL;
  2515. if (NULL == pSharedWow) {
  2516. return;
  2517. }
  2518. if (NULL == pSharedWow->pWOWRecord) {
  2519. return;
  2520. }
  2521. if (pSharedWow->pWOWRecord == pWOWRecord) {
  2522. pSharedWow->pWOWRecord = pWOWRecord->WOWRecordNext;
  2523. return;
  2524. }
  2525. WOWRecordLast = pSharedWow->pWOWRecord;
  2526. WOWRecordCurrent = WOWRecordLast->WOWRecordNext;
  2527. while (WOWRecordCurrent && WOWRecordCurrent != pWOWRecord){
  2528. WOWRecordLast = WOWRecordCurrent;
  2529. WOWRecordCurrent = WOWRecordCurrent->WOWRecordNext;
  2530. }
  2531. if (WOWRecordCurrent != NULL)
  2532. WOWRecordLast->WOWRecordNext = pWOWRecord->WOWRecordNext;
  2533. return;
  2534. }
  2535. PCONSOLERECORD BaseSrvAllocateConsoleRecord (
  2536. VOID
  2537. )
  2538. {
  2539. PCONSOLERECORD pConsoleRecord;
  2540. if (NULL == (pConsoleRecord = RtlAllocateHeap (RtlProcessHeap (),
  2541. MAKE_TAG(VDM_TAG),
  2542. sizeof (CONSOLERECORD)))) {
  2543. return NULL;
  2544. }
  2545. RtlZeroMemory(pConsoleRecord, sizeof(CONSOLERECORD));
  2546. return pConsoleRecord;
  2547. }
  2548. VOID BaseSrvFreeConsoleRecord (
  2549. PCONSOLERECORD pConsoleRecord
  2550. )
  2551. {
  2552. PDOSRECORD pDOSRecord;
  2553. if (pConsoleRecord == NULL)
  2554. return;
  2555. while (pDOSRecord = pConsoleRecord->DOSRecord){
  2556. pConsoleRecord->DOSRecord = pDOSRecord->DOSRecordNext;
  2557. BaseSrvFreeDOSRecord (pDOSRecord);
  2558. }
  2559. if (pConsoleRecord->lpszzCurDirs)
  2560. RtlFreeHeap(BaseSrvHeap, 0, pConsoleRecord->lpszzCurDirs);
  2561. if (pConsoleRecord->DosUserToken)
  2562. NtClose(pConsoleRecord->DosUserToken);
  2563. BaseSrvRemoveConsoleRecord (pConsoleRecord);
  2564. RtlFreeHeap (RtlProcessHeap (), 0, pConsoleRecord );
  2565. }
  2566. VOID BaseSrvRemoveConsoleRecord (
  2567. PCONSOLERECORD pConsoleRecord
  2568. )
  2569. {
  2570. PCONSOLERECORD pTempLast,pTemp;
  2571. if (DOSHead == NULL)
  2572. return;
  2573. if(DOSHead == pConsoleRecord) {
  2574. DOSHead = pConsoleRecord->Next;
  2575. return;
  2576. }
  2577. pTempLast = DOSHead;
  2578. pTemp = DOSHead->Next;
  2579. while (pTemp && pTemp != pConsoleRecord){
  2580. pTempLast = pTemp;
  2581. pTemp = pTemp->Next;
  2582. }
  2583. if (pTemp)
  2584. pTempLast->Next = pTemp->Next;
  2585. return;
  2586. }
  2587. PDOSRECORD
  2588. BaseSrvAllocateDOSRecord(
  2589. VOID
  2590. )
  2591. {
  2592. PDOSRECORD DOSRecord;
  2593. DOSRecord = RtlAllocateHeap ( RtlProcessHeap (), MAKE_TAG( VDM_TAG ), sizeof (DOSRECORD));
  2594. if (DOSRecord == NULL)
  2595. return NULL;
  2596. RtlZeroMemory ((PVOID)DOSRecord,sizeof(DOSRECORD));
  2597. return DOSRecord;
  2598. }
  2599. VOID BaseSrvFreeDOSRecord (
  2600. PDOSRECORD pDOSRecord
  2601. )
  2602. {
  2603. BaseSrvFreeVDMInfo (pDOSRecord->lpVDMInfo);
  2604. if(pDOSRecord->pFilePath) {
  2605. RtlFreeHeap(RtlProcessHeap (), 0, pDOSRecord->pFilePath);
  2606. }
  2607. RtlFreeHeap(RtlProcessHeap (), 0, pDOSRecord);
  2608. return;
  2609. }
  2610. VOID BaseSrvAddDOSRecord (
  2611. PCONSOLERECORD pConsoleRecord,
  2612. PDOSRECORD pDOSRecord
  2613. )
  2614. {
  2615. PDOSRECORD pDOSRecordTemp;
  2616. pDOSRecord->DOSRecordNext = NULL;
  2617. if(pConsoleRecord->DOSRecord == NULL){
  2618. pConsoleRecord->DOSRecord = pDOSRecord;
  2619. return;
  2620. }
  2621. pDOSRecordTemp = pConsoleRecord->DOSRecord;
  2622. while (pDOSRecordTemp->DOSRecordNext)
  2623. pDOSRecordTemp = pDOSRecordTemp->DOSRecordNext;
  2624. pDOSRecordTemp->DOSRecordNext = pDOSRecord;
  2625. return;
  2626. }
  2627. VOID
  2628. BaseSrvRemoveDOSRecord (
  2629. PCONSOLERECORD pConsoleRecord,
  2630. PDOSRECORD pDOSRecord
  2631. )
  2632. {
  2633. PDOSRECORD DOSRecordCurrent,DOSRecordLast = NULL;
  2634. if( pConsoleRecord == NULL)
  2635. return;
  2636. if(pConsoleRecord->DOSRecord == pDOSRecord){
  2637. pConsoleRecord->DOSRecord = pDOSRecord->DOSRecordNext;
  2638. return;
  2639. }
  2640. DOSRecordLast = pConsoleRecord->DOSRecord;
  2641. if (DOSRecordLast)
  2642. DOSRecordCurrent = DOSRecordLast->DOSRecordNext;
  2643. else
  2644. return;
  2645. while (DOSRecordCurrent && DOSRecordCurrent != pDOSRecord){
  2646. DOSRecordLast = DOSRecordCurrent;
  2647. DOSRecordCurrent = DOSRecordCurrent->DOSRecordNext;
  2648. }
  2649. if (DOSRecordCurrent == NULL)
  2650. return;
  2651. else
  2652. DOSRecordLast->DOSRecordNext = pDOSRecord->DOSRecordNext;
  2653. return;
  2654. }
  2655. VOID
  2656. BaseSrvFreeVDMInfo(
  2657. IN PVDMINFO lpVDMInfo
  2658. )
  2659. {
  2660. if (lpVDMInfo == NULL)
  2661. return;
  2662. if (lpVDMInfo->CmdLine)
  2663. RtlFreeHeap(RtlProcessHeap (), 0,lpVDMInfo->CmdLine);
  2664. if (lpVDMInfo->AppName) {
  2665. RtlFreeHeap(RtlProcessHeap (), 0, lpVDMInfo->AppName);
  2666. }
  2667. if (lpVDMInfo->PifFile) {
  2668. RtlFreeHeap(RtlProcessHeap (), 0, lpVDMInfo->PifFile);
  2669. }
  2670. if(lpVDMInfo->Enviornment)
  2671. RtlFreeHeap(RtlProcessHeap (), 0,lpVDMInfo->Enviornment);
  2672. if(lpVDMInfo->Desktop)
  2673. RtlFreeHeap(RtlProcessHeap (), 0,lpVDMInfo->Desktop);
  2674. if(lpVDMInfo->Title)
  2675. RtlFreeHeap(RtlProcessHeap (), 0,lpVDMInfo->Title);
  2676. if(lpVDMInfo->Reserved)
  2677. RtlFreeHeap(RtlProcessHeap (), 0,lpVDMInfo->Reserved);
  2678. if(lpVDMInfo->CurDirectory)
  2679. RtlFreeHeap(RtlProcessHeap (), 0,lpVDMInfo->CurDirectory);
  2680. RtlFreeHeap(RtlProcessHeap (), 0,lpVDMInfo);
  2681. return;
  2682. }
  2683. ULONG BaseSrvCreatePairWaitHandles (ServerHandle, ClientHandle)
  2684. HANDLE *ServerHandle;
  2685. HANDLE *ClientHandle;
  2686. {
  2687. NTSTATUS Status;
  2688. PCSR_THREAD t;
  2689. Status = NtCreateEvent(
  2690. ServerHandle,
  2691. EVENT_ALL_ACCESS,
  2692. NULL,
  2693. NotificationEvent,
  2694. FALSE
  2695. );
  2696. if (!NT_SUCCESS(Status) )
  2697. return Status;
  2698. t = CSR_SERVER_QUERYCLIENTTHREAD();
  2699. Status = NtDuplicateObject (
  2700. NtCurrentProcess(),
  2701. *ServerHandle,
  2702. t->Process->ProcessHandle,
  2703. ClientHandle,
  2704. 0,
  2705. FALSE,
  2706. DUPLICATE_SAME_ACCESS
  2707. );
  2708. if ( NT_SUCCESS(Status) ){
  2709. return STATUS_SUCCESS;
  2710. }
  2711. else {
  2712. NtClose (*ServerHandle);
  2713. return Status;
  2714. }
  2715. }
  2716. // generate global task id
  2717. //
  2718. // The handling of a task id should be redone wrt the user notification
  2719. // private apis
  2720. // note that wow task id is never 0 or (ULONG)-1
  2721. //
  2722. ULONG
  2723. BaseSrvGetWOWTaskId(
  2724. PSHAREDWOWRECORDHEAD pSharedWowHead // (->pSharedWowRecord)
  2725. )
  2726. {
  2727. PWOWRECORD pWOWRecord;
  2728. PSHAREDWOWRECORD pSharedWow = pSharedWowHead->pSharedWowRecord;
  2729. static BOOL fWrapped = FALSE;
  2730. if (WOWTaskIdNext == WOWMAXID) {
  2731. fWrapped = TRUE;
  2732. WOWTaskIdNext = WOWMINID;
  2733. }
  2734. if (fWrapped && NULL != pSharedWow) {
  2735. while (NULL != pSharedWow) {
  2736. #if 0
  2737. if (pSharedWow->WowSessionId == WOWTaskIdNext) {
  2738. if (WOWMAXID == ++WOWTaskIdNext) {
  2739. WOWTaskIdNext = WOWMINID;
  2740. }
  2741. pSharedWow = pSharedWowHead->pSharedWowRecord;
  2742. continue; // go back to the beginning of the loop
  2743. }
  2744. #endif
  2745. // examine all the records for this wow
  2746. pWOWRecord = pSharedWow->pWOWRecord;
  2747. while (NULL != pWOWRecord) {
  2748. if (pWOWRecord->iTask == WOWTaskIdNext) {
  2749. if (WOWMAXID == ++WOWTaskIdNext) {
  2750. WOWTaskIdNext = WOWMINID;
  2751. }
  2752. break; // we are breaking out => (pWOWRecord != NULL)
  2753. }
  2754. pWOWRecord = pWOWRecord->WOWRecordNext;
  2755. }
  2756. if (NULL == pWOWRecord) { // id is ok for this wow -- check the next wow
  2757. pSharedWow = pSharedWow->pNextSharedWow;
  2758. }
  2759. else {
  2760. pSharedWow = pSharedWowHead->pSharedWowRecord;
  2761. }
  2762. }
  2763. }
  2764. return WOWTaskIdNext++;
  2765. }
  2766. VOID
  2767. BaseSrvAddConsoleRecord(
  2768. IN PCONSOLERECORD pConsoleRecord
  2769. )
  2770. {
  2771. pConsoleRecord->Next = DOSHead;
  2772. DOSHead = pConsoleRecord;
  2773. }
  2774. VOID BaseSrvCloseStandardHandles (HANDLE hVDM, PDOSRECORD pDOSRecord)
  2775. {
  2776. PVDMINFO pVDMInfo = pDOSRecord->lpVDMInfo;
  2777. if (pVDMInfo == NULL)
  2778. return;
  2779. if (pVDMInfo->StdIn)
  2780. NtDuplicateObject (hVDM,
  2781. pVDMInfo->StdIn,
  2782. NULL,
  2783. NULL,
  2784. 0,
  2785. 0,
  2786. DUPLICATE_CLOSE_SOURCE);
  2787. if (pVDMInfo->StdOut)
  2788. NtDuplicateObject (hVDM,
  2789. pVDMInfo->StdOut,
  2790. NULL,
  2791. NULL,
  2792. 0,
  2793. 0,
  2794. DUPLICATE_CLOSE_SOURCE);
  2795. if (pVDMInfo->StdErr)
  2796. NtDuplicateObject (hVDM,
  2797. pVDMInfo->StdErr,
  2798. NULL,
  2799. NULL,
  2800. 0,
  2801. 0,
  2802. DUPLICATE_CLOSE_SOURCE);
  2803. pVDMInfo->StdIn = 0;
  2804. pVDMInfo->StdOut = 0;
  2805. pVDMInfo->StdErr = 0;
  2806. return;
  2807. }
  2808. VOID BaseSrvClosePairWaitHandles (PDOSRECORD pDOSRecord)
  2809. {
  2810. PCSR_THREAD t;
  2811. if (pDOSRecord->hWaitForParentDup)
  2812. NtClose (pDOSRecord->hWaitForParentDup);
  2813. t = CSR_SERVER_QUERYCLIENTTHREAD();
  2814. if (pDOSRecord->hWaitForParent)
  2815. NtDuplicateObject (t->Process->ProcessHandle,
  2816. pDOSRecord->hWaitForParent,
  2817. NULL,
  2818. NULL,
  2819. 0,
  2820. 0,
  2821. DUPLICATE_CLOSE_SOURCE);
  2822. pDOSRecord->hWaitForParentDup = 0;
  2823. pDOSRecord->hWaitForParent = 0;
  2824. return;
  2825. }
  2826. ULONG
  2827. BaseSrvSetReenterCount (
  2828. IN OUT PCSR_API_MSG m,
  2829. IN OUT PCSR_REPLY_STATUS ReplyStatus
  2830. )
  2831. {
  2832. PBASE_SET_REENTER_COUNT_MSG b = (PBASE_SET_REENTER_COUNT_MSG)&m->u.ApiMessageData;
  2833. NTSTATUS Status;
  2834. PCONSOLERECORD pConsoleRecord;
  2835. ULONG SequenceNumber;
  2836. if(!NT_SUCCESS(BaseSrvGetVdmSequence(m->h.ClientId.UniqueProcess, &SequenceNumber))) {
  2837. return (ULONG)STATUS_INVALID_PARAMETER;
  2838. }
  2839. Status = RtlEnterCriticalSection( &BaseSrvDOSCriticalSection );
  2840. ASSERT(NT_SUCCESS(Status));
  2841. Status = BaseSrvGetConsoleRecord(b->ConsoleHandle,&pConsoleRecord);
  2842. if (!NT_SUCCESS (Status) || SequenceNumber != pConsoleRecord->SequenceNumber) {
  2843. RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
  2844. return ((ULONG)STATUS_INVALID_PARAMETER);
  2845. }
  2846. if (b->fIncDec == INCREMENT_REENTER_COUNT)
  2847. pConsoleRecord->nReEntrancy++;
  2848. else {
  2849. pConsoleRecord->nReEntrancy--;
  2850. if(pConsoleRecord->hWaitForVDMDup)
  2851. NtSetEvent (pConsoleRecord->hWaitForVDMDup,NULL);
  2852. }
  2853. RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
  2854. return TRUE;
  2855. }
  2856. /*
  2857. * Spawn of ntvdm failed before CreateProcessW finished.
  2858. * delete the console record.
  2859. */
  2860. VOID
  2861. BaseSrvVDMTerminated (
  2862. IN HANDLE hVDM,
  2863. IN ULONG DosSesId
  2864. )
  2865. {
  2866. NTSTATUS Status;
  2867. PCONSOLERECORD pConsoleRecord;
  2868. RtlEnterCriticalSection( &BaseSrvDOSCriticalSection );
  2869. if (!hVDM) // no-console-handle case
  2870. Status = GetConsoleRecordDosSesId(DosSesId,&pConsoleRecord);
  2871. else
  2872. Status = BaseSrvGetConsoleRecord(hVDM,&pConsoleRecord);
  2873. if (NT_SUCCESS (Status)) {
  2874. BaseSrvExitVDMWorker(pConsoleRecord);
  2875. }
  2876. RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
  2877. }
  2878. NTSTATUS
  2879. BaseSrvUpdateVDMSequenceNumber (
  2880. IN ULONG VdmBinaryType, // binary type
  2881. IN HANDLE hVDM, // console handle
  2882. IN ULONG DosSesId, // session id
  2883. IN HANDLE UniqueProcessClientID, // client id
  2884. IN HANDLE UniqueProcessParentID // parent id
  2885. )
  2886. {
  2887. NTSTATUS Status;
  2888. PCSR_PROCESS ProcessVDM;
  2889. ULONG SequenceNumber;
  2890. if(!NT_SUCCESS(BaseSrvGetVdmSequence(UniqueProcessParentID, &SequenceNumber))){
  2891. return STATUS_INVALID_PARAMETER;
  2892. }
  2893. // so how do we know what to update ?
  2894. // this condition is always true: (hvdm ^ DosSesId)
  2895. // hence since shared wow
  2896. // sequence numbers are important -- hence we need to acquire
  2897. // a wow critical section -- does not hurt -- this op performed once
  2898. // during the new wow creation
  2899. if (IS_SHARED_WOW_BINARY(VdmBinaryType)) {
  2900. PSHAREDWOWRECORD pSharedWowRecord;
  2901. Status = ENTER_WOW_CRITICAL();
  2902. ASSERT(NT_SUCCESS(Status));
  2903. // this looks like a shared wow binary -- hence locate the
  2904. // appropriate vdm either by hvdm or by dos session id
  2905. if (!hVDM) { // search by console handle
  2906. Status = BaseSrvFindSharedWowRecordByConsoleHandle(&gWowHead,
  2907. hVDM,
  2908. &pSharedWowRecord);
  2909. }
  2910. else { // search by the task id
  2911. Status = BaseSrvFindSharedWowRecordByTaskId(&gWowHead,
  2912. DosSesId,
  2913. &pSharedWowRecord,
  2914. NULL);
  2915. }
  2916. if (NT_SUCCESS(Status) && 0 == pSharedWowRecord->SequenceNumber) {
  2917. if (SequenceNumber == pSharedWowRecord->ParentSequenceNumber) {
  2918. // now obtain a sequence number please
  2919. Status = CsrLockProcessByClientId(UniqueProcessClientID,
  2920. &ProcessVDM);
  2921. if (NT_SUCCESS(Status)) {
  2922. ProcessVDM->fVDM = TRUE;
  2923. pSharedWowRecord->SequenceNumber = ProcessVDM->SequenceNumber;
  2924. pSharedWowRecord->ParentSequenceNumber = 0;
  2925. pSharedWowRecord->dwWowExecProcessId = HandleToLong(UniqueProcessClientID);
  2926. CsrUnlockProcess(ProcessVDM);
  2927. } else {
  2928. // The spawned ntvdm.exe went away, give up.
  2929. BaseSrvDeleteSharedWowRecord(&gWowHead,pSharedWowRecord);
  2930. }
  2931. }
  2932. }
  2933. else {
  2934. #if DEVL
  2935. DbgPrint( "BASESRV: WOW is in inconsistent state. Contact WOW Team\n");
  2936. #endif
  2937. }
  2938. LEAVE_WOW_CRITICAL();
  2939. }
  2940. else { // not shared wow binary
  2941. PCONSOLERECORD pConsoleRecord;
  2942. Status = RtlEnterCriticalSection( &BaseSrvDOSCriticalSection );
  2943. ASSERT( NT_SUCCESS( Status ) );
  2944. if (!hVDM) // no-console-handle case
  2945. Status = GetConsoleRecordDosSesId(DosSesId,&pConsoleRecord);
  2946. else
  2947. Status = BaseSrvGetConsoleRecord(hVDM,&pConsoleRecord);
  2948. if (NT_SUCCESS (Status) && 0 == pConsoleRecord->SequenceNumber) {
  2949. if (SequenceNumber == pConsoleRecord->ParentSequenceNumber) {
  2950. Status = CsrLockProcessByClientId(UniqueProcessClientID,
  2951. &ProcessVDM);
  2952. if (NT_SUCCESS(Status)) {
  2953. ProcessVDM->fVDM = TRUE;
  2954. pConsoleRecord->SequenceNumber = ProcessVDM->SequenceNumber;
  2955. pConsoleRecord->ParentSequenceNumber = 0;
  2956. pConsoleRecord->dwProcessId = HandleToLong(UniqueProcessClientID);
  2957. CsrUnlockProcess(ProcessVDM);
  2958. }
  2959. // The spawned ntvdm.exe went away, give up.
  2960. // The caller BasepCreateProcess will clean up dos records, so we don't need to here.
  2961. // else
  2962. // BaseSrvExitVdmWorker(pConsoleRecord);
  2963. }
  2964. }
  2965. else {
  2966. #if DEVL
  2967. DbgPrint( "BASESRV: DOS is in inconsistent state. Contact DOS Team\n");
  2968. #endif
  2969. }
  2970. RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
  2971. }
  2972. return Status;
  2973. }
  2974. VOID
  2975. BaseSrvCleanupVDMResources ( //////// BUGBUGBUGBUG
  2976. IN PCSR_PROCESS Process
  2977. )
  2978. {
  2979. PCONSOLERECORD pConsoleHead;
  2980. PSHAREDWOWRECORD pSharedWowRecord;
  2981. NTSTATUS Status;
  2982. PBATRECORD pBatRecord;
  2983. if (!Process->fVDM) {
  2984. Status = RtlEnterCriticalSection( &BaseSrvDOSCriticalSection );
  2985. ASSERT(NT_SUCCESS(Status));
  2986. pBatRecord = BatRecordHead;
  2987. while (pBatRecord &&
  2988. pBatRecord->SequenceNumber != Process->SequenceNumber)
  2989. pBatRecord = pBatRecord->BatRecordNext;
  2990. if (pBatRecord)
  2991. BaseSrvFreeAndRemoveBatRecord(pBatRecord);
  2992. RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
  2993. }
  2994. // search all the shared wow's
  2995. Status = ENTER_WOW_CRITICAL();
  2996. ASSERT(NT_SUCCESS(Status));
  2997. pSharedWowRecord = gWowHead.pSharedWowRecord;
  2998. while (pSharedWowRecord) {
  2999. if (pSharedWowRecord->SequenceNumber == Process->SequenceNumber) {
  3000. BaseSrvDeleteSharedWowRecord(&gWowHead, pSharedWowRecord);
  3001. break;
  3002. }
  3003. else
  3004. pSharedWowRecord = pSharedWowRecord->pNextSharedWow;
  3005. }
  3006. pSharedWowRecord = gWowHead.pSharedWowRecord;
  3007. while (pSharedWowRecord) {
  3008. if (pSharedWowRecord->ParentSequenceNumber == Process->SequenceNumber) {
  3009. BaseSrvDeleteSharedWowRecord(&gWowHead, pSharedWowRecord);
  3010. break;
  3011. }
  3012. else
  3013. pSharedWowRecord = pSharedWowRecord->pNextSharedWow;
  3014. }
  3015. LEAVE_WOW_CRITICAL();
  3016. // search all the dos's and separate wow's
  3017. Status = RtlEnterCriticalSection( &BaseSrvDOSCriticalSection );
  3018. ASSERT(NT_SUCCESS(Status));
  3019. pConsoleHead = DOSHead;
  3020. while (pConsoleHead) {
  3021. if (pConsoleHead->SequenceNumber == Process->SequenceNumber){
  3022. BaseSrvExitVDMWorker (pConsoleHead);
  3023. break;
  3024. }
  3025. else
  3026. pConsoleHead = pConsoleHead->Next;
  3027. }
  3028. pConsoleHead = DOSHead;
  3029. while (pConsoleHead) {
  3030. if (pConsoleHead->ParentSequenceNumber == Process->SequenceNumber){
  3031. BaseSrvExitVDMWorker (pConsoleHead);
  3032. break;
  3033. }
  3034. else
  3035. pConsoleHead = pConsoleHead->Next;
  3036. }
  3037. RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
  3038. return;
  3039. }
  3040. VOID
  3041. BaseSrvExitVDMWorker (
  3042. PCONSOLERECORD pConsoleRecord
  3043. )
  3044. {
  3045. PDOSRECORD pDOSRecord;
  3046. if (pConsoleRecord->hWaitForVDMDup){
  3047. NtClose(pConsoleRecord->hWaitForVDMDup);
  3048. pConsoleRecord->hWaitForVDMDup =0;
  3049. }
  3050. pDOSRecord = pConsoleRecord->DOSRecord;
  3051. while (pDOSRecord) {
  3052. if (pDOSRecord->hWaitForParentDup) {
  3053. NtSetEvent (pDOSRecord->hWaitForParentDup,NULL);
  3054. NtClose (pDOSRecord->hWaitForParentDup);
  3055. pDOSRecord->hWaitForParentDup = 0;
  3056. }
  3057. pDOSRecord = pDOSRecord->DOSRecordNext;
  3058. }
  3059. NtClose(pConsoleRecord->hVDM);
  3060. BaseSrvFreeConsoleRecord (pConsoleRecord);
  3061. return;
  3062. }
  3063. NTSTATUS
  3064. BaseSrvFillPifInfo (
  3065. PVDMINFO lpVDMInfo,
  3066. PBASE_GET_NEXT_VDM_COMMAND_MSG b
  3067. )
  3068. {
  3069. LPSTR Title;
  3070. ULONG TitleLen;
  3071. NTSTATUS Status;
  3072. Status = STATUS_INVALID_PARAMETER;
  3073. if (!lpVDMInfo)
  3074. return Status;
  3075. /*
  3076. * Get the title for the window in precedence order
  3077. */
  3078. // startupinfo title
  3079. if (lpVDMInfo->TitleLen && lpVDMInfo->Title)
  3080. {
  3081. Title = lpVDMInfo->Title;
  3082. TitleLen = lpVDMInfo->TitleLen;
  3083. }
  3084. // App Name
  3085. else if (lpVDMInfo->AppName && lpVDMInfo->AppLen)
  3086. {
  3087. Title = lpVDMInfo->AppName;
  3088. TitleLen = lpVDMInfo->AppLen;
  3089. }
  3090. // hopeless
  3091. else {
  3092. Title = NULL;
  3093. TitleLen = 0;
  3094. }
  3095. try {
  3096. if (b->PifLen) {
  3097. *b->PifFile = '\0';
  3098. }
  3099. if (b->TitleLen) {
  3100. *b->Title = '\0';
  3101. }
  3102. if (b->CurDirectoryLen) {
  3103. *b->CurDirectory = '\0';
  3104. }
  3105. if ( (!b->TitleLen || TitleLen <= b->TitleLen) &&
  3106. (!b->PifLen || lpVDMInfo->PifLen <= b->PifLen) &&
  3107. (!b->CurDirectoryLen ||
  3108. lpVDMInfo->CurDirectoryLen <= b->CurDirectoryLen) &&
  3109. (!b->ReservedLen || lpVDMInfo->ReservedLen <= b->ReservedLen))
  3110. {
  3111. if (b->TitleLen) {
  3112. if (Title && TitleLen) {
  3113. RtlMoveMemory(b->Title, Title, TitleLen);
  3114. *((LPSTR)b->Title + TitleLen - 1) = '\0';
  3115. }
  3116. else {
  3117. *b->Title = '\0';
  3118. }
  3119. }
  3120. if (lpVDMInfo->PifLen && b->PifLen)
  3121. RtlMoveMemory(b->PifFile,
  3122. lpVDMInfo->PifFile,
  3123. lpVDMInfo->PifLen);
  3124. if (lpVDMInfo->CurDirectoryLen && b->CurDirectoryLen)
  3125. RtlMoveMemory(b->CurDirectory,
  3126. lpVDMInfo->CurDirectory,
  3127. lpVDMInfo->CurDirectoryLen
  3128. );
  3129. if (lpVDMInfo->Reserved && b->ReservedLen)
  3130. RtlMoveMemory(b->Reserved,
  3131. lpVDMInfo->Reserved,
  3132. lpVDMInfo->ReservedLen
  3133. );
  3134. Status = STATUS_SUCCESS;
  3135. }
  3136. }
  3137. except(EXCEPTION_EXECUTE_HANDLER) {
  3138. Status = GetExceptionCode();
  3139. }
  3140. /* fill out the size for each field */
  3141. b->PifLen = (USHORT)lpVDMInfo->PifLen;
  3142. b->CurDirectoryLen = lpVDMInfo->CurDirectoryLen;
  3143. b->TitleLen = TitleLen;
  3144. b->ReservedLen = lpVDMInfo->ReservedLen;
  3145. return Status;
  3146. }
  3147. /***************************************************************************\
  3148. * IsClientSystem
  3149. *
  3150. * Determines if caller is SYSTEM
  3151. *
  3152. * Returns TRUE is caller is system, FALSE if not (or error)
  3153. *
  3154. * History:
  3155. * 12-May-94 AndyH Created
  3156. \***************************************************************************/
  3157. BOOL
  3158. IsClientSystem(
  3159. HANDLE hUserToken
  3160. )
  3161. {
  3162. BYTE achBuffer[100];
  3163. PTOKEN_USER pUser = (PTOKEN_USER) achBuffer;
  3164. DWORD dwBytesRequired;
  3165. NTSTATUS NtStatus;
  3166. BOOL fAllocatedBuffer = FALSE;
  3167. BOOL fSystem;
  3168. SID_IDENTIFIER_AUTHORITY SidIdAuth = SECURITY_NT_AUTHORITY;
  3169. static PSID pSystemSid = NULL;
  3170. if (!pSystemSid) {
  3171. // Create a sid for local system
  3172. NtStatus = RtlAllocateAndInitializeSid(
  3173. &SidIdAuth,
  3174. 1, // SubAuthorityCount, 1 for local system
  3175. SECURITY_LOCAL_SYSTEM_RID,
  3176. 0,0,0,0,0,0,0,
  3177. &pSystemSid
  3178. );
  3179. if (!NT_SUCCESS(NtStatus)) {
  3180. pSystemSid = NULL;
  3181. return FALSE;
  3182. }
  3183. }
  3184. NtStatus = NtQueryInformationToken(
  3185. hUserToken, // Handle
  3186. TokenUser, // TokenInformationClass
  3187. pUser, // TokenInformation
  3188. sizeof(achBuffer), // TokenInformationLength
  3189. &dwBytesRequired // ReturnLength
  3190. );
  3191. if (!NT_SUCCESS(NtStatus))
  3192. {
  3193. if (NtStatus != STATUS_BUFFER_TOO_SMALL)
  3194. {
  3195. return FALSE;
  3196. }
  3197. //
  3198. // Allocate space for the user info
  3199. //
  3200. pUser = (PTOKEN_USER) RtlAllocateHeap(BaseSrvHeap, MAKE_TAG( VDM_TAG ), dwBytesRequired);
  3201. if (pUser == NULL)
  3202. {
  3203. return FALSE;
  3204. }
  3205. fAllocatedBuffer = TRUE;
  3206. //
  3207. // Read in the UserInfo
  3208. //
  3209. NtStatus = NtQueryInformationToken(
  3210. hUserToken, // Handle
  3211. TokenUser, // TokenInformationClass
  3212. pUser, // TokenInformation
  3213. dwBytesRequired, // TokenInformationLength
  3214. &dwBytesRequired // ReturnLength
  3215. );
  3216. if (!NT_SUCCESS(NtStatus))
  3217. {
  3218. RtlFreeHeap(BaseSrvHeap, 0, pUser);
  3219. return FALSE;
  3220. }
  3221. }
  3222. // Compare callers SID with SystemSid
  3223. fSystem = RtlEqualSid(pSystemSid, pUser->User.Sid);
  3224. if (fAllocatedBuffer)
  3225. {
  3226. RtlFreeHeap(BaseSrvHeap, 0, pUser);
  3227. }
  3228. return (fSystem);
  3229. }
  3230. BOOL
  3231. BaseSrvIsVdmAllowed(
  3232. VOID
  3233. )
  3234. /*++
  3235. Routine Description:
  3236. This routine checks the registry to see if running NTVDM is disabled.
  3237. If the information is not specified in registry, the default will be NOT disabled and
  3238. TRUE will be returned to indicated running VDM is allowed.
  3239. Arguments:
  3240. None.
  3241. Return Value:
  3242. BOOL - TRUE means yes; Otherwise no.
  3243. --*/
  3244. {
  3245. NTSTATUS status;
  3246. HANDLE hCurrentUser, hAppCompat;
  3247. UNICODE_STRING unicodeKeyName, unicodeValueName;
  3248. OBJECT_ATTRIBUTES objectAttributes;
  3249. PKEY_VALUE_PARTIAL_INFORMATION keyValueInformation;
  3250. UCHAR valueBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(ULONG)];
  3251. ULONG resultLength;
  3252. BOOL vdmAllowed, impersonate, checkDefault = TRUE;
  3253. ULONG flags = 0;
  3254. RtlInitUnicodeString(&unicodeValueName, L"VDMDisallowed" );
  3255. keyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)valueBuffer;
  3256. //
  3257. // First check if machine policy for Vdm Disallow is enabled, if yes
  3258. // vdm is not allowed to run.
  3259. //
  3260. RtlInitUnicodeString(&unicodeKeyName,
  3261. L"\\REGISTRY\\MACHINE\\Software\\Policies\\Microsoft\\Windows\\AppCompat");
  3262. InitializeObjectAttributes( &objectAttributes,
  3263. &unicodeKeyName,
  3264. OBJ_CASE_INSENSITIVE,
  3265. NULL,
  3266. NULL );
  3267. //
  3268. // Open key for READ access.
  3269. //
  3270. status = NtOpenKey( &hAppCompat,
  3271. KEY_READ,
  3272. &objectAttributes );
  3273. if (NT_SUCCESS(status))
  3274. {
  3275. status = NtQueryValueKey( hAppCompat,
  3276. &unicodeValueName,
  3277. KeyValuePartialInformation,
  3278. keyValueInformation,
  3279. sizeof(valueBuffer),
  3280. &resultLength
  3281. );
  3282. NtClose( hAppCompat);
  3283. if (NT_SUCCESS(status) && keyValueInformation->Type == REG_DWORD)
  3284. {
  3285. checkDefault = FALSE;
  3286. flags = *(PULONG)keyValueInformation->Data;
  3287. if (flags)
  3288. {
  3289. return FALSE;
  3290. }
  3291. }
  3292. }
  3293. //
  3294. // If we come here, machine policy is either not configured or VDM
  3295. // is allowed to run on this machine.
  3296. // Next check if current user policy for Vdm Disallow is enabled, if yes
  3297. // vdm is not allowed to run.
  3298. //
  3299. impersonate = CsrImpersonateClient(NULL);
  3300. if (impersonate) {
  3301. status = RtlOpenCurrentUser(KEY_READ, &hCurrentUser);
  3302. CsrRevertToSelf();
  3303. } else {
  3304. status = STATUS_BAD_IMPERSONATION_LEVEL;
  3305. }
  3306. if (NT_SUCCESS(status))
  3307. {
  3308. RtlInitUnicodeString(&unicodeKeyName,
  3309. L"Software\\Policies\\Microsoft\\Windows\\AppCompat");
  3310. InitializeObjectAttributes( &objectAttributes,
  3311. &unicodeKeyName,
  3312. OBJ_CASE_INSENSITIVE,
  3313. hCurrentUser,
  3314. NULL );
  3315. //
  3316. // Open key for READ access.
  3317. //
  3318. status = NtOpenKey( &hAppCompat,
  3319. KEY_READ,
  3320. &objectAttributes );
  3321. NtClose(hCurrentUser);
  3322. if (NT_SUCCESS(status))
  3323. {
  3324. status = NtQueryValueKey( hAppCompat,
  3325. &unicodeValueName,
  3326. KeyValuePartialInformation,
  3327. keyValueInformation,
  3328. sizeof(valueBuffer),
  3329. &resultLength
  3330. );
  3331. NtClose( hAppCompat);
  3332. if (NT_SUCCESS(status) && keyValueInformation->Type == REG_DWORD)
  3333. {
  3334. checkDefault = FALSE;
  3335. flags = *(PULONG)keyValueInformation->Data;
  3336. if (flags)
  3337. {
  3338. return FALSE;
  3339. }
  3340. }
  3341. }
  3342. }
  3343. if (checkDefault == FALSE)
  3344. {
  3345. return TRUE;
  3346. }
  3347. //
  3348. // If we come here, machine policy is not configured AND
  3349. // the current user policy is not configured either.
  3350. // Next check if default setting for Vdm Disallow is enabled, if yes
  3351. // vdm is not allowed to run.
  3352. //
  3353. vdmAllowed = TRUE;
  3354. RtlInitUnicodeString(&unicodeKeyName, L"\\REGISTRY\\MACHINE\\System\\CurrentControlSet\\Control\\WOW");
  3355. RtlInitUnicodeString(&unicodeValueName, L"DisallowedPolicyDefault" );
  3356. InitializeObjectAttributes( &objectAttributes,
  3357. &unicodeKeyName,
  3358. OBJ_CASE_INSENSITIVE,
  3359. NULL,
  3360. NULL );
  3361. //
  3362. // Open key for READ access.
  3363. //
  3364. status = NtOpenKey( &hAppCompat,
  3365. KEY_READ,
  3366. &objectAttributes );
  3367. if (NT_SUCCESS(status))
  3368. {
  3369. status = NtQueryValueKey( hAppCompat,
  3370. &unicodeValueName,
  3371. KeyValuePartialInformation,
  3372. keyValueInformation,
  3373. sizeof(valueBuffer),
  3374. &resultLength
  3375. );
  3376. NtClose( hAppCompat);
  3377. if (NT_SUCCESS(status))
  3378. {
  3379. if (keyValueInformation->Type == REG_DWORD)
  3380. {
  3381. flags = *(PULONG)keyValueInformation->Data;
  3382. if (flags) vdmAllowed = FALSE;
  3383. }
  3384. }
  3385. }
  3386. return vdmAllowed;
  3387. }
  3388. NTSTATUS
  3389. BaseSrvIsClientVdm(
  3390. IN HANDLE UniqueProcessClientId
  3391. )
  3392. /*
  3393. * Verifies that the client thread is in a VDM process
  3394. *
  3395. */
  3396. {
  3397. NTSTATUS Status;
  3398. PCSR_PROCESS Process;
  3399. VDM_QUERY_VDM_PROCESS_DATA QueryVdmProcessData;
  3400. Status = CsrLockProcessByClientId(UniqueProcessClientId,&Process);
  3401. if (!NT_SUCCESS(Status))
  3402. return Status;
  3403. //
  3404. // Check the Target Process to see if this is a Wx86 process
  3405. //
  3406. QueryVdmProcessData.IsVdmProcess = FALSE;
  3407. QueryVdmProcessData.ProcessHandle = Process->ProcessHandle;
  3408. Status = NtVdmControl(VdmQueryVdmProcess, &QueryVdmProcessData);
  3409. if (!NT_SUCCESS(Status) || QueryVdmProcessData.IsVdmProcess == FALSE) {
  3410. Status = STATUS_ACCESS_DENIED;
  3411. }
  3412. CsrUnlockProcess(Process);
  3413. return(Status);
  3414. }
  3415. NTSTATUS
  3416. BaseSrvGetSharedWowRecordByPid(
  3417. DWORD dwProcessId,
  3418. PSHAREDWOWRECORD* ppSharedWowRecord
  3419. )
  3420. {
  3421. PSHAREDWOWRECORD pSharedWowRecord = gWowHead.pSharedWowRecord;
  3422. while (NULL != pSharedWowRecord) {
  3423. if (pSharedWowRecord->dwWowExecProcessId == dwProcessId) {
  3424. break;
  3425. }
  3426. pSharedWowRecord = pSharedWowRecord->pNextSharedWow;
  3427. }
  3428. if (NULL != pSharedWowRecord) {
  3429. *ppSharedWowRecord = pSharedWowRecord;
  3430. return STATUS_SUCCESS;
  3431. }
  3432. return STATUS_NOT_FOUND; // bummer, this is not found
  3433. }
  3434. NTSTATUS
  3435. BaseSrvGetConsoleRecordByPid (
  3436. DWORD dwProcessId,
  3437. OUT PCONSOLERECORD *pConsoleRecord
  3438. )
  3439. {
  3440. PCONSOLERECORD pConsoleHead;
  3441. pConsoleHead = DOSHead;
  3442. while (pConsoleHead) {
  3443. if (pConsoleHead->dwProcessId == dwProcessId){
  3444. *pConsoleRecord = pConsoleHead;
  3445. return STATUS_SUCCESS;
  3446. }
  3447. else
  3448. pConsoleHead = pConsoleHead->Next;
  3449. }
  3450. return STATUS_NOT_FOUND;
  3451. }
  3452. NTSTATUS
  3453. BaseSrvAddSepWowTask(
  3454. PBASE_GET_NEXT_VDM_COMMAND_MSG b,
  3455. PCONSOLERECORD pConsoleRecord
  3456. ){
  3457. PDOSRECORD pDosRecord;
  3458. LPSHAREDTASK pSharedTask;
  3459. PCHAR pFilePath;
  3460. DWORD dwFilePath;
  3461. BOOL fWinExecApp = FALSE;
  3462. if(b->EnvLen != sizeof(SHAREDTASK)) {
  3463. return STATUS_INVALID_PARAMETER;
  3464. }
  3465. if(!pConsoleRecord->pfnW32HungAppNotifyThread) {
  3466. pConsoleRecord->pfnW32HungAppNotifyThread = (LPTHREAD_START_ROUTINE)b->Reserved;
  3467. }
  3468. if(b->iTask == -1) {
  3469. // this wow app was run through winexec instead of createprocess
  3470. // we need to add a record for this app.
  3471. pDosRecord = BaseSrvAllocateDOSRecord();
  3472. if(NULL == pDosRecord) {
  3473. return STATUS_MEMORY_NOT_ALLOCATED;
  3474. }
  3475. pDosRecord->iTask = BaseSrvGetWOWTaskId(&gWowHead);
  3476. pDosRecord->VDMState = VDM_BUSY;
  3477. fWinExecApp = TRUE;
  3478. }
  3479. else {
  3480. pDosRecord = pConsoleRecord->DOSRecord;
  3481. }
  3482. if(pDosRecord->pFilePath) {
  3483. RtlFreeHeap(RtlProcessHeap (), 0, pDosRecord->pFilePath);
  3484. pDosRecord->pFilePath = NULL;
  3485. }
  3486. pSharedTask = (LPSHAREDTASK) b->Env;
  3487. pFilePath = pSharedTask->szFilePath;
  3488. while(*pFilePath &&
  3489. pFilePath < pSharedTask->szFilePath + 127) {
  3490. pFilePath++;
  3491. }
  3492. dwFilePath = (DWORD)(pFilePath - pSharedTask->szFilePath) + 1;
  3493. if(pDosRecord->pFilePath) {
  3494. RtlFreeHeap(RtlProcessHeap (), 0, pDosRecord->pFilePath);
  3495. }
  3496. pDosRecord->pFilePath = RtlAllocateHeap ( RtlProcessHeap (), MAKE_TAG( VDM_TAG ), dwFilePath);
  3497. if(!pDosRecord->pFilePath) {
  3498. if(fWinExecApp) {
  3499. BaseSrvFreeDOSRecord(pDosRecord);
  3500. }
  3501. return STATUS_MEMORY_NOT_ALLOCATED;
  3502. }
  3503. pDosRecord->dwThreadId = pSharedTask->dwThreadId;
  3504. pDosRecord->hTask16 = pSharedTask->hTask16;
  3505. pDosRecord->hMod16 = pSharedTask->hMod16;
  3506. RtlCopyMemory( pDosRecord->szModName, pSharedTask->szModName,9);
  3507. RtlCopyMemory( pDosRecord->pFilePath, pSharedTask->szFilePath, dwFilePath);
  3508. pDosRecord->pFilePath[dwFilePath-1] = 0;
  3509. if(fWinExecApp) {
  3510. BaseSrvAddDOSRecord(pConsoleRecord,pDosRecord);
  3511. }
  3512. return STATUS_SUCCESS;
  3513. }
  3514. NTSTATUS BaseSrvAddSharedWowTask (
  3515. PBASE_GET_NEXT_VDM_COMMAND_MSG b,
  3516. PSHAREDWOWRECORD pSharedWow
  3517. )
  3518. {
  3519. PWOWRECORD pWowRecord;
  3520. BOOL fWinExecApp = FALSE;
  3521. LPSHAREDTASK pSharedTask;
  3522. PCHAR pFilePath;
  3523. DWORD dwFilePath;
  3524. //
  3525. // Make sure source buffer is the right size.
  3526. //
  3527. if(b->EnvLen != sizeof(SHAREDTASK)) {
  3528. return STATUS_INVALID_PARAMETER;
  3529. }
  3530. if(!pSharedWow->pfnW32HungAppNotifyThread) {
  3531. pSharedWow->pfnW32HungAppNotifyThread = (LPTHREAD_START_ROUTINE)b->Reserved;
  3532. }
  3533. if(b->iTask == -1) {
  3534. // this wow app was run through winexec instead of createprocess
  3535. // we need to add a record for this app.
  3536. pWowRecord = BaseSrvAllocateWOWRecord(&gWowHead);
  3537. if(NULL == pWowRecord) {
  3538. return STATUS_MEMORY_NOT_ALLOCATED;
  3539. }
  3540. pWowRecord->fDispatched = TRUE;
  3541. fWinExecApp = TRUE;
  3542. }
  3543. else {
  3544. // this wow app run through createprocess, there should be a record
  3545. // of it stored someplace.
  3546. // find it and check if it needs to be updated
  3547. pWowRecord = pSharedWow->pWOWRecord;
  3548. while (NULL != pWowRecord && pWowRecord->iTask != b->iTask){
  3549. pWowRecord = pWowRecord->WOWRecordNext;
  3550. }
  3551. if (NULL == pWowRecord) {
  3552. // Couldn't find the record,bad iTask then
  3553. return STATUS_INVALID_PARAMETER;
  3554. }
  3555. }
  3556. b->iTask = pWowRecord->iTask;
  3557. pSharedTask = (LPSHAREDTASK) b->Env;
  3558. pFilePath = pSharedTask->szFilePath;
  3559. while(*pFilePath &&
  3560. pFilePath < pSharedTask->szFilePath + 127) {
  3561. pFilePath++;
  3562. }
  3563. dwFilePath = (DWORD)(pFilePath - pSharedTask->szFilePath) + 1;
  3564. if(pWowRecord->pFilePath) {
  3565. RtlFreeHeap(RtlProcessHeap (), 0, pWowRecord->pFilePath);
  3566. }
  3567. pWowRecord->pFilePath = RtlAllocateHeap ( RtlProcessHeap (), MAKE_TAG( VDM_TAG ), dwFilePath);
  3568. if(!pWowRecord->pFilePath) {
  3569. if(fWinExecApp) {
  3570. BaseSrvFreeWOWRecord(pWowRecord);
  3571. }
  3572. return STATUS_MEMORY_NOT_ALLOCATED;
  3573. }
  3574. pWowRecord->dwThreadId = pSharedTask->dwThreadId;
  3575. pWowRecord->hTask16 = pSharedTask->hTask16;
  3576. pWowRecord->hMod16 = pSharedTask->hMod16;
  3577. RtlCopyMemory( pWowRecord->szModName, pSharedTask->szModName,9);
  3578. RtlCopyMemory( pWowRecord->pFilePath, pSharedTask->szFilePath, dwFilePath);
  3579. pWowRecord->pFilePath[dwFilePath-1] = 0;
  3580. if(fWinExecApp) {
  3581. BaseSrvAddWOWRecord (pSharedWow, pWowRecord);
  3582. }
  3583. return STATUS_SUCCESS;
  3584. }
  3585. NTSTATUS
  3586. BaseSrvAddWowTask (
  3587. PCSR_API_MSG m,
  3588. ULONG SequenceNumber
  3589. ){
  3590. PBASE_GET_NEXT_VDM_COMMAND_MSG b = (PBASE_GET_NEXT_VDM_COMMAND_MSG)&m->u.ApiMessageData;
  3591. DWORD dwProcessId = HandleToLong( m->h.ClientId.UniqueProcess);
  3592. PCONSOLERECORD pConsoleRecord;
  3593. PSHAREDWOWRECORD pSharedWow;
  3594. NTSTATUS Status;
  3595. RtlEnterCriticalSection( &BaseSrvDOSCriticalSection );
  3596. Status = BaseSrvGetConsoleRecordByPid(dwProcessId, &pConsoleRecord);
  3597. if(NT_SUCCESS(Status)) {
  3598. if(pConsoleRecord->SequenceNumber == SequenceNumber) {
  3599. Status = BaseSrvAddSepWowTask(b, pConsoleRecord);
  3600. }
  3601. else {
  3602. RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
  3603. return STATUS_INVALID_PARAMETER;
  3604. }
  3605. }
  3606. RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
  3607. if(NT_SUCCESS(Status)) {
  3608. return STATUS_SUCCESS;
  3609. }
  3610. ENTER_WOW_CRITICAL();
  3611. Status = BaseSrvGetSharedWowRecordByPid(dwProcessId, &pSharedWow);
  3612. if(NT_SUCCESS(Status)) {
  3613. if(pSharedWow->SequenceNumber == SequenceNumber) {
  3614. Status = BaseSrvAddSharedWowTask(b, pSharedWow);
  3615. }
  3616. else
  3617. Status = STATUS_INVALID_PARAMETER;
  3618. }
  3619. LEAVE_WOW_CRITICAL();
  3620. return Status;
  3621. }
  3622. BOOL
  3623. BaseSrvCheckProcessAccess(
  3624. DWORD dwProcessId,
  3625. BOOL fImpersonateClientFirst
  3626. ){
  3627. BOOL fResult;
  3628. CLIENT_ID ClientId;
  3629. OBJECT_ATTRIBUTES Obja;
  3630. HANDLE ProcessHandle;
  3631. NTSTATUS Status;
  3632. if(fImpersonateClientFirst) {
  3633. fResult = CsrImpersonateClient(NULL);
  3634. if(!fResult) {
  3635. return STATUS_BAD_IMPERSONATION_LEVEL;
  3636. }
  3637. }
  3638. ClientId.UniqueThread = NULL;
  3639. ClientId.UniqueProcess = LongToHandle(dwProcessId);;
  3640. InitializeObjectAttributes(
  3641. &Obja,
  3642. NULL,
  3643. 0,
  3644. NULL,
  3645. NULL
  3646. );
  3647. Status = NtOpenProcess( &ProcessHandle,
  3648. PROCESS_QUERY_INFORMATION,
  3649. &Obja,
  3650. &ClientId);
  3651. if(fImpersonateClientFirst) {
  3652. CsrRevertToSelf();
  3653. }
  3654. if(!NT_SUCCESS(Status)) {
  3655. return STATUS_INVALID_PARAMETER;
  3656. }
  3657. NtClose(ProcessHandle);
  3658. return STATUS_SUCCESS;
  3659. }
  3660. NTSTATUS
  3661. BaseSrvEnumSepWow (
  3662. PBASE_GET_NEXT_VDM_COMMAND_MSG b,
  3663. PCONSOLERECORD pConsoleRecord
  3664. ){
  3665. PDOSRECORD pDosRecord;
  3666. LPSHAREDTASK pCurrentTask;
  3667. DWORD cbTaskArray = 0;
  3668. PCHAR pSource,pDest;
  3669. NTSTATUS Status;
  3670. pDosRecord = pConsoleRecord->DOSRecord;
  3671. RtlZeroMemory(b->Env, b->EnvLen);
  3672. pCurrentTask = (LPSHAREDTASK)b->Env;
  3673. while(pDosRecord) {
  3674. if(pDosRecord->pFilePath) {
  3675. cbTaskArray += sizeof(SHAREDTASK);
  3676. if(cbTaskArray <= b->EnvLen) {
  3677. pCurrentTask->dwThreadId = pDosRecord->dwThreadId;
  3678. pCurrentTask->hTask16 = pDosRecord->hTask16;
  3679. pCurrentTask->hMod16 = pDosRecord->hMod16;
  3680. RtlCopyMemory(pCurrentTask->szModName,pDosRecord->szModName,9);
  3681. pSource = pDosRecord->pFilePath;
  3682. pDest = pCurrentTask->szFilePath;
  3683. while(*pSource) {
  3684. *pDest++ = *pSource++;
  3685. }
  3686. pCurrentTask++;
  3687. }
  3688. }
  3689. pDosRecord = pDosRecord->DOSRecordNext;
  3690. }
  3691. Status = cbTaskArray > b->EnvLen ? STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS;
  3692. b->EnvLen = cbTaskArray;
  3693. return Status;
  3694. }
  3695. NTSTATUS
  3696. BaseSrvEnumSharedWow (
  3697. PBASE_GET_NEXT_VDM_COMMAND_MSG b,
  3698. PSHAREDWOWRECORD pSharedWow
  3699. ){
  3700. PWOWRECORD pWowRecord;
  3701. LPSHAREDTASK pCurrentTask;
  3702. DWORD cbTaskArray = 0;
  3703. PCHAR pSource,pDest;
  3704. NTSTATUS Status;
  3705. pWowRecord = pSharedWow->pWOWRecord;
  3706. RtlZeroMemory(b->Env, b->EnvLen);
  3707. pCurrentTask = (LPSHAREDTASK)b->Env;
  3708. while(pWowRecord) {
  3709. if(pWowRecord->pFilePath) {
  3710. cbTaskArray += sizeof(SHAREDTASK);
  3711. if(cbTaskArray <= b->EnvLen) {
  3712. pCurrentTask->dwThreadId = pWowRecord->dwThreadId;
  3713. pCurrentTask->hTask16 = pWowRecord->hTask16;
  3714. pCurrentTask->hMod16 = pWowRecord->hMod16;
  3715. RtlCopyMemory(pCurrentTask->szModName,pWowRecord->szModName,9);
  3716. pSource = pWowRecord->pFilePath;
  3717. pDest = pCurrentTask->szFilePath;
  3718. while(*pSource) {
  3719. *pDest++ = *pSource++;
  3720. }
  3721. pCurrentTask++;
  3722. }
  3723. }
  3724. pWowRecord = pWowRecord->WOWRecordNext;
  3725. }
  3726. Status = cbTaskArray > b->EnvLen ? STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS;
  3727. b->EnvLen = cbTaskArray;
  3728. return Status;
  3729. }
  3730. NTSTATUS
  3731. BaseSrvEnumWowTask (
  3732. PBASE_GET_NEXT_VDM_COMMAND_MSG b
  3733. ){
  3734. PCONSOLERECORD pConsoleRecord;
  3735. PSHAREDWOWRECORD pSharedWow;
  3736. BOOL fReturnSize = FALSE;
  3737. NTSTATUS Status;
  3738. Status = BaseSrvCheckProcessAccess(b->iTask,TRUE);
  3739. if(!NT_SUCCESS(Status)) {
  3740. return STATUS_ACCESS_DENIED;
  3741. }
  3742. RtlEnterCriticalSection( &BaseSrvDOSCriticalSection );
  3743. Status = BaseSrvGetConsoleRecordByPid(b->iTask,&pConsoleRecord);
  3744. if(NT_SUCCESS(Status)) {
  3745. Status = BaseSrvEnumSepWow(b,
  3746. pConsoleRecord);
  3747. }
  3748. RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
  3749. if(NT_SUCCESS(Status)) {
  3750. return STATUS_SUCCESS;
  3751. }
  3752. ENTER_WOW_CRITICAL();
  3753. Status = BaseSrvGetSharedWowRecordByPid(b->iTask,&pSharedWow);
  3754. if(NT_SUCCESS(Status)) {
  3755. Status = BaseSrvEnumSharedWow(b,
  3756. pSharedWow);
  3757. }
  3758. LEAVE_WOW_CRITICAL();
  3759. return Status;
  3760. }
  3761. NTSTATUS
  3762. BaseSrvEnumWowProcess(
  3763. PBASE_GET_NEXT_VDM_COMMAND_MSG b
  3764. ){
  3765. LPSHAREDPROCESS pSharedProcess;
  3766. PSHAREDWOWRECORD pSharedWow;
  3767. PCONSOLERECORD pConsoleRecord;
  3768. NTSTATUS Status;
  3769. DWORD cbProcArray = 0;
  3770. BOOL fImpersonate;
  3771. RtlZeroMemory(b->Env, b->EnvLen);
  3772. if(b->iTask) {
  3773. if(!NT_SUCCESS(BaseSrvCheckProcessAccess(b->iTask,TRUE))) {
  3774. return STATUS_ACCESS_DENIED;
  3775. }
  3776. if(b->EnvLen != sizeof(SHAREDPROCESS)) {
  3777. return STATUS_INVALID_PARAMETER;
  3778. }
  3779. ENTER_WOW_CRITICAL();
  3780. Status = BaseSrvGetSharedWowRecordByPid(b->iTask,&pSharedWow);
  3781. if(NT_SUCCESS(Status)) {
  3782. pSharedProcess = (LPSHAREDPROCESS)b->Env;
  3783. pSharedProcess->dwProcessId = pSharedWow->dwWowExecProcessId;
  3784. pSharedProcess->dwAttributes = WOW_SYSTEM;
  3785. pSharedProcess->pfnW32HungAppNotifyThread =pSharedWow->pfnW32HungAppNotifyThread;
  3786. }
  3787. LEAVE_WOW_CRITICAL();
  3788. if(NT_SUCCESS(Status)) {
  3789. return STATUS_SUCCESS;
  3790. }
  3791. RtlEnterCriticalSection( &BaseSrvDOSCriticalSection );
  3792. Status = BaseSrvGetConsoleRecordByPid(b->iTask,&pConsoleRecord);
  3793. if(NT_SUCCESS(Status)) {
  3794. pSharedProcess = (LPSHAREDPROCESS)b->Env;
  3795. pSharedProcess->dwProcessId = pConsoleRecord->dwProcessId;
  3796. pSharedProcess->dwAttributes = 0;
  3797. pSharedProcess->pfnW32HungAppNotifyThread = pConsoleRecord->pfnW32HungAppNotifyThread;
  3798. }
  3799. RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
  3800. return Status;
  3801. }
  3802. fImpersonate = CsrImpersonateClient(NULL);
  3803. if (!fImpersonate) {
  3804. return STATUS_BAD_IMPERSONATION_LEVEL;
  3805. }
  3806. ENTER_WOW_CRITICAL();
  3807. pSharedProcess = (LPSHAREDPROCESS)b->Env;
  3808. pSharedWow = gWowHead.pSharedWowRecord;
  3809. while(pSharedWow) {
  3810. Status =BaseSrvCheckProcessAccess(
  3811. pSharedWow->dwWowExecProcessId,FALSE);
  3812. if(NT_SUCCESS(Status)) {
  3813. cbProcArray += sizeof(SHAREDPROCESS);
  3814. if(cbProcArray <= b->EnvLen) {
  3815. pSharedProcess->dwProcessId = pSharedWow->dwWowExecProcessId;
  3816. pSharedProcess->dwAttributes = WOW_SYSTEM;
  3817. pSharedProcess->pfnW32HungAppNotifyThread =pSharedWow->pfnW32HungAppNotifyThread;
  3818. pSharedProcess++;
  3819. }
  3820. }
  3821. pSharedWow = pSharedWow->pNextSharedWow;
  3822. }
  3823. LEAVE_WOW_CRITICAL();
  3824. RtlEnterCriticalSection( &BaseSrvDOSCriticalSection );
  3825. pConsoleRecord = DOSHead;
  3826. while(pConsoleRecord) {
  3827. // jarbats. 02-04-26
  3828. // The only difference between separate wow and regular dos console records
  3829. // is that DOSRecord->pFilePath is not NULL for a separate wow (initialized
  3830. // in BaseSrvAddSepWow) whereas for dos it is always NULL.
  3831. if(pConsoleRecord->DOSRecord && pConsoleRecord->DOSRecord->pFilePath) {
  3832. Status =BaseSrvCheckProcessAccess(
  3833. pConsoleRecord->dwProcessId,FALSE);
  3834. if(NT_SUCCESS(Status)) {
  3835. cbProcArray += sizeof(SHAREDPROCESS);
  3836. if(cbProcArray <= b->EnvLen) {
  3837. pSharedProcess->dwProcessId = pConsoleRecord->dwProcessId;
  3838. pSharedProcess->dwAttributes = 0;
  3839. pSharedProcess->pfnW32HungAppNotifyThread = pConsoleRecord->pfnW32HungAppNotifyThread;
  3840. pSharedProcess++;
  3841. }
  3842. }
  3843. }
  3844. pConsoleRecord = pConsoleRecord->Next;
  3845. }
  3846. RtlLeaveCriticalSection( &BaseSrvDOSCriticalSection );
  3847. CsrRevertToSelf();
  3848. Status = cbProcArray > b->EnvLen ? STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS;
  3849. b->EnvLen = cbProcArray;
  3850. return Status;
  3851. }