Source code of Windows XP (NT5)
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.

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