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

3837 lines
125 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. vdm.c
  5. Abstract:
  6. This module implements Win32 APIs for VDMs
  7. Author:
  8. Sudeepb Bharati (sudeepb) 04-Sep-1991
  9. Revision History:
  10. --*/
  11. #include "basedll.h"
  12. #include "apcompat.h"
  13. #define STRSAFE_NO_DEPRECATE
  14. #include <strsafe.h>
  15. #pragma hdrstop
  16. BOOL
  17. APIENTRY
  18. GetBinaryTypeA(
  19. IN LPCSTR lpApplicationName,
  20. OUT LPDWORD lpBinaryType
  21. )
  22. /*++
  23. Routine Description: ANSI version of GetBinaryTypeW.
  24. This API returns the binary type of lpApplicationName.
  25. Arguments:
  26. lpApplicationName - Full pathname of the binary
  27. lpBinaryType - pointer where binary type will be returned.
  28. Return Value:
  29. TRUE - if SUCCESS; lpBinaryType has following
  30. SCS_64BIT_BINARY - Win64 Binary
  31. SCS_32BIT_BINARY - Win32 Binary
  32. SCS_DOS_BINARY - DOS Binary
  33. SCS_WOW_BINARY - Windows 3.X Binary
  34. SCS_PIF_BINARY - PIF file
  35. SCS_POSIX_BINARY - POSIX Binary
  36. SCS_OS216_BINARY - OS/2 Binary
  37. FALSE - if file not found or of unknown type. More info with GetLastError
  38. --*/
  39. {
  40. NTSTATUS Status;
  41. PUNICODE_STRING CommandLine;
  42. ANSI_STRING AnsiString;
  43. UNICODE_STRING DynamicCommandLine;
  44. BOOLEAN bReturn = FALSE;
  45. CommandLine = &NtCurrentTeb()->StaticUnicodeString;
  46. RtlInitAnsiString(&AnsiString,lpApplicationName);
  47. if ( (ULONG)AnsiString.Length<<1 < (ULONG)NtCurrentTeb()->StaticUnicodeString.MaximumLength ) {
  48. DynamicCommandLine.Buffer = NULL;
  49. Status = RtlAnsiStringToUnicodeString(CommandLine,&AnsiString,FALSE);
  50. if ( !NT_SUCCESS(Status) ) {
  51. BaseSetLastNTError(Status);
  52. return FALSE;
  53. }
  54. }
  55. else {
  56. Status = RtlAnsiStringToUnicodeString(&DynamicCommandLine,&AnsiString,TRUE);
  57. if ( !NT_SUCCESS(Status) ) {
  58. BaseSetLastNTError(Status);
  59. return FALSE;
  60. }
  61. }
  62. bReturn = (BOOLEAN)GetBinaryTypeW(
  63. DynamicCommandLine.Buffer ? DynamicCommandLine.Buffer : CommandLine->Buffer,
  64. lpBinaryType);
  65. RtlFreeUnicodeString(&DynamicCommandLine);
  66. return((BOOL)bReturn);
  67. }
  68. BOOL
  69. WINAPI
  70. GetBinaryTypeW(
  71. IN LPCWSTR lpApplicationName,
  72. OUT LPDWORD lpBinaryType
  73. )
  74. /*++
  75. Routine Description: Unicode version.
  76. This API returns the binary type of lpApplicationName.
  77. Arguments:
  78. lpApplicationName - Full pathname of the binary
  79. lpBinaryType - pointer where binary type will be returned.
  80. Return Value:
  81. TRUE - if SUCCESS; lpBinaryType has following
  82. SCS_64BIT_BINARY - Win64 Binary
  83. SCS_32BIT_BINARY - Win32 Binary
  84. SCS_DOS_BINARY - DOS Binary
  85. SCS_WOW_BINARY - Windows 3.X Binary
  86. SCS_PIF_BINARY - PIF file
  87. SCS_POSIX_BINARY - POSIX Binary
  88. SCS_OS216_BINARY - OS/2 Binary
  89. FALSE - if file not found or of unknown type. More info with GetLastError
  90. --*/
  91. {
  92. NTSTATUS Status;
  93. UNICODE_STRING PathName;
  94. RTL_RELATIVE_NAME_U RelativeName;
  95. BOOLEAN TranslationStatus;
  96. OBJECT_ATTRIBUTES Obja;
  97. PVOID FreeBuffer = NULL;
  98. HANDLE FileHandle, SectionHandle=NULL;
  99. IO_STATUS_BLOCK IoStatusBlock;
  100. LONG fBinaryType = SCS_THIS_PLATFORM_BINARY;
  101. BOOLEAN bReturn = FALSE;
  102. SECTION_IMAGE_INFORMATION ImageInformation;
  103. try {
  104. //
  105. // Translate to an NT name.
  106. //
  107. TranslationStatus = RtlDosPathNameToRelativeNtPathName_U(
  108. // DynamicCommandLine.Buffer ? DynamicCommandLine.Buffer : CommandLine->Buffer,
  109. lpApplicationName,
  110. &PathName,
  111. NULL,
  112. &RelativeName
  113. );
  114. if ( !TranslationStatus ) {
  115. BaseSetLastNTError(STATUS_OBJECT_NAME_INVALID);
  116. goto GBTtryexit;
  117. }
  118. FreeBuffer = PathName.Buffer;
  119. if ( RelativeName.RelativeName.Length ) {
  120. PathName = RelativeName.RelativeName;
  121. }
  122. else {
  123. RelativeName.ContainingDirectory = NULL;
  124. }
  125. InitializeObjectAttributes(
  126. &Obja,
  127. &PathName,
  128. OBJ_CASE_INSENSITIVE,
  129. RelativeName.ContainingDirectory,
  130. NULL
  131. );
  132. //
  133. // Open the file for execute access
  134. //
  135. Status = NtOpenFile(
  136. &FileHandle,
  137. SYNCHRONIZE | FILE_EXECUTE,
  138. &Obja,
  139. &IoStatusBlock,
  140. FILE_SHARE_READ | FILE_SHARE_DELETE,
  141. FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE
  142. );
  143. RtlReleaseRelativeName(&RelativeName);
  144. if (!NT_SUCCESS(Status) ) {
  145. BaseSetLastNTError(Status);
  146. goto GBTtryexit;
  147. }
  148. //
  149. // Create a section object backed by the file
  150. //
  151. Status = NtCreateSection(
  152. &SectionHandle,
  153. SECTION_ALL_ACCESS,
  154. NULL,
  155. NULL,
  156. PAGE_EXECUTE,
  157. SEC_IMAGE,
  158. FileHandle
  159. );
  160. NtClose(FileHandle);
  161. if (!NT_SUCCESS(Status) ) {
  162. SectionHandle = NULL;
  163. switch (Status) {
  164. case STATUS_INVALID_IMAGE_NE_FORMAT:
  165. #if defined(i386) && defined(OS2_SUPPORT_ENABLED)
  166. fBinaryType = SCS_OS216_BINARY;
  167. break;
  168. #endif
  169. case STATUS_INVALID_IMAGE_PROTECT:
  170. fBinaryType = SCS_DOS_BINARY;
  171. break;
  172. case STATUS_INVALID_IMAGE_WIN_16:
  173. fBinaryType = SCS_WOW_BINARY;
  174. break;
  175. case STATUS_INVALID_IMAGE_NOT_MZ:
  176. fBinaryType = BaseIsDosApplication(&PathName, Status);
  177. if (!fBinaryType){
  178. BaseSetLastNTError(Status);
  179. goto GBTtryexit;
  180. }
  181. fBinaryType = (fBinaryType == BINARY_TYPE_DOS_PIF) ?
  182. SCS_PIF_BINARY : SCS_DOS_BINARY;
  183. break;
  184. case STATUS_INVALID_IMAGE_WIN_32:
  185. fBinaryType = SCS_32BIT_BINARY;
  186. break;
  187. case STATUS_INVALID_IMAGE_WIN_64:
  188. fBinaryType = SCS_64BIT_BINARY;
  189. break;
  190. default:
  191. BaseSetLastNTError(Status);
  192. goto GBTtryexit;
  193. }
  194. }
  195. else {
  196. //
  197. // Query the section
  198. //
  199. Status = NtQuerySection(
  200. SectionHandle,
  201. SectionImageInformation,
  202. &ImageInformation,
  203. sizeof( ImageInformation ),
  204. NULL
  205. );
  206. if (!NT_SUCCESS( Status )) {
  207. BaseSetLastNTError(Status);
  208. goto GBTtryexit;
  209. }
  210. if (ImageInformation.ImageCharacteristics & IMAGE_FILE_DLL) {
  211. SetLastError(ERROR_BAD_EXE_FORMAT);
  212. goto GBTtryexit;
  213. }
  214. if (ImageInformation.Machine !=
  215. RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress)->FileHeader.Machine) {
  216. #ifdef MIPS
  217. if ( ImageInformation.Machine == IMAGE_FILE_MACHINE_R3000 ||
  218. ImageInformation.Machine == IMAGE_FILE_MACHINE_R4000 ) {
  219. ;
  220. }
  221. else {
  222. SetLastError(ERROR_BAD_EXE_FORMAT);
  223. goto GBTtryexit;
  224. }
  225. #else
  226. switch ( ImageInformation.Machine ) {
  227. case IMAGE_FILE_MACHINE_I386:
  228. fBinaryType = SCS_32BIT_BINARY;
  229. break;
  230. #if defined(BUILD_WOW6432)
  231. //
  232. // GetBinaryType (64-bit image) from an application running on win64
  233. // will fall to here since the 64-bit kernel allows creation of 32-bit/64-bit
  234. // image sections.
  235. //
  236. case IMAGE_FILE_MACHINE_IA64:
  237. case IMAGE_FILE_MACHINE_AMD64:
  238. fBinaryType = SCS_64BIT_BINARY;
  239. break;
  240. #endif
  241. default:
  242. SetLastError(ERROR_BAD_EXE_FORMAT);
  243. goto GBTtryexit;
  244. }
  245. #endif // MIPS
  246. }
  247. else if ( ImageInformation.SubSystemType != IMAGE_SUBSYSTEM_WINDOWS_GUI &&
  248. ImageInformation.SubSystemType != IMAGE_SUBSYSTEM_WINDOWS_CUI ) {
  249. if ( ImageInformation.SubSystemType == IMAGE_SUBSYSTEM_POSIX_CUI ) {
  250. fBinaryType = SCS_POSIX_BINARY;
  251. }
  252. }
  253. }
  254. *lpBinaryType = fBinaryType;
  255. bReturn = TRUE;
  256. GBTtryexit:;
  257. }
  258. finally {
  259. if (SectionHandle)
  260. NtClose(SectionHandle);
  261. if (FreeBuffer)
  262. RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
  263. }
  264. return bReturn;
  265. }
  266. VOID
  267. APIENTRY
  268. VDMOperationStarted
  269. (
  270. BOOL IsWowCaller
  271. )
  272. /*++
  273. Routine Description:
  274. This routine is used by MVDM to tell base that it has hooked
  275. ctrl-c handler with console. If the cmd window is killed
  276. before VDM could hook ctrl-c, then we wont get a chance to
  277. cleanup our data structures. The absence of this call tells
  278. base that it has to clean up the resources next time a
  279. call is made to create a VDM.
  280. Arguments:
  281. IsWowCaller - TRUE if the caller is WOWVDM
  282. Return Value:
  283. None
  284. --*/
  285. {
  286. BaseUpdateVDMEntry(UPDATE_VDM_HOOKED_CTRLC,
  287. NULL,
  288. 0,
  289. IsWowCaller);
  290. return;
  291. }
  292. BOOL
  293. APIENTRY
  294. GetNextVDMCommand(
  295. PVDMINFO lpVDMInfo
  296. )
  297. /*++
  298. Routine Description:
  299. This routine is used by MVDM to get a new command to execute. The
  300. VDM is blocked untill a DOS/WOW binary is encountered.
  301. Arguments:
  302. lpVDMInfo - pointer to VDMINFO where new DOS command and other
  303. enviornment information is returned.
  304. if lpVDMInfo is NULL, then the caller is
  305. asking whether its the first VDM in the system.
  306. Return Value:
  307. TRUE - The operation was successful. lpVDMInfo is filled in.
  308. FALSE/NULL - The operation failed.
  309. --*/
  310. {
  311. NTSTATUS Status, Status2;
  312. BASE_API_MSG m;
  313. PBASE_GET_NEXT_VDM_COMMAND_MSG a = &m.u.GetNextVDMCommand;
  314. PBASE_EXIT_VDM_MSG c = &m.u.ExitVDM;
  315. PBASE_IS_FIRST_VDM_MSG d = &m.u.IsFirstVDM;
  316. PBASE_SET_REENTER_COUNT_MSG e = &m.u.SetReenterCount;
  317. PCSR_CAPTURE_HEADER CaptureBuffer;
  318. ULONG Len,nPointers;
  319. USHORT VDMStateSave;
  320. if (lpVDMInfo->VDMState &
  321. (ASKING_FOR_WOWPROCLIST | ASKING_FOR_WOWTASKLIST | ASKING_TO_ADD_WOWTASK))
  322. {
  323. RtlZeroMemory(a,sizeof(BASE_GET_NEXT_VDM_COMMAND_MSG));
  324. a->iTask = lpVDMInfo->iTask;
  325. a->EnvLen = lpVDMInfo->EnviornmentSize;
  326. a->Reserved = lpVDMInfo->Reserved;
  327. a->VDMState = lpVDMInfo->VDMState;
  328. CaptureBuffer = NULL;
  329. if (lpVDMInfo->Enviornment) {
  330. Len= (lpVDMInfo->EnviornmentSize) ?
  331. ROUND_UP(lpVDMInfo->EnviornmentSize, 4) : 4;
  332. CaptureBuffer = CsrAllocateCaptureBuffer(1, Len);
  333. if (CaptureBuffer == NULL) {
  334. BaseSetLastNTError( STATUS_NO_MEMORY );
  335. return FALSE;
  336. }
  337. CsrAllocateMessagePointer( CaptureBuffer,
  338. lpVDMInfo->EnviornmentSize,
  339. (PVOID *)&a->Env
  340. );
  341. RtlMoveMemory(a->Env,
  342. lpVDMInfo->Enviornment,
  343. lpVDMInfo->EnviornmentSize);
  344. }
  345. Status = CsrClientCallServer(
  346. (PCSR_API_MSG)&m,
  347. CaptureBuffer,
  348. CSR_MAKE_API_NUMBER( BASESRV_SERVERDLL_INDEX,
  349. BasepGetNextVDMCommand
  350. ),
  351. sizeof( *a )
  352. );
  353. if (NT_SUCCESS(Status)) {
  354. Status = (NTSTATUS)m.ReturnValue;
  355. }
  356. if(!NT_SUCCESS(Status)) {
  357. if(CaptureBuffer) {
  358. CsrFreeCaptureBuffer( CaptureBuffer );
  359. }
  360. BaseSetLastNTError(Status);
  361. return FALSE;
  362. }
  363. //
  364. // Copy back info from the server side
  365. //
  366. try{
  367. if (lpVDMInfo->Enviornment){
  368. RtlMoveMemory(lpVDMInfo->Enviornment,
  369. a->Env,
  370. lpVDMInfo->EnviornmentSize);
  371. }
  372. }
  373. except ( EXCEPTION_EXECUTE_HANDLER ) {
  374. BaseSetLastNTError(GetExceptionCode());
  375. CsrFreeCaptureBuffer( CaptureBuffer );
  376. return FALSE;
  377. }
  378. lpVDMInfo->iTask = a->iTask;
  379. lpVDMInfo->EnviornmentSize = a->EnvLen;
  380. if(CaptureBuffer) {
  381. CsrFreeCaptureBuffer( CaptureBuffer );
  382. }
  383. return TRUE;
  384. }
  385. // Special case to query the first VDM In the system.
  386. if(lpVDMInfo == NULL){
  387. Status = CsrClientCallServer(
  388. (PCSR_API_MSG)&m,
  389. NULL,
  390. CSR_MAKE_API_NUMBER(BASESRV_SERVERDLL_INDEX,
  391. BasepIsFirstVDM
  392. ),
  393. sizeof( *d )
  394. );
  395. if (NT_SUCCESS(Status)) {
  396. return(d->FirstVDM);
  397. }
  398. else {
  399. BaseSetLastNTError(Status);
  400. return FALSE;
  401. }
  402. }
  403. // Special case to increment/decrement the re-enterancy count
  404. if (lpVDMInfo->VDMState == INCREMENT_REENTER_COUNT ||
  405. lpVDMInfo->VDMState == DECREMENT_REENTER_COUNT) {
  406. e->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
  407. e->fIncDec = lpVDMInfo->VDMState;
  408. Status = CsrClientCallServer(
  409. (PCSR_API_MSG)&m,
  410. NULL,
  411. CSR_MAKE_API_NUMBER( BASESRV_SERVERDLL_INDEX,
  412. BasepSetReenterCount
  413. ),
  414. sizeof( *e )
  415. );
  416. if (NT_SUCCESS(Status)) {
  417. return TRUE;
  418. }
  419. else {
  420. BaseSetLastNTError(Status);
  421. return FALSE;
  422. }
  423. }
  424. VDMStateSave = lpVDMInfo->VDMState;
  425. // console handle is always passed on in this case
  426. // wow is differentiated by a parameter a->VDMState
  427. // a->VDMState & ASKING_FOR_WOW_BINARY indicates wow
  428. a->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
  429. if (lpVDMInfo->VDMState & ASKING_FOR_PIF) {
  430. a->iTask = lpVDMInfo->iTask;
  431. }
  432. else {
  433. a->iTask = 0;
  434. }
  435. a->AppLen = lpVDMInfo->AppLen;
  436. a->PifLen = lpVDMInfo->PifLen;
  437. a->CmdLen = lpVDMInfo->CmdSize;
  438. a->EnvLen = lpVDMInfo->EnviornmentSize;
  439. a->ExitCode = lpVDMInfo->ErrorCode;
  440. a->VDMState = VDMStateSave;
  441. a->WaitObjectForVDM = 0;
  442. a->DesktopLen = lpVDMInfo->DesktopLen;
  443. a->TitleLen = lpVDMInfo->TitleLen;
  444. a->ReservedLen = lpVDMInfo->ReservedLen;
  445. a->CurDirectoryLen = lpVDMInfo->CurDirectoryLen;
  446. // Find the total space for capture buffer
  447. // startup info
  448. Len = ROUND_UP(sizeof(STARTUPINFOA),4);
  449. nPointers = 1;
  450. if (lpVDMInfo->CmdSize) {
  451. Len += ROUND_UP(a->CmdLen,4);
  452. nPointers++;
  453. }
  454. if (lpVDMInfo->AppLen) {
  455. Len +=ROUND_UP(a->AppLen,4);
  456. nPointers++;
  457. }
  458. if (lpVDMInfo->PifLen) {
  459. Len +=ROUND_UP(a->PifLen,4);
  460. nPointers++;
  461. }
  462. if (lpVDMInfo->Enviornment) {
  463. nPointers++;
  464. Len+= (lpVDMInfo->EnviornmentSize) ?
  465. ROUND_UP(lpVDMInfo->EnviornmentSize, 4) : 4;
  466. }
  467. if (lpVDMInfo->CurDirectoryLen == 0)
  468. a->CurDirectory = NULL;
  469. else{
  470. Len += ROUND_UP(lpVDMInfo->CurDirectoryLen,4);
  471. nPointers++;
  472. }
  473. if (lpVDMInfo->DesktopLen == 0)
  474. a->Desktop = NULL;
  475. else {
  476. Len += ROUND_UP(lpVDMInfo->DesktopLen,4);
  477. nPointers++;
  478. }
  479. if (lpVDMInfo->TitleLen == 0)
  480. a->Title = NULL;
  481. else {
  482. Len += ROUND_UP(lpVDMInfo->TitleLen,4);
  483. nPointers++;
  484. }
  485. if (lpVDMInfo->ReservedLen == 0)
  486. a->Reserved = NULL;
  487. else {
  488. Len += ROUND_UP(lpVDMInfo->ReservedLen,4);
  489. nPointers++;
  490. }
  491. CaptureBuffer = CsrAllocateCaptureBuffer(nPointers, Len);
  492. if (CaptureBuffer == NULL) {
  493. BaseSetLastNTError( STATUS_NO_MEMORY );
  494. return FALSE;
  495. }
  496. if (lpVDMInfo->CmdLine) {
  497. CsrAllocateMessagePointer( CaptureBuffer,
  498. lpVDMInfo->CmdSize,
  499. (PVOID *)&a->CmdLine
  500. );
  501. }
  502. else {
  503. a->CmdLine = NULL;
  504. }
  505. if (lpVDMInfo->AppLen) {
  506. CsrAllocateMessagePointer( CaptureBuffer,
  507. lpVDMInfo->AppLen,
  508. (PVOID *)&a->AppName
  509. );
  510. }
  511. else {
  512. a->AppName = NULL;
  513. }
  514. if (lpVDMInfo->PifLen) {
  515. CsrAllocateMessagePointer( CaptureBuffer,
  516. lpVDMInfo->PifLen,
  517. (PVOID *)&a->PifFile
  518. );
  519. }
  520. else {
  521. a->PifFile = NULL;
  522. }
  523. if (lpVDMInfo->EnviornmentSize) {
  524. CsrAllocateMessagePointer( CaptureBuffer,
  525. lpVDMInfo->EnviornmentSize,
  526. (PVOID *)&a->Env
  527. );
  528. }
  529. else {
  530. a->Env = NULL;
  531. }
  532. if (lpVDMInfo->CurDirectoryLen)
  533. CsrAllocateMessagePointer( CaptureBuffer,
  534. lpVDMInfo->CurDirectoryLen,
  535. (PVOID *)&a->CurDirectory
  536. );
  537. else
  538. a->CurDirectory = NULL;
  539. CsrAllocateMessagePointer( CaptureBuffer,
  540. sizeof(STARTUPINFOA),
  541. (PVOID *)&a->StartupInfo
  542. );
  543. if (lpVDMInfo->DesktopLen)
  544. CsrAllocateMessagePointer( CaptureBuffer,
  545. lpVDMInfo->DesktopLen,
  546. (PVOID *)&a->Desktop
  547. );
  548. else
  549. a->Desktop = NULL;
  550. if (lpVDMInfo->TitleLen)
  551. CsrAllocateMessagePointer( CaptureBuffer,
  552. lpVDMInfo->TitleLen,
  553. (PVOID *)&a->Title
  554. );
  555. else
  556. a->Title = NULL;
  557. if (lpVDMInfo->ReservedLen)
  558. CsrAllocateMessagePointer( CaptureBuffer,
  559. lpVDMInfo->ReservedLen,
  560. (PVOID *)&a->Reserved
  561. );
  562. else
  563. a->Reserved = NULL;
  564. retry:
  565. Status = CsrClientCallServer(
  566. (PCSR_API_MSG)&m,
  567. CaptureBuffer,
  568. CSR_MAKE_API_NUMBER( BASESRV_SERVERDLL_INDEX,
  569. BasepGetNextVDMCommand
  570. ),
  571. sizeof( *a )
  572. );
  573. if (a->WaitObjectForVDM) {
  574. Status2 = NtWaitForSingleObject(a->WaitObjectForVDM,FALSE,NULL);
  575. if (Status2 != STATUS_SUCCESS){
  576. CsrFreeCaptureBuffer(CaptureBuffer);
  577. BaseSetLastNTError(Status2);
  578. return FALSE;
  579. }
  580. else {
  581. a->VDMState |= ASKING_FOR_SECOND_TIME;
  582. a->ExitCode = 0;
  583. goto retry;
  584. }
  585. }
  586. if (NT_SUCCESS(Status)) {
  587. Status = (NTSTATUS)m.ReturnValue;
  588. }
  589. if (!NT_SUCCESS( Status )) {
  590. if (Status == STATUS_INVALID_PARAMETER) {
  591. //This means one of the buffer size is less than required.
  592. lpVDMInfo->CmdSize = a->CmdLen;
  593. lpVDMInfo->AppLen = a->AppLen;
  594. lpVDMInfo->PifLen = a->PifLen;
  595. lpVDMInfo->EnviornmentSize = a->EnvLen;
  596. lpVDMInfo->CurDirectoryLen = a->CurDirectoryLen;
  597. lpVDMInfo->DesktopLen = a->DesktopLen;
  598. lpVDMInfo->TitleLen = a->TitleLen;
  599. lpVDMInfo->ReservedLen = a->ReservedLen;
  600. }
  601. else {
  602. lpVDMInfo->CmdSize = 0;
  603. lpVDMInfo->AppLen = 0;
  604. lpVDMInfo->PifLen = 0;
  605. lpVDMInfo->EnviornmentSize = 0;
  606. lpVDMInfo->CurDirectoryLen = 0;
  607. lpVDMInfo->DesktopLen = 0;
  608. lpVDMInfo->TitleLen = 0;
  609. lpVDMInfo->ReservedLen = 0;
  610. }
  611. CsrFreeCaptureBuffer( CaptureBuffer );
  612. BaseSetLastNTError(Status);
  613. return FALSE;
  614. }
  615. try {
  616. if (lpVDMInfo->CmdSize)
  617. RtlMoveMemory(lpVDMInfo->CmdLine,
  618. a->CmdLine,
  619. a->CmdLen);
  620. if (lpVDMInfo->AppLen)
  621. RtlMoveMemory(lpVDMInfo->AppName,
  622. a->AppName,
  623. a->AppLen);
  624. if (lpVDMInfo->PifLen)
  625. RtlMoveMemory(lpVDMInfo->PifFile,
  626. a->PifFile,
  627. a->PifLen);
  628. if (lpVDMInfo->Enviornment)
  629. RtlMoveMemory(lpVDMInfo->Enviornment,
  630. a->Env,
  631. a->EnvLen);
  632. if (lpVDMInfo->CurDirectoryLen)
  633. RtlMoveMemory(lpVDMInfo->CurDirectory,
  634. a->CurDirectory,
  635. a->CurDirectoryLen);
  636. if (a->VDMState & STARTUP_INFO_RETURNED)
  637. RtlMoveMemory(&lpVDMInfo->StartupInfo,
  638. a->StartupInfo,
  639. sizeof(STARTUPINFOA));
  640. if (lpVDMInfo->DesktopLen){
  641. RtlMoveMemory(lpVDMInfo->Desktop,
  642. a->Desktop,
  643. a->DesktopLen);
  644. lpVDMInfo->StartupInfo.lpDesktop = lpVDMInfo->Desktop;
  645. }
  646. if (lpVDMInfo->TitleLen){
  647. RtlMoveMemory(lpVDMInfo->Title,
  648. a->Title,
  649. a->TitleLen);
  650. lpVDMInfo->StartupInfo.lpTitle = lpVDMInfo->Title;
  651. }
  652. if (lpVDMInfo->ReservedLen){
  653. RtlMoveMemory(lpVDMInfo->Reserved,
  654. a->Reserved,
  655. a->ReservedLen);
  656. lpVDMInfo->StartupInfo.lpReserved = lpVDMInfo->Reserved;
  657. }
  658. lpVDMInfo->CmdSize = a->CmdLen;
  659. lpVDMInfo->AppLen = a->AppLen;
  660. lpVDMInfo->PifLen = a->PifLen;
  661. lpVDMInfo->EnviornmentSize = a->EnvLen;
  662. if (a->VDMState & STARTUP_INFO_RETURNED)
  663. lpVDMInfo->VDMState = STARTUP_INFO_RETURNED;
  664. else
  665. lpVDMInfo->VDMState = 0;
  666. lpVDMInfo->CurDrive = a->CurrentDrive;
  667. lpVDMInfo->StdIn = a->StdIn;
  668. lpVDMInfo->StdOut = a->StdOut;
  669. lpVDMInfo->StdErr = a->StdErr;
  670. lpVDMInfo->iTask = a->iTask;
  671. lpVDMInfo->CodePage = a->CodePage;
  672. lpVDMInfo->CurDirectoryLen = a->CurDirectoryLen;
  673. lpVDMInfo->DesktopLen = a->DesktopLen;
  674. lpVDMInfo->TitleLen = a->TitleLen;
  675. lpVDMInfo->ReservedLen = a->ReservedLen;
  676. lpVDMInfo->dwCreationFlags = a->dwCreationFlags;
  677. lpVDMInfo->fComingFromBat = a->fComingFromBat;
  678. CsrFreeCaptureBuffer( CaptureBuffer );
  679. return TRUE;
  680. }
  681. except ( EXCEPTION_EXECUTE_HANDLER ) {
  682. BaseSetLastNTError(GetExceptionCode());
  683. CsrFreeCaptureBuffer( CaptureBuffer );
  684. return FALSE;
  685. }
  686. }
  687. VOID
  688. APIENTRY
  689. ExitVDM(
  690. BOOL IsWowCaller,
  691. ULONG iWowTask
  692. )
  693. /*++
  694. Routine Description:
  695. This routine is used by MVDM to exit.
  696. Arguments:
  697. IsWowCaller - TRUE if the caller is WOWVDM.
  698. FALSE if the caller is DOSVDM
  699. This parameter is obsolete as basesrv knows about the kind
  700. of vdm that is calling us
  701. iWowTask - if IsWowCaller == FALSE then Dont Care
  702. - if IsWowCaller == TRUE && iWowTask != -1 kill iWowTask task
  703. - if IsWowCaller == TRUE && iWowTask == -1 kill all wow task
  704. Return Value:
  705. None
  706. --*/
  707. {
  708. NTSTATUS Status;
  709. BASE_API_MSG m;
  710. PBASE_EXIT_VDM_MSG c = &m.u.ExitVDM;
  711. c->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
  712. if (IsWowCaller) {
  713. c->iWowTask = iWowTask;
  714. }
  715. else {
  716. c->iWowTask = 0;
  717. }
  718. // this parameter means
  719. c->WaitObjectForVDM =0;
  720. Status = CsrClientCallServer(
  721. (PCSR_API_MSG)&m,
  722. NULL,
  723. CSR_MAKE_API_NUMBER( BASESRV_SERVERDLL_INDEX,
  724. BasepExitVDM
  725. ),
  726. sizeof( *c )
  727. );
  728. if (NT_SUCCESS(Status) && c->WaitObjectForVDM) {
  729. NtClose (c->WaitObjectForVDM);
  730. }
  731. return;
  732. }
  733. /*++
  734. Routine Description:
  735. Set new VDM current directories
  736. Arguments:
  737. cchCurDir - length of buffer in bytes
  738. lpszCurDir - buffer to return the current director of NTVDM
  739. Return Value:
  740. TRUE if function succeed
  741. FALSE if function failed, GetLastError() has the error code
  742. --*/
  743. BOOL
  744. APIENTRY
  745. SetVDMCurrentDirectories(
  746. IN ULONG cchCurDirs,
  747. IN LPSTR lpszzCurDirs
  748. )
  749. {
  750. NTSTATUS Status;
  751. PCSR_CAPTURE_HEADER CaptureBuffer;
  752. BASE_API_MSG m;
  753. PBASE_GET_SET_VDM_CUR_DIRS_MSG a = &m.u.GetSetVDMCurDirs;
  754. a->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
  755. // caller must have a valid console(WOW will fail)
  756. if (a->ConsoleHandle == (HANDLE) -1) {
  757. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  758. return FALSE;
  759. }
  760. if (cchCurDirs && lpszzCurDirs) {
  761. // get capture buffer, one pointer in the message
  762. CaptureBuffer = CsrAllocateCaptureBuffer(1, cchCurDirs);
  763. if (CaptureBuffer == NULL) {
  764. BaseSetLastNTError( STATUS_NO_MEMORY );
  765. return FALSE;
  766. }
  767. CsrAllocateMessagePointer( CaptureBuffer,
  768. cchCurDirs,
  769. (PVOID *)&a->lpszzCurDirs
  770. );
  771. a->cchCurDirs = cchCurDirs;
  772. try {
  773. RtlMoveMemory(a->lpszzCurDirs, lpszzCurDirs, cchCurDirs);
  774. }
  775. except (EXCEPTION_EXECUTE_HANDLER) {
  776. BaseSetLastNTError(GetExceptionCode());
  777. CsrFreeCaptureBuffer(CaptureBuffer);
  778. return FALSE;
  779. }
  780. Status = CsrClientCallServer(
  781. (PCSR_API_MSG)&m,
  782. CaptureBuffer,
  783. CSR_MAKE_API_NUMBER(BASESRV_SERVERDLL_INDEX,
  784. BasepSetVDMCurDirs
  785. ),
  786. sizeof( *a )
  787. );
  788. CsrFreeCaptureBuffer(CaptureBuffer);
  789. if (!NT_SUCCESS(Status) || !NT_SUCCESS((NTSTATUS)m.ReturnValue)) {
  790. BaseSetLastNTError(Status);
  791. return FALSE;
  792. }
  793. }
  794. return TRUE;
  795. }
  796. /*++
  797. Routine Description:
  798. To return current directory of NTVDM.
  799. This allows the parent process(CMD.EXE in most cases) to keep track the
  800. current directory after each VDM execution.
  801. NOTE: this function doesn't apply to wow
  802. Arguments:
  803. cchCurDir - length of buffer in bytes
  804. lpszCurDir - buffer to return the current director of NTVDM
  805. Note: We don't require the process id to the running VDM because
  806. current directories are global to every VDMs under a single NTVDM
  807. control -- each console handle has its own current directories
  808. Return Value:
  809. ULONG - (1). number of bytes written to the given buffer if succeed
  810. (2). lentgh of the current directory including NULL
  811. if the provided buffer is not large enough
  812. (3). 0 then GetLastError() has the error code
  813. --*/
  814. ULONG
  815. APIENTRY
  816. GetVDMCurrentDirectories(
  817. IN ULONG cchCurDirs,
  818. IN LPSTR lpszzCurDirs
  819. )
  820. {
  821. NTSTATUS Status;
  822. PCSR_CAPTURE_HEADER CaptureBuffer;
  823. BASE_API_MSG m;
  824. PBASE_GET_SET_VDM_CUR_DIRS_MSG a = &m.u.GetSetVDMCurDirs;
  825. a->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
  826. if (a->ConsoleHandle == (HANDLE) -1) {
  827. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  828. return 0L;
  829. }
  830. if (cchCurDirs && lpszzCurDirs) {
  831. CaptureBuffer = CsrAllocateCaptureBuffer(1, cchCurDirs);
  832. if (CaptureBuffer == NULL) {
  833. BaseSetLastNTError( STATUS_NO_MEMORY );
  834. return FALSE;
  835. }
  836. CsrAllocateMessagePointer( CaptureBuffer,
  837. cchCurDirs,
  838. (PVOID *)&a->lpszzCurDirs
  839. );
  840. a->cchCurDirs = cchCurDirs;
  841. }
  842. else {
  843. a->cchCurDirs = 0;
  844. a->lpszzCurDirs = NULL;
  845. CaptureBuffer = NULL;
  846. }
  847. m.ReturnValue = 0xffffffff;
  848. Status = CsrClientCallServer(
  849. (PCSR_API_MSG)&m,
  850. CaptureBuffer,
  851. CSR_MAKE_API_NUMBER(BASESRV_SERVERDLL_INDEX,
  852. BasepGetVDMCurDirs
  853. ),
  854. sizeof( *a )
  855. );
  856. if (m.ReturnValue == 0xffffffff) {
  857. a->cchCurDirs = 0;
  858. }
  859. if (NT_SUCCESS(Status)) {
  860. Status = m.ReturnValue;
  861. }
  862. if (NT_SUCCESS(Status)) {
  863. try {
  864. RtlMoveMemory(lpszzCurDirs, a->lpszzCurDirs, a->cchCurDirs);
  865. }
  866. except(EXCEPTION_EXECUTE_HANDLER) {
  867. Status = GetExceptionCode();
  868. a->cchCurDirs = 0;
  869. }
  870. }
  871. else {
  872. BaseSetLastNTError(Status);
  873. }
  874. if (CaptureBuffer) {
  875. CsrFreeCaptureBuffer(CaptureBuffer);
  876. }
  877. return a->cchCurDirs;
  878. }
  879. VOID
  880. APIENTRY
  881. CmdBatNotification(
  882. IN ULONG fBeginEnd
  883. )
  884. /*++
  885. Routine Description:
  886. This API lets base know about .bat processing from cmd. This is
  887. required by VDM, so that it can decided correctly when to put
  888. command.com prompt on TSRs. If the command came from .bat file
  889. then VDM should'nt put its prompt. This is important for
  890. ventura publisher and civilization apps.
  891. Arguments:
  892. fBeginEnd - CMD_BAT_OPERATION_STARTING -> .BAT processing is starting
  893. CMD_BAT_OPERATION_TERMINATING -> .BAT processing is ending
  894. Return Value:
  895. None
  896. --*/
  897. {
  898. #if defined(BUILD_WOW6432)
  899. // 32-bit cmd.exe calls this in WOW64, but there is no VDM support, so
  900. // no need for a WOW64 thunk for it.
  901. UNREFERENCED_PARAMETER(fBeginEnd);
  902. #else
  903. BASE_API_MSG m;
  904. PBASE_BAT_NOTIFICATION_MSG a = &m.u.BatNotification;
  905. a->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
  906. if (a->ConsoleHandle == (HANDLE) -1)
  907. return;
  908. a->fBeginEnd = fBeginEnd;
  909. CsrClientCallServer((PCSR_API_MSG)&m,
  910. NULL,
  911. CSR_MAKE_API_NUMBER(BASESRV_SERVERDLL_INDEX,
  912. BasepBatNotification
  913. ),
  914. sizeof( *a )
  915. );
  916. #endif
  917. return;
  918. }
  919. NTSTATUS
  920. APIENTRY
  921. RegisterWowExec(
  922. IN HANDLE hwndWowExec
  923. )
  924. /*++
  925. Routine Description:
  926. This API gives basesrv the window handle for the shared WowExec so
  927. it can send WM_WOWEXECSTARTAPP messages to WowExec. This
  928. saves having a thread in WOW dedicated to GetNextVDMCommand.
  929. Arguments:
  930. hwndWowExec - Win32 window handle for WowExec in shared WOW VDM.
  931. Separate WOW VDMs don't register their WowExec handle
  932. because they never get commands from base.
  933. NULL is passed to de-register any given wowexec
  934. Return Value:
  935. If hwndWowExec != NULL then returns success if wow had been registered successfully
  936. if hwndWowExec == NULL then returns success if no tasks are pending to be executed
  937. --*/
  938. {
  939. BASE_API_MSG m;
  940. PBASE_REGISTER_WOWEXEC_MSG a = &m.u.RegisterWowExec;
  941. NTSTATUS Status;
  942. a->hwndWowExec = hwndWowExec;
  943. a->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
  944. Status = CsrClientCallServer((PCSR_API_MSG)&m,
  945. NULL,
  946. CSR_MAKE_API_NUMBER(BASESRV_SERVERDLL_INDEX,
  947. BasepRegisterWowExec
  948. ),
  949. sizeof( *a )
  950. );
  951. return Status;
  952. }
  953. /*++
  954. Routine Description:
  955. This routine is used to close standard IO handles before returning to the
  956. caller
  957. Arguments:
  958. pVDMInfo - VDM Info record containing stdio handles
  959. Return Value:
  960. None
  961. --*/
  962. VOID
  963. BaseCloseStandardHandle(
  964. IN PVDMINFO pVDMInfo
  965. )
  966. {
  967. if (pVDMInfo->StdIn)
  968. NtClose (pVDMInfo->StdIn);
  969. if (pVDMInfo->StdOut)
  970. NtClose (pVDMInfo->StdOut);
  971. if (pVDMInfo->StdErr)
  972. NtClose (pVDMInfo->StdErr);
  973. pVDMInfo->StdIn = 0;
  974. pVDMInfo->StdOut = 0;
  975. pVDMInfo->StdErr = 0;
  976. }
  977. NTSTATUS BaseGetVdmLuid(
  978. HANDLE Token,
  979. PLUID pluidCaller
  980. )
  981. {
  982. PTOKEN_STATISTICS pStats;
  983. ULONG BytesRequired;
  984. NTSTATUS Status;
  985. /*
  986. * Get the session id of the caller.
  987. */
  988. Status = NtQueryInformationToken(
  989. Token, // Handle
  990. TokenStatistics, // TokenInformationClass
  991. NULL, // TokenInformation
  992. 0, // TokenInformationLength
  993. &BytesRequired // ReturnLength
  994. );
  995. if (Status != STATUS_BUFFER_TOO_SMALL) {
  996. return Status;
  997. }
  998. //
  999. // Allocate space for the user info
  1000. //
  1001. pStats = (PTOKEN_STATISTICS)RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( VDM_TAG ), BytesRequired);
  1002. if (pStats == NULL) {
  1003. return Status;
  1004. }
  1005. //
  1006. // Read in the user info
  1007. //
  1008. Status = NtQueryInformationToken(
  1009. Token, // Handle
  1010. TokenStatistics, // TokenInformationClass
  1011. pStats, // TokenInformation
  1012. BytesRequired, // TokenInformationLength
  1013. &BytesRequired // ReturnLength
  1014. );
  1015. if (NT_SUCCESS(Status)) {
  1016. if (pluidCaller != NULL)
  1017. *pluidCaller = pStats->AuthenticationId;
  1018. }
  1019. RtlFreeHeap(RtlProcessHeap(), 0, pStats);
  1020. return Status;
  1021. }
  1022. NTSTATUS
  1023. BaseCheckVDMp(
  1024. IN ULONG BinaryType,
  1025. IN PCWCH lpApplicationName,
  1026. IN PCWCH lpCommandLine,
  1027. IN PCWCH lpCurrentDirectory,
  1028. IN ANSI_STRING *pAnsiStringEnv,
  1029. IN PBASE_API_MSG m,
  1030. IN OUT PULONG iTask,
  1031. IN DWORD dwCreationFlags,
  1032. LPSTARTUPINFOW lpStartupInfo,
  1033. IN HANDLE hUserToken
  1034. )
  1035. /*++
  1036. Routine Description:
  1037. This routine calls the windows server to find out if the VDM for the
  1038. current session is already present. If so, a new process is'nt created
  1039. instead the DOS binary is dispatched to the existing VDM. Otherwise,
  1040. a new VDM process is created. This routine also passes the app name
  1041. and command line to the server in DOS int21/0ah style which is later
  1042. passed by the server to the VDM.
  1043. Arguments:
  1044. BinaryType - DOS/WOW binary
  1045. lpApplicationName -- pointer to the full path name of the executable.
  1046. lpCommandLine -- command line
  1047. lpCurrentDirectory - Current directory
  1048. lpEnvironment, - Envirinment strings
  1049. m - pointer to the base api message.
  1050. iTask - taskid for win16 apps, and no-console dos apps
  1051. dwCreationFlags - creation flags as passed to createprocess
  1052. lpStartupInfo =- pointer to startupinfo as passed to createprocess
  1053. Return Value:
  1054. OEM vs. ANSI:
  1055. The command line, Application Name, title are converted to OEM strings,
  1056. suitable for the VDM. All other strings are returned as ANSI.
  1057. returns nt status code of the last operation
  1058. STATUS_ACCESS_DENIED -- Operation failed (desktop access denied)
  1059. STATUS_SUCCESS -- Operation sucseeded
  1060. --*/
  1061. {
  1062. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  1063. PPEB Peb;
  1064. PBASE_CHECKVDM_MSG b= (PBASE_CHECKVDM_MSG)&m->u.CheckVDM;
  1065. PCSR_CAPTURE_HEADER CaptureBuffer;
  1066. ANSI_STRING AnsiStringCurrentDir,AnsiStringDesktop;
  1067. ANSI_STRING AnsiStringReserved, AnsiStringPif;
  1068. OEM_STRING OemStringCmd, OemStringAppName, OemStringTitle;
  1069. UNICODE_STRING UnicodeString;
  1070. PCHAR pch, Buffer = NULL;
  1071. ULONG Len;
  1072. ULONG bufPointers;
  1073. LPWSTR wsBuffer;
  1074. LPWSTR wsAppName;
  1075. LPWSTR wsPifName;
  1076. LPWSTR wsCmdLine;
  1077. LPWSTR wsPif=L".pif";
  1078. LPWSTR wsSharedWowPif=L"wowexec.pif";
  1079. PWCHAR pwch;
  1080. BOOLEAN bNewConsole;
  1081. DWORD dw, dwTotal, Length;
  1082. WCHAR wchBuffer[MAX_PATH + 1];
  1083. ULONG BinarySubType;
  1084. LPWSTR lpAllocatedReserved = NULL;
  1085. DWORD HandleFlags;
  1086. LUID VdmUserLuid;
  1087. // does a trivial test of the environment
  1088. if (!ARGUMENT_PRESENT(pAnsiStringEnv) ||
  1089. pAnsiStringEnv->Length > MAXIMUM_VDM_ENVIORNMENT) {
  1090. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  1091. return STATUS_INVALID_PARAMETER;
  1092. }
  1093. wsCmdLine = wsAppName = NULL;
  1094. OemStringCmd.Buffer = NULL;
  1095. OemStringAppName.Buffer = NULL;
  1096. AnsiStringCurrentDir.Buffer = NULL;
  1097. AnsiStringDesktop.Buffer = NULL;
  1098. AnsiStringPif.Buffer = NULL;
  1099. OemStringTitle.Buffer = NULL;
  1100. AnsiStringReserved.Buffer = NULL;
  1101. wsBuffer = NULL;
  1102. wsPifName = NULL;
  1103. BinarySubType = BinaryType & BINARY_SUBTYPE_MASK;
  1104. BinaryType = BinaryType & ~BINARY_SUBTYPE_MASK;
  1105. bNewConsole = !NtCurrentPeb()->ProcessParameters->ConsoleHandle ||
  1106. (dwCreationFlags & CREATE_NEW_CONSOLE);
  1107. try {
  1108. if (BinaryType == BINARY_TYPE_DOS) {
  1109. Peb = NtCurrentPeb();
  1110. if (lpStartupInfo && lpStartupInfo->dwFlags & STARTF_USESTDHANDLES) {
  1111. b->StdIn = lpStartupInfo->hStdInput;
  1112. b->StdOut = lpStartupInfo->hStdOutput;
  1113. b->StdErr = lpStartupInfo->hStdError;
  1114. }
  1115. else {
  1116. b->StdIn = Peb->ProcessParameters->StandardInput;
  1117. b->StdOut = Peb->ProcessParameters->StandardOutput;
  1118. b->StdErr = Peb->ProcessParameters->StandardError;
  1119. //
  1120. // Verify that the standard handles ntvdm process will inherit
  1121. // from the calling process are real handles. They are not
  1122. // handles if the calling process was created with
  1123. // STARTF_USEHOTKEY | STARTF_HASSHELLDATA.
  1124. // Note that CreateProcess clears STARTF_USESTANDHANDLES
  1125. // if either STARTF_USEHOTKEY or STARTF_HASSHELLDATA is set.
  1126. //
  1127. if (Peb->ProcessParameters->WindowFlags &
  1128. (STARTF_USEHOTKEY | STARTF_HASSHELLDATA)) {
  1129. if (b->StdIn && !CONSOLE_HANDLE(b->StdIn) &&
  1130. !GetHandleInformation(b->StdIn, &HandleFlags))
  1131. b->StdIn = 0;
  1132. if (b->StdOut && !CONSOLE_HANDLE(b->StdOut) &&
  1133. !GetHandleInformation(b->StdOut, &HandleFlags)) {
  1134. if (b->StdErr == b->StdOut)
  1135. b->StdErr = 0;
  1136. b->StdOut = 0;
  1137. }
  1138. if (b->StdErr && b->StdErr != b->StdOut &&
  1139. !CONSOLE_HANDLE(b->StdErr) &&
  1140. !GetHandleInformation(b->StdErr, &HandleFlags))
  1141. b->StdErr = 0;
  1142. }
  1143. }
  1144. if (CONSOLE_HANDLE((b->StdIn)))
  1145. b->StdIn = 0;
  1146. if (CONSOLE_HANDLE((b->StdOut)))
  1147. b->StdOut = 0;
  1148. if (CONSOLE_HANDLE((b->StdErr)))
  1149. b->StdErr = 0;
  1150. }
  1151. if (BinaryType == BINARY_TYPE_SEPWOW) {
  1152. bNewConsole = TRUE;
  1153. }
  1154. //
  1155. // Convert Unicode Application Name to Oem short name
  1156. //
  1157. // skiping leading white space
  1158. while(*lpApplicationName == (WCHAR)' ' || *lpApplicationName == (WCHAR)'\t' ) {
  1159. lpApplicationName++;
  1160. }
  1161. // space for short AppName
  1162. Len = wcslen(lpApplicationName);
  1163. dwTotal = Len + 1 + MAX_PATH;
  1164. wsAppName = RtlAllocateHeap(RtlProcessHeap(),
  1165. MAKE_TAG(VDM_TAG),
  1166. dwTotal * sizeof(WCHAR)
  1167. );
  1168. if (wsAppName == NULL) {
  1169. Status = STATUS_NO_MEMORY;
  1170. goto BCVTryExit;
  1171. }
  1172. dw = GetShortPathNameW(lpApplicationName, wsAppName, dwTotal);
  1173. // If getting the short name is impossible, stop right here.
  1174. // We can not execute a 16bits biranry if we can not find
  1175. // its appropriate short name alias. Sorry HPFS, Sorry NFS
  1176. if (0 == dw || dw > dwTotal) {
  1177. Status = STATUS_OBJECT_PATH_INVALID;
  1178. goto BCVTryExit;
  1179. }
  1180. RtlInitUnicodeString(&UnicodeString, wsAppName);
  1181. Status = RtlUnicodeStringToOemString(&OemStringAppName,
  1182. &UnicodeString,
  1183. TRUE
  1184. );
  1185. if (!NT_SUCCESS(Status) ){
  1186. goto BCVTryExit;
  1187. }
  1188. //
  1189. // Find len of basename excluding extension,
  1190. // for CommandTail max len check.
  1191. //
  1192. dw = OemStringAppName.Length;
  1193. pch = OemStringAppName.Buffer;
  1194. Length = 1; // start at one for space between cmdname & cmdtail
  1195. while (dw-- && *pch != '.') {
  1196. if (*pch == '\\') {
  1197. Length = 1;
  1198. }
  1199. else {
  1200. Length++;
  1201. }
  1202. pch++;
  1203. }
  1204. //
  1205. // Find the beg of the command tail to pass as the CmdLine
  1206. //
  1207. Len = wcslen(lpApplicationName);
  1208. if (L'"' == lpCommandLine[0]) {
  1209. //
  1210. // Application name is quoted, skip the quoted text
  1211. // to get command tail.
  1212. //
  1213. pwch = (LPWSTR)&lpCommandLine[1];
  1214. while (*pwch && L'"' != *pwch++) {
  1215. ;
  1216. }
  1217. } else if (Len <= wcslen(lpCommandLine) &&
  1218. 0 == _wcsnicmp(lpApplicationName, lpCommandLine, Len)) {
  1219. //
  1220. // Application path is also on the command line, skip past
  1221. // that to reach the command tail instead of looking for
  1222. // the first white space.
  1223. //
  1224. pwch = (LPWSTR)lpCommandLine + Len;
  1225. } else {
  1226. //
  1227. // We assume first token is exename (argv[0]).
  1228. //
  1229. pwch = (LPWSTR)lpCommandLine;
  1230. // skip leading white characters
  1231. while (*pwch != UNICODE_NULL &&
  1232. (*pwch == (WCHAR) ' ' || *pwch == (WCHAR) '\t')) {
  1233. pwch++;
  1234. }
  1235. // skip first token
  1236. if (*pwch == (WCHAR) '\"') { // quotes as delimiter
  1237. pwch++;
  1238. while (*pwch && *pwch++ != '\"') {
  1239. ;
  1240. }
  1241. }
  1242. else { // white space as delimiter
  1243. while (*pwch && *pwch != ' ' && *pwch != '\t') {
  1244. pwch++;
  1245. }
  1246. }
  1247. }
  1248. //
  1249. // pwch points past the application name, now skip any trailing
  1250. // whitespace.
  1251. //
  1252. while (*pwch && (L' ' == *pwch || L'\t' == *pwch)) {
  1253. pwch++;
  1254. }
  1255. wsCmdLine = pwch;
  1256. dw = wcslen(wsCmdLine);
  1257. // convert to oem
  1258. UnicodeString.Length = (USHORT)(dw * sizeof(WCHAR));
  1259. UnicodeString.MaximumLength = UnicodeString.Length + sizeof(WCHAR);
  1260. UnicodeString.Buffer = wsCmdLine;
  1261. Status = RtlUnicodeStringToOemString(
  1262. &OemStringCmd,
  1263. &UnicodeString,
  1264. TRUE);
  1265. if (!NT_SUCCESS(Status) ){
  1266. goto BCVTryExit;
  1267. }
  1268. //
  1269. // check len of command line for dos compatibility
  1270. //
  1271. if (OemStringCmd.Length >= MAXIMUM_VDM_COMMAND_LENGTH - Length) {
  1272. Status = STATUS_INVALID_PARAMETER;
  1273. goto BCVTryExit;
  1274. }
  1275. //
  1276. // Search for matching pif file. Search order is AppName dir,
  1277. // followed by win32 default search path. For the shared wow, pif
  1278. // is wowexec.pif if it exists.
  1279. //
  1280. wsBuffer = RtlAllocateHeap(RtlProcessHeap(),MAKE_TAG( VDM_TAG ),MAX_PATH*sizeof(WCHAR));
  1281. if (!wsBuffer) {
  1282. Status = STATUS_NO_MEMORY;
  1283. goto BCVTryExit;
  1284. }
  1285. wsPifName = RtlAllocateHeap(RtlProcessHeap(),MAKE_TAG( VDM_TAG ),MAX_PATH*sizeof(WCHAR));
  1286. if (!wsPifName) {
  1287. Status = STATUS_NO_MEMORY;
  1288. goto BCVTryExit;
  1289. }
  1290. if (BinaryType == BINARY_TYPE_WIN16) {
  1291. wcscpy(wsBuffer, wsSharedWowPif);
  1292. Len = 0;
  1293. }
  1294. else {
  1295. // dos application path should be less than MAX_PATH
  1296. if(Len >= MAX_PATH) {
  1297. Status = STATUS_INVALID_PARAMETER;
  1298. goto BCVTryExit;
  1299. }
  1300. // start with fully qualified app name
  1301. wcscpy(wsBuffer, lpApplicationName);
  1302. // strip extension if any
  1303. pwch = wcsrchr(wsBuffer, (WCHAR)'.');
  1304. // dos application must have an extention
  1305. if (pwch == NULL || wsBuffer - pwch + MAX_PATH < sizeof(wsPif)/sizeof(WCHAR)) {
  1306. Status = STATUS_INVALID_PARAMETER;
  1307. goto BCVTryExit;
  1308. }
  1309. wcscpy(pwch, wsPif);
  1310. Len = GetFileAttributesW(wsBuffer);
  1311. if (Len == (DWORD)(-1) || (Len & FILE_ATTRIBUTE_DIRECTORY)) {
  1312. Len = 0;
  1313. }
  1314. else {
  1315. Len = wcslen(wsBuffer) + 1;
  1316. wcsncpy(wsPifName, wsBuffer, Len);
  1317. }
  1318. }
  1319. if (!Len) { // try basename
  1320. // find beg of basename
  1321. pwch = wcsrchr(wsBuffer, (WCHAR)'\\');
  1322. if (!pwch ) {
  1323. pwch = wcsrchr(wsBuffer, (WCHAR)':');
  1324. }
  1325. // move basename to beg of wsBuffer
  1326. if (pwch++) {
  1327. while (*pwch != UNICODE_NULL &&
  1328. *pwch != (WCHAR)' ' && *pwch != (WCHAR)'\t' )
  1329. {
  1330. wsBuffer[Len++] = *pwch++;
  1331. }
  1332. wsBuffer[Len] = UNICODE_NULL;
  1333. }
  1334. if (Len) {
  1335. Len = SearchPathW(
  1336. NULL,
  1337. wsBuffer,
  1338. wsPif, // L".pif"
  1339. MAX_PATH,
  1340. wsPifName,
  1341. NULL
  1342. );
  1343. if (Len >= MAX_PATH) {
  1344. Status = STATUS_NO_MEMORY;
  1345. goto BCVTryExit;
  1346. }
  1347. }
  1348. }
  1349. if (!Len)
  1350. *wsPifName = UNICODE_NULL;
  1351. if (!ARGUMENT_PRESENT( lpCurrentDirectory )) {
  1352. #pragma prefast(suppress: 209, "RtlGetCurrentDirectory_U takes a byte count")
  1353. dw = RtlGetCurrentDirectory_U(sizeof (wchBuffer), wchBuffer);
  1354. wchBuffer[dw / sizeof(WCHAR)] = UNICODE_NULL;
  1355. dw = GetShortPathNameW(wchBuffer,
  1356. wchBuffer,
  1357. sizeof(wchBuffer) / sizeof(WCHAR)
  1358. );
  1359. if (dw > sizeof(wchBuffer) / sizeof(WCHAR))
  1360. goto BCVTryExit;
  1361. else if (dw == 0) {
  1362. RtlInitUnicodeString(&UnicodeString, wchBuffer);
  1363. dw = UnicodeString.Length / sizeof(WCHAR);
  1364. }
  1365. else {
  1366. UnicodeString.Length = (USHORT)(dw * sizeof(WCHAR));
  1367. UnicodeString.Buffer = wchBuffer;
  1368. UnicodeString.MaximumLength = (USHORT)sizeof(wchBuffer);
  1369. }
  1370. // DOS limit of 64 includes the final NULL but not the leading
  1371. // drive and slash. So here we should be checking the ansi length
  1372. // of current directory + 1 (for NULL) - 3 (for c:\).
  1373. if ( dw - 2 <= MAXIMUM_VDM_CURRENT_DIR ) {
  1374. Status = RtlUnicodeStringToAnsiString(
  1375. &AnsiStringCurrentDir,
  1376. &UnicodeString,
  1377. TRUE
  1378. );
  1379. }
  1380. else {
  1381. Status = STATUS_INVALID_PARAMETER;
  1382. }
  1383. if ( !NT_SUCCESS(Status) ) {
  1384. goto BCVTryExit;
  1385. }
  1386. }
  1387. else {
  1388. // first get a full path name
  1389. dw = GetFullPathNameW(lpCurrentDirectory,
  1390. sizeof(wchBuffer) / sizeof(WCHAR),
  1391. wchBuffer,
  1392. NULL);
  1393. if (0 != dw && dw <= sizeof(wchBuffer) / sizeof(WCHAR)) {
  1394. dw = GetShortPathNameW(wchBuffer,
  1395. wchBuffer,
  1396. sizeof(wchBuffer) / sizeof(WCHAR));
  1397. }
  1398. if (dw > sizeof(wchBuffer) / sizeof(WCHAR))
  1399. goto BCVTryExit;
  1400. if (dw != 0) {
  1401. UnicodeString.Buffer = wchBuffer;
  1402. UnicodeString.Length = (USHORT)(dw * sizeof(WCHAR));
  1403. UnicodeString.MaximumLength = sizeof(wchBuffer);
  1404. }
  1405. else
  1406. RtlInitUnicodeString(&UnicodeString, lpCurrentDirectory);
  1407. Status = RtlUnicodeStringToAnsiString(
  1408. &AnsiStringCurrentDir,
  1409. &UnicodeString,
  1410. TRUE);
  1411. if ( !NT_SUCCESS(Status) ){
  1412. goto BCVTryExit;
  1413. }
  1414. // DOS limit of 64 includes the final NULL but not the leading
  1415. // drive and slash. So here we should be checking the ansi length
  1416. // of current directory + 1 (for NULL) - 3 (for c:\).
  1417. if((AnsiStringCurrentDir.Length - 2) > MAXIMUM_VDM_CURRENT_DIR) {
  1418. Status = STATUS_INVALID_PARAMETER;
  1419. goto BCVTryExit;
  1420. }
  1421. }
  1422. // NT allows applications to use UNC name as their current directory.
  1423. // while NTVDM can't do that. We will end up a weird drive number
  1424. // like '\' - 'a') here ????????????????????????????????
  1425. //
  1426. // Place Current Drive
  1427. if(AnsiStringCurrentDir.Buffer[0] <= 'Z')
  1428. b->CurDrive = AnsiStringCurrentDir.Buffer[0] - 'A';
  1429. else
  1430. b->CurDrive = AnsiStringCurrentDir.Buffer[0] - 'a';
  1431. //
  1432. // Hotkey info in NT traditionally is specified in the
  1433. // startupinfo.lpReserved field, but Win95 added a
  1434. // duplicate mechanism. If the Win95 method was used,
  1435. // map it to the NT method here so the rest of the
  1436. // VDM code only has to deal with one method.
  1437. //
  1438. // If the caller was specified a hotkey
  1439. // in lpReserved as well as using STARTF_USEHOTKEY,
  1440. // the STARTF_USEHOTKEY hotkey will take precedence.
  1441. //
  1442. if (lpStartupInfo && lpStartupInfo->dwFlags & STARTF_USEHOTKEY) {
  1443. DWORD cbAlloc = sizeof(WCHAR) *
  1444. (20 + // "hotkey.4294967295 " (MAXULONG)
  1445. (lpStartupInfo->lpReserved // length of prev lpReserved
  1446. ? wcslen(lpStartupInfo->lpReserved)
  1447. : 0
  1448. ) +
  1449. 1 // NULL terminator
  1450. );
  1451. lpAllocatedReserved = RtlAllocateHeap(RtlProcessHeap(),
  1452. MAKE_TAG( VDM_TAG ),
  1453. cbAlloc
  1454. );
  1455. if (lpAllocatedReserved) {
  1456. swprintf(lpAllocatedReserved,
  1457. L"hotkey.%u %s",
  1458. HandleToUlong(lpStartupInfo->hStdInput),
  1459. lpStartupInfo->lpReserved ? lpStartupInfo->lpReserved : L""
  1460. );
  1461. lpStartupInfo->dwFlags &= ~STARTF_USEHOTKEY;
  1462. lpStartupInfo->hStdInput = 0;
  1463. lpStartupInfo->lpReserved = lpAllocatedReserved;
  1464. }
  1465. }
  1466. //
  1467. // Allocate Capture Buffer
  1468. //
  1469. //
  1470. bufPointers = 2; // CmdLine, AppName
  1471. //
  1472. // CmdLine for capture buffer, 3 for 0xd,0xa and NULL
  1473. //
  1474. Len = ROUND_UP((OemStringCmd.Length + 3),4);
  1475. // AppName, 1 for NULL
  1476. Len += ROUND_UP((OemStringAppName.Length + 1),4);
  1477. // Env
  1478. if (pAnsiStringEnv->Length) {
  1479. bufPointers++;
  1480. Len += ROUND_UP(pAnsiStringEnv->Length, 4);
  1481. }
  1482. // CurrentDir
  1483. if (AnsiStringCurrentDir.Length){
  1484. bufPointers++;
  1485. Len += ROUND_UP((AnsiStringCurrentDir.Length +1),4); // 1 for NULL
  1486. }
  1487. // pif file name, 1 for NULL
  1488. if (wsPifName && *wsPifName != UNICODE_NULL) {
  1489. bufPointers++;
  1490. RtlInitUnicodeString(&UnicodeString,wsPifName);
  1491. Status = RtlUnicodeStringToAnsiString(&AnsiStringPif,
  1492. &UnicodeString,
  1493. TRUE
  1494. );
  1495. if ( !NT_SUCCESS(Status) ){
  1496. goto BCVTryExit;
  1497. }
  1498. Len += ROUND_UP((AnsiStringPif.Length+1),4);
  1499. }
  1500. //
  1501. // startupinfo space
  1502. //
  1503. if (lpStartupInfo) {
  1504. Len += ROUND_UP(sizeof(STARTUPINFOA),4);
  1505. bufPointers++;
  1506. if (lpStartupInfo->lpDesktop) {
  1507. bufPointers++;
  1508. RtlInitUnicodeString(&UnicodeString,lpStartupInfo->lpDesktop);
  1509. Status = RtlUnicodeStringToAnsiString(
  1510. &AnsiStringDesktop,
  1511. &UnicodeString,
  1512. TRUE);
  1513. if ( !NT_SUCCESS(Status) ){
  1514. goto BCVTryExit;
  1515. }
  1516. Len += ROUND_UP((AnsiStringDesktop.Length+1),4);
  1517. }
  1518. if (lpStartupInfo->lpTitle) {
  1519. bufPointers++;
  1520. RtlInitUnicodeString(&UnicodeString,lpStartupInfo->lpTitle);
  1521. Status = RtlUnicodeStringToOemString(
  1522. &OemStringTitle,
  1523. &UnicodeString,
  1524. TRUE);
  1525. if ( !NT_SUCCESS(Status) ){
  1526. goto BCVTryExit;
  1527. }
  1528. Len += ROUND_UP((OemStringTitle.Length+1),4);
  1529. }
  1530. if (lpStartupInfo->lpReserved) {
  1531. bufPointers++;
  1532. RtlInitUnicodeString(&UnicodeString,lpStartupInfo->lpReserved);
  1533. Status = RtlUnicodeStringToAnsiString(
  1534. &AnsiStringReserved,
  1535. &UnicodeString,
  1536. TRUE);
  1537. if ( !NT_SUCCESS(Status) ){
  1538. goto BCVTryExit;
  1539. }
  1540. Len += ROUND_UP((AnsiStringReserved.Length+1),4);
  1541. }
  1542. }
  1543. //
  1544. // luid space
  1545. //
  1546. // Allocate UserLuid pointer
  1547. if(hUserToken) {
  1548. bufPointers++;
  1549. if (!NT_SUCCESS(BaseGetVdmLuid(hUserToken,&VdmUserLuid))) {
  1550. Status = STATUS_INVALID_PARAMETER;
  1551. goto BCVTryExit;
  1552. }
  1553. Len += ROUND_UP(sizeof(LUID),4);
  1554. }
  1555. // capture message buffer
  1556. CaptureBuffer = CsrAllocateCaptureBuffer(bufPointers, Len);
  1557. if (CaptureBuffer == NULL) {
  1558. Status = STATUS_NO_MEMORY;
  1559. goto BCVTryExit;
  1560. }
  1561. // Allocate CmdLine pointer
  1562. CsrAllocateMessagePointer( CaptureBuffer,
  1563. ROUND_UP((OemStringCmd.Length + 3),4),
  1564. (PVOID *)&b->CmdLine
  1565. );
  1566. // Copy Command Line
  1567. RtlMoveMemory (b->CmdLine, OemStringCmd.Buffer, OemStringCmd.Length);
  1568. b->CmdLine[OemStringCmd.Length] = 0xd;
  1569. b->CmdLine[OemStringCmd.Length+1] = 0xa;
  1570. b->CmdLine[OemStringCmd.Length+2] = 0;
  1571. b->CmdLen = (USHORT)(OemStringCmd.Length + 3);
  1572. // Allocate AppName pointer
  1573. CsrAllocateMessagePointer( CaptureBuffer,
  1574. ROUND_UP((OemStringAppName.Length + 1),4),
  1575. (PVOID *)&b->AppName
  1576. );
  1577. // Copy AppName
  1578. RtlMoveMemory (b->AppName,
  1579. OemStringAppName.Buffer,
  1580. OemStringAppName.Length
  1581. );
  1582. b->AppName[OemStringAppName.Length] = 0;
  1583. b->AppLen = OemStringAppName.Length + 1;
  1584. // Allocate PifFile pointer, Copy PifFile name
  1585. if(AnsiStringPif.Buffer) {
  1586. CsrAllocateMessagePointer( CaptureBuffer,
  1587. ROUND_UP((AnsiStringPif.Length + 1),4),
  1588. (PVOID *)&b->PifFile
  1589. );
  1590. RtlMoveMemory(b->PifFile,
  1591. AnsiStringPif.Buffer,
  1592. AnsiStringPif.Length);
  1593. b->PifFile[AnsiStringPif.Length] = 0;
  1594. b->PifLen = AnsiStringPif.Length + 1;
  1595. }
  1596. else {
  1597. b->PifLen = 0;
  1598. b->PifFile = NULL;
  1599. }
  1600. // Allocate Env pointer, Copy Env strings
  1601. if(pAnsiStringEnv->Length) {
  1602. CsrAllocateMessagePointer( CaptureBuffer,
  1603. ROUND_UP((pAnsiStringEnv->Length),4),
  1604. (PVOID *)&b->Env
  1605. );
  1606. RtlMoveMemory(b->Env,
  1607. pAnsiStringEnv->Buffer,
  1608. pAnsiStringEnv->Length);
  1609. b->EnvLen = pAnsiStringEnv->Length;
  1610. }
  1611. else {
  1612. b->EnvLen = 0;
  1613. b->Env = NULL;
  1614. }
  1615. if(AnsiStringCurrentDir.Length) {
  1616. // Allocate Curdir pointer
  1617. CsrAllocateMessagePointer( CaptureBuffer,
  1618. ROUND_UP((AnsiStringCurrentDir.Length + 1),4),
  1619. (PVOID *)&b->CurDirectory
  1620. );
  1621. // copy cur directory
  1622. RtlMoveMemory (b->CurDirectory,
  1623. AnsiStringCurrentDir.Buffer,
  1624. AnsiStringCurrentDir.Length+1);
  1625. b->CurDirectoryLen = AnsiStringCurrentDir.Length+1;
  1626. }
  1627. else {
  1628. b->CurDirectory = NULL;
  1629. b->CurDirectoryLen = 0;
  1630. }
  1631. // Allocate startupinfo pointer
  1632. if (lpStartupInfo) {
  1633. CsrAllocateMessagePointer( CaptureBuffer,
  1634. ROUND_UP(sizeof(STARTUPINFOA),4),
  1635. (PVOID *)&b->StartupInfo
  1636. );
  1637. // Copy startupinfo
  1638. b->StartupInfo->dwX = lpStartupInfo->dwX;
  1639. b->StartupInfo->dwY = lpStartupInfo->dwY;
  1640. b->StartupInfo->dwXSize = lpStartupInfo->dwXSize;
  1641. b->StartupInfo->dwYSize = lpStartupInfo->dwYSize;
  1642. b->StartupInfo->dwXCountChars= lpStartupInfo->dwXCountChars;
  1643. b->StartupInfo->dwYCountChars= lpStartupInfo->dwYCountChars;
  1644. b->StartupInfo->dwFillAttribute=lpStartupInfo->dwFillAttribute;
  1645. b->StartupInfo->dwFlags = lpStartupInfo->dwFlags;
  1646. b->StartupInfo->wShowWindow = lpStartupInfo->wShowWindow;
  1647. b->StartupInfo->cb = sizeof(STARTUPINFOA);
  1648. }
  1649. else {
  1650. b->StartupInfo = NULL;
  1651. }
  1652. // Allocate pointer for Desktop info if needed
  1653. if (AnsiStringDesktop.Buffer) {
  1654. CsrAllocateMessagePointer( CaptureBuffer,
  1655. ROUND_UP((AnsiStringDesktop.Length + 1),4),
  1656. (PVOID *)&b->Desktop
  1657. );
  1658. // Copy desktop string
  1659. RtlMoveMemory (b->Desktop,
  1660. AnsiStringDesktop.Buffer,
  1661. AnsiStringDesktop.Length+1);
  1662. b->DesktopLen =AnsiStringDesktop.Length+1;
  1663. }
  1664. else {
  1665. b->Desktop = NULL;
  1666. b->DesktopLen =0;
  1667. }
  1668. // Allocate pointer for Title info if needed
  1669. if (OemStringTitle.Buffer) {
  1670. CsrAllocateMessagePointer( CaptureBuffer,
  1671. ROUND_UP((OemStringTitle.Length + 1),4),
  1672. (PVOID *)&b->Title
  1673. );
  1674. // Copy title string
  1675. RtlMoveMemory (b->Title,
  1676. OemStringTitle.Buffer,
  1677. OemStringTitle.Length+1);
  1678. b->TitleLen = OemStringTitle.Length+1;
  1679. }
  1680. else {
  1681. b->Title = NULL;
  1682. b->TitleLen = 0;
  1683. }
  1684. // Allocate pointer for Reserved field if needed
  1685. if (AnsiStringReserved.Buffer) {
  1686. CsrAllocateMessagePointer( CaptureBuffer,
  1687. ROUND_UP((AnsiStringReserved.Length + 1),4),
  1688. (PVOID *)&b->Reserved
  1689. );
  1690. // Copy reserved string
  1691. RtlMoveMemory (b->Reserved,
  1692. AnsiStringReserved.Buffer,
  1693. AnsiStringReserved.Length+1);
  1694. b->ReservedLen = AnsiStringReserved.Length+1;
  1695. }
  1696. else {
  1697. b->Reserved = NULL;
  1698. b->ReservedLen = 0;
  1699. }
  1700. // Allocate UserLuid pointer
  1701. if(hUserToken) {
  1702. CsrAllocateMessagePointer( CaptureBuffer,
  1703. ROUND_UP(sizeof(LUID),4),
  1704. (PVOID *)&b->UserLuid
  1705. );
  1706. RtlCopyLuid(b->UserLuid,&VdmUserLuid);
  1707. }
  1708. else {
  1709. b->UserLuid = NULL;
  1710. }
  1711. // VadimB: this code is of no consequence to our marvelous new
  1712. // architecture for tracking shared wows.
  1713. // Reason: the checkvdm command is executed within the context of
  1714. // a parent process thus at this point ConsoleHandle is of any
  1715. // interest only to DOS apps.
  1716. if (BinaryType == BINARY_TYPE_WIN16)
  1717. b->ConsoleHandle = (HANDLE)-1;
  1718. else if (bNewConsole)
  1719. b->ConsoleHandle = 0;
  1720. else
  1721. b->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
  1722. b->VDMState = FALSE;
  1723. b->BinaryType = BinaryType;
  1724. b->CodePage = (ULONG) GetConsoleCP ();
  1725. b->dwCreationFlags = dwCreationFlags;
  1726. Status = CsrClientCallServer(
  1727. (PCSR_API_MSG)m,
  1728. CaptureBuffer,
  1729. CSR_MAKE_API_NUMBER( BASESRV_SERVERDLL_INDEX,
  1730. BasepCheckVDM
  1731. ),
  1732. sizeof( *b )
  1733. );
  1734. // if desktop access is denied, then we try again with the
  1735. // current default desktop
  1736. //
  1737. if ((STATUS_ACCESS_DENIED == Status) && (0 == b->DesktopLen)) {
  1738. CsrFreeCaptureBuffer(CaptureBuffer);
  1739. goto BCVTryExit;
  1740. }
  1741. CsrFreeCaptureBuffer(CaptureBuffer);
  1742. if (!NT_SUCCESS(Status) || !NT_SUCCESS((NTSTATUS)m->ReturnValue)) {
  1743. Status = (NTSTATUS)m->ReturnValue;
  1744. goto BCVTryExit;
  1745. }
  1746. // VadimB: This iTask could be :
  1747. // (*) If not wow task - then dos task id (items below are not
  1748. // relevant for this case)
  1749. // (*) Shared wow exists and ready - this is a wow task id
  1750. // that is unique across all the shared wows
  1751. *iTask = b->iTask;
  1752. Status = STATUS_SUCCESS;
  1753. BCVTryExit:;
  1754. }
  1755. finally {
  1756. if(Buffer != NULL)
  1757. RtlFreeHeap(RtlProcessHeap(), 0, (PVOID)Buffer);
  1758. if(wsBuffer != NULL)
  1759. RtlFreeHeap(RtlProcessHeap(), 0, (PVOID)wsBuffer);
  1760. if(wsPifName != NULL)
  1761. RtlFreeHeap(RtlProcessHeap(), 0, (PVOID)wsPifName);
  1762. if(OemStringCmd.Buffer != NULL)
  1763. RtlFreeOemString(&OemStringCmd);
  1764. if(OemStringAppName.Buffer != NULL)
  1765. RtlFreeOemString(&OemStringAppName);
  1766. if(AnsiStringPif.Buffer != NULL)
  1767. RtlFreeAnsiString(&AnsiStringPif);
  1768. if(AnsiStringCurrentDir.Buffer != NULL)
  1769. RtlFreeAnsiString(&AnsiStringCurrentDir);
  1770. if(AnsiStringDesktop.Buffer != NULL)
  1771. RtlFreeAnsiString(&AnsiStringDesktop);
  1772. if(OemStringTitle.Buffer != NULL)
  1773. RtlFreeAnsiString(&OemStringTitle);
  1774. if(AnsiStringReserved.Buffer != NULL)
  1775. RtlFreeAnsiString(&AnsiStringReserved);
  1776. if (wsAppName != NULL)
  1777. RtlFreeHeap(RtlProcessHeap(), 0, wsAppName);
  1778. if (lpAllocatedReserved != NULL)
  1779. RtlFreeHeap(RtlProcessHeap(), 0, lpAllocatedReserved);
  1780. }
  1781. return Status;
  1782. }
  1783. /*
  1784. jarbats
  1785. Some apps send startupinfo with bad desktop name
  1786. as a result, basecheckvdm will fail with because
  1787. access to the desktop can't be obtained
  1788. in that case we attempt again with the parents desktop
  1789. */
  1790. NTSTATUS
  1791. BaseCheckVDM(
  1792. IN ULONG BinaryType,
  1793. IN PCWCH lpApplicationName,
  1794. IN PCWCH lpCommandLine,
  1795. IN PCWCH lpCurrentDirectory,
  1796. IN ANSI_STRING *pAnsiStringEnv,
  1797. IN PBASE_API_MSG m,
  1798. IN OUT PULONG iTask,
  1799. IN DWORD dwCreationFlags,
  1800. LPSTARTUPINFOW lpStartupInfo,
  1801. IN HANDLE hUserToken
  1802. ) {
  1803. NTSTATUS Status;
  1804. LPWSTR lpDesktopOld;
  1805. Status = BaseCheckVDMp(
  1806. BinaryType,
  1807. lpApplicationName,
  1808. lpCommandLine,
  1809. lpCurrentDirectory,
  1810. pAnsiStringEnv,
  1811. m,
  1812. iTask,
  1813. dwCreationFlags,
  1814. lpStartupInfo,
  1815. hUserToken
  1816. );
  1817. if ( Status == STATUS_ACCESS_DENIED ) {
  1818. lpDesktopOld = lpStartupInfo->lpDesktop;
  1819. lpStartupInfo->lpDesktop =
  1820. (LPWSTR)((PRTL_USER_PROCESS_PARAMETERS)NtCurrentPeb()->
  1821. ProcessParameters)->DesktopInfo.Buffer;
  1822. Status = BaseCheckVDMp(
  1823. BinaryType,
  1824. lpApplicationName,
  1825. lpCommandLine,
  1826. lpCurrentDirectory,
  1827. pAnsiStringEnv,
  1828. m,
  1829. iTask,
  1830. dwCreationFlags,
  1831. lpStartupInfo,
  1832. hUserToken
  1833. );
  1834. if (!NT_SUCCESS(Status)) {
  1835. lpStartupInfo->lpDesktop = lpDesktopOld;
  1836. }
  1837. } else if (Status == STATUS_VDM_DISALLOWED) {
  1838. UNICODE_STRING UnicodeString;
  1839. ULONG_PTR ErrorParameters[2];
  1840. ULONG ErrorResponse;
  1841. RtlInitUnicodeString(&UnicodeString, lpApplicationName);
  1842. ErrorParameters[0] = (ULONG_PTR)&UnicodeString;
  1843. NtRaiseHardError(
  1844. STATUS_VDM_DISALLOWED,
  1845. 1, // 1 parameter
  1846. 1, // ParameterStringMask
  1847. ErrorParameters,
  1848. OptionOk,
  1849. &ErrorResponse
  1850. );
  1851. }
  1852. return Status;
  1853. }
  1854. BOOL
  1855. BaseUpdateVDMEntry(
  1856. IN ULONG UpdateIndex,
  1857. IN OUT HANDLE *WaitHandle,
  1858. IN ULONG IndexInfo,
  1859. IN ULONG BinaryType
  1860. )
  1861. {
  1862. NTSTATUS Status;
  1863. BASE_API_MSG m;
  1864. PBASE_UPDATE_VDM_ENTRY_MSG c = &m.u.UpdateVDMEntry;
  1865. switch (UpdateIndex) {
  1866. case UPDATE_VDM_UNDO_CREATION:
  1867. c->iTask = HandleToUlong(*WaitHandle);
  1868. c->VDMCreationState = (USHORT)IndexInfo;
  1869. break;
  1870. case UPDATE_VDM_PROCESS_HANDLE:
  1871. c->VDMProcessHandle = *WaitHandle; // Actually this is VDM handle
  1872. c->iTask = IndexInfo;
  1873. break;
  1874. }
  1875. // VadimB: this ConsoleHandle is of no consequence to the
  1876. // shared wow tracking mechanism
  1877. if(BinaryType == BINARY_TYPE_WIN16)
  1878. c->ConsoleHandle = (HANDLE)-1;
  1879. else if (c->iTask)
  1880. c->ConsoleHandle = 0;
  1881. else
  1882. c->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
  1883. c->EntryIndex = (WORD)UpdateIndex;
  1884. c->BinaryType = BinaryType;
  1885. Status = CsrClientCallServer(
  1886. (PCSR_API_MSG)&m,
  1887. NULL,
  1888. CSR_MAKE_API_NUMBER( BASESRV_SERVERDLL_INDEX,
  1889. BasepUpdateVDMEntry
  1890. ),
  1891. sizeof( *c )
  1892. );
  1893. if (!NT_SUCCESS(Status) || !NT_SUCCESS((NTSTATUS)m.ReturnValue)) {
  1894. BaseSetLastNTError((NTSTATUS)m.ReturnValue);
  1895. return FALSE;
  1896. }
  1897. switch (UpdateIndex) {
  1898. case UPDATE_VDM_UNDO_CREATION:
  1899. break;
  1900. case UPDATE_VDM_PROCESS_HANDLE:
  1901. *WaitHandle = c->WaitObjectForParent;
  1902. break;
  1903. }
  1904. return TRUE;
  1905. }
  1906. ULONG
  1907. BaseIsDosApplication(
  1908. IN PUNICODE_STRING PathName,
  1909. IN NTSTATUS Status
  1910. )
  1911. /*++
  1912. Routine Description:
  1913. Determines if app is a ".com" or a ".pif" type of app
  1914. by looking at the extension, and the Status from NtCreateSection
  1915. for PAGE_EXECUTE.
  1916. Arguments:
  1917. PathName -- Supplies a pointer to the path string
  1918. Status -- Status code from CreateSection call
  1919. bNewConsole -- Pif can exec only from a new console
  1920. Return Value:
  1921. file is a com\pif dos application
  1922. SCS_DOS_BINARY - ".com", may also be a .exe extension
  1923. SCS_PIF_BINARY - ".pif"
  1924. 0 -- file is not a dos application, may be a .bat or .cmd file
  1925. --*/
  1926. {
  1927. UNICODE_STRING String;
  1928. // check for .com extension
  1929. String.Length = BaseDotComSuffixName.Length;
  1930. String.Buffer = &(PathName->Buffer[(PathName->Length - String.Length) /
  1931. sizeof(WCHAR)]);
  1932. if (RtlEqualUnicodeString(&String, &BaseDotComSuffixName, TRUE))
  1933. return BINARY_TYPE_DOS_COM;
  1934. // check for .pif extension
  1935. String.Length = BaseDotPifSuffixName.Length;
  1936. String.Buffer = &(PathName->Buffer[(PathName->Length - String.Length) /
  1937. sizeof(WCHAR)]);
  1938. if (RtlEqualUnicodeString(&String, &BaseDotPifSuffixName, TRUE))
  1939. return BINARY_TYPE_DOS_PIF;
  1940. // check for .exe extension
  1941. String.Length = BaseDotExeSuffixName.Length;
  1942. String.Buffer = &(PathName->Buffer[(PathName->Length - String.Length) /
  1943. sizeof(WCHAR)]);
  1944. if (RtlEqualUnicodeString(&String, &BaseDotExeSuffixName, TRUE))
  1945. return BINARY_TYPE_DOS_EXE;
  1946. return 0;
  1947. }
  1948. BOOL
  1949. BaseGetVdmConfigInfo(
  1950. IN LPCWSTR CommandLine,
  1951. IN ULONG DosSeqId,
  1952. IN ULONG BinaryType,
  1953. IN PUNICODE_STRING CmdLineString,
  1954. IN OUT PULONG VdmSize
  1955. )
  1956. /*++
  1957. Routine Description:
  1958. This routine locates the VDM configuration information for Wow vdms in
  1959. the system configuration file. It also reconstructs the commandline so
  1960. that we can start the VDM. The new command line is composed from the
  1961. information in the configuration file + the old command line.
  1962. Arguments:
  1963. CommandLine -- pointer to a string pointer that is used to pass the
  1964. command line string
  1965. DosSeqId - new console session id. This parameter is also valid for
  1966. shared wow as it is passed to ntvdm as -i parameter. Another
  1967. parameter to identify shared wow is passed to ntvdm as
  1968. '-ws' where 'w' stands for wow app, 's' stands for separate
  1969. In response to this 's' parameter ntvdm launches a
  1970. separate wow (one-time shot). By default, ntvdm starts a shared
  1971. wow.
  1972. VdmSize --entry:
  1973. return: the size in bytes of the VDM to be created
  1974. BinaryType - dos, sharedwow, sepwow
  1975. Return Value:
  1976. TRUE -- VDM configuration information was available
  1977. FALSE -- VDM configuration information was not available
  1978. Notes:
  1979. --*/
  1980. {
  1981. NTSTATUS Status;
  1982. ANSI_STRING AnsiString;
  1983. PCH pDst;
  1984. WCHAR CmdLine[2*MAX_PATH];
  1985. WCHAR szSystemDirectory[MAX_PATH];
  1986. DWORD dwLen;
  1987. CmdLineString->Buffer = NULL;
  1988. *VdmSize = 16L*1024L*1024L;
  1989. dwLen = GetSystemDirectoryW(szSystemDirectory,MAX_PATH);
  1990. if(!dwLen || dwLen >= MAX_PATH) {
  1991. SetLastError(ERROR_INVALID_NAME);
  1992. return FALSE;
  1993. }
  1994. if (DosSeqId) {
  1995. #pragma prefast(suppress:53, the buffer is big enough (PREfast bug 775))
  1996. _snwprintf(CmdLine,
  1997. sizeof(CmdLine)/sizeof(WCHAR),
  1998. L"\"%s\\ntvdm.exe\" -i%lx %s%c",
  1999. szSystemDirectory,
  2000. DosSeqId,
  2001. BinaryType != BINARY_TYPE_DOS? L"-w":L"",
  2002. BinaryType == BINARY_TYPE_SEPWOW? L's':L' '
  2003. );
  2004. }
  2005. else {
  2006. #pragma prefast(suppress:53, the buffer is big enough (PREfast bug 775))
  2007. _snwprintf(CmdLine,
  2008. sizeof(CmdLine)/sizeof(WCHAR),
  2009. L"\"%s\\ntvdm.exe\" %s%c",
  2010. szSystemDirectory,
  2011. BinaryType != BINARY_TYPE_DOS? L"-w":L"",
  2012. BinaryType == BINARY_TYPE_SEPWOW? L's':L'\0'
  2013. );
  2014. }
  2015. return RtlCreateUnicodeString(CmdLineString, CmdLine);
  2016. }
  2017. BOOL
  2018. BaseCheckForVDM(
  2019. IN HANDLE hProcess,
  2020. OUT LPDWORD lpExitCode
  2021. )
  2022. {
  2023. NTSTATUS Status;
  2024. EVENT_BASIC_INFORMATION ebi;
  2025. BASE_API_MSG m;
  2026. PBASE_GET_VDM_EXIT_CODE_MSG a = &m.u.GetVDMExitCode;
  2027. Status = NtQueryEvent (
  2028. hProcess,
  2029. EventBasicInformation,
  2030. &ebi,
  2031. sizeof(ebi),
  2032. NULL);
  2033. if(!NT_SUCCESS(Status)) {
  2034. return FALSE;
  2035. }
  2036. a->ConsoleHandle = NtCurrentPeb()->ProcessParameters->ConsoleHandle;
  2037. a->hParent = hProcess;
  2038. Status = CsrClientCallServer(
  2039. (PCSR_API_MSG)&m,
  2040. NULL,
  2041. CSR_MAKE_API_NUMBER( BASESRV_SERVERDLL_INDEX,
  2042. BasepGetVDMExitCode),
  2043. sizeof( *a )
  2044. );
  2045. if (!NT_SUCCESS(Status)) {
  2046. return FALSE;
  2047. }
  2048. *lpExitCode = (DWORD)a->ExitCode;
  2049. return TRUE;
  2050. }
  2051. DWORD
  2052. APIENTRY
  2053. GetShortPathNameA(
  2054. IN LPCSTR lpszLongPath,
  2055. IN LPSTR lpShortPath,
  2056. IN DWORD cchBuffer
  2057. )
  2058. {
  2059. UNICODE_STRING UString, UStringRet;
  2060. ANSI_STRING AString;
  2061. NTSTATUS Status;
  2062. WCHAR TempPathW[MAX_PATH];
  2063. LPWSTR lpShortPathW = NULL;
  2064. DWORD ReturnValue;
  2065. DWORD ReturnValueW;
  2066. if (lpszLongPath == NULL) {
  2067. SetLastError(ERROR_INVALID_PARAMETER);
  2068. return 0;
  2069. }
  2070. // We have to initialize it before the "try" statement
  2071. AString.Buffer = NULL;
  2072. UString.Buffer = NULL;
  2073. ReturnValue = 0;
  2074. ReturnValueW = 0;
  2075. try {
  2076. if (!Basep8BitStringToDynamicUnicodeString(&UString, lpszLongPath )) {
  2077. goto gspTryExit;
  2078. }
  2079. // we have to get the real converted path in order to find out
  2080. // the required length. An UNICODE char does not necessarily convert
  2081. // to one ANSI char(A DBCS is basically TWO ANSI char!!!!!).
  2082. // First, we use the buffer allocated from the stack. If the buffer
  2083. // is too small, we then allocate it from heap.
  2084. // A check of (lpShortPathW && TempPathW != lpShortPathW) will reveal
  2085. // if we have allocated a buffer from heap and need to release it.
  2086. lpShortPathW = TempPathW;
  2087. ReturnValueW = GetShortPathNameW(UString.Buffer, lpShortPathW, sizeof(TempPathW) / sizeof(WCHAR));
  2088. if (ReturnValueW >= sizeof(TempPathW) / sizeof(WCHAR))
  2089. {
  2090. // the stack-based buffer is too small. Allocate a new buffer
  2091. // from heap.
  2092. lpShortPathW = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( VDM_TAG ),
  2093. ReturnValueW * sizeof(WCHAR)
  2094. );
  2095. if (lpShortPathW) {
  2096. ReturnValueW = GetShortPathNameW(UString.Buffer, lpShortPathW, ReturnValueW);
  2097. }
  2098. else {
  2099. ReturnValueW = 0;
  2100. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2101. }
  2102. }
  2103. if (ReturnValueW)
  2104. {
  2105. // we are here because we have something interesting left to do.
  2106. // Convert the UNICODE path name to ANSI(or OEM).
  2107. UString.MaximumLength = (USHORT)((ReturnValueW + 1) * sizeof(WCHAR));
  2108. UStringRet.Buffer = lpShortPathW;
  2109. UStringRet.Length = (USHORT)(ReturnValueW * sizeof(WCHAR));
  2110. Status = BasepUnicodeStringTo8BitString(&AString,
  2111. &UStringRet,
  2112. TRUE
  2113. );
  2114. if (!NT_SUCCESS(Status))
  2115. {
  2116. BaseSetLastNTError(Status);
  2117. ReturnValue=0;
  2118. goto gspTryExit;
  2119. }
  2120. // now AString.Length contains the size of the converted path
  2121. // name. If the caller provides enough buffer, copy the
  2122. // path name.
  2123. ReturnValue = AString.Length;
  2124. if (ARGUMENT_PRESENT(lpShortPath) && cchBuffer > ReturnValue)
  2125. {
  2126. RtlMoveMemory(lpShortPath, AString.Buffer, ReturnValue);
  2127. // terminate the string with NULL char
  2128. lpShortPath[ReturnValue] = '\0';
  2129. }
  2130. else
  2131. {
  2132. // either the caller does not provide a buffer or
  2133. // the provided buffer is too small return the required size,
  2134. // including the terminated null char
  2135. ReturnValue++;
  2136. }
  2137. }
  2138. gspTryExit:;
  2139. }
  2140. finally {
  2141. if (UString.Buffer)
  2142. RtlFreeUnicodeString(&UString);
  2143. if (AString.Buffer)
  2144. RtlFreeAnsiString(&AString);
  2145. if (lpShortPathW && lpShortPathW != TempPathW)
  2146. RtlFreeHeap(RtlProcessHeap(), 0, lpShortPathW);
  2147. }
  2148. return ReturnValue;
  2149. }
  2150. /****
  2151. GetShortPathName
  2152. Description:
  2153. This function converts the given path name to its short form if
  2154. needed. The conversion may not be necessary and in that case,
  2155. this function simply copies down the given name to the return buffer.
  2156. The caller can have the return buffer set equal to the given path name
  2157. address.
  2158. Parameters:
  2159. lpszLongPath - Points to a NULL terminated string.
  2160. lpszShortPath - Buffer address to return the short name.
  2161. cchBuffer - Buffer size in char of lpszShortPath.
  2162. Return Value
  2163. If the GetShortPathName function succeeds, the return value is the length,
  2164. in characters, of the string copied to lpszShortPath,
  2165. not including the terminating
  2166. null character.
  2167. If the lpszShortPath is too small, the return value is
  2168. the size of the buffer, in
  2169. characters, required to hold the path.
  2170. If the function fails, the return value is zero. To get
  2171. extended error information, use
  2172. the GetLastError function.
  2173. Remarks:
  2174. The "short name" can be longer than its "long name". lpszLongPath doesn't
  2175. have to be a fully qualified path name or a long path name.
  2176. ****/
  2177. DWORD
  2178. APIENTRY
  2179. GetShortPathNameW(
  2180. IN LPCWSTR lpszLongPath,
  2181. IN LPWSTR lpszShortPath,
  2182. IN DWORD cchBuffer
  2183. )
  2184. {
  2185. LPCWSTR pcs;
  2186. LPWSTR pSrcCopy, pSrc, pFirst, pLast, pDst;
  2187. WCHAR wch;
  2188. HANDLE FindHandle;
  2189. WIN32_FIND_DATAW FindData;
  2190. LPWSTR Buffer;
  2191. DWORD ReturnLen=0, Length;
  2192. UINT PrevErrorMode;
  2193. if (!ARGUMENT_PRESENT(lpszLongPath)) {
  2194. SetLastError(ERROR_INVALID_PARAMETER);
  2195. return 0;
  2196. }
  2197. //
  2198. // override the error mode since we will be touching the media.
  2199. // This is to prevent file system's pop-up when the given path does not
  2200. // exist or the media is not available.
  2201. // we are doing this because we can not depend on the caller's current
  2202. // error mode. NOTE: the old error mode must be restored.
  2203. PrevErrorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
  2204. try {
  2205. Buffer = NULL;
  2206. pSrcCopy = NULL;
  2207. // first, make sure the given path exist
  2208. if (0xFFFFFFFF == GetFileAttributesW(lpszLongPath))
  2209. {
  2210. //
  2211. // (bjm - 3/17/99)
  2212. // This behavior (failing if the file does not exist) is new (to NT) with NT 5.
  2213. // (It's the Win9x behavior.)
  2214. // Give an exception to Norton AntiVirus Uninstall.
  2215. // If we fail this call, there will be a registry value left behind in VDD that'll cause
  2216. // undeserved ugly messages for a user. Norton AV Uninstall counts on NT 4 behavior
  2217. // which did not care if the file existed to do this conversion. This was changed in
  2218. // NT 5.0 to match Win9x behavior.
  2219. //
  2220. if ( !NtCurrentPeb() || !APPCOMPATFLAG(KACF_OLDGETSHORTPATHNAME) )
  2221. {
  2222. // last error has been set by GetFileAttributes
  2223. ReturnLen = 0;
  2224. goto gsnTryExit;
  2225. }
  2226. }
  2227. pcs = SkipPathTypeIndicator_U(lpszLongPath);
  2228. if (!pcs || *pcs == UNICODE_NULL || !FindLFNorSFN_U((LPWSTR)pcs, &pFirst, &pLast, TRUE))
  2229. {
  2230. // nothing to convert, copy down the source string
  2231. // to the buffer if necessary
  2232. ReturnLen = wcslen(lpszLongPath);
  2233. if (cchBuffer > ReturnLen && ARGUMENT_PRESENT(lpszShortPath))
  2234. {
  2235. if (lpszShortPath != lpszLongPath)
  2236. RtlMoveMemory(lpszShortPath, lpszLongPath,
  2237. (ReturnLen + 1) * sizeof(WCHAR)
  2238. );
  2239. }
  2240. else {
  2241. // the caller does not provide enough buffer, return
  2242. // necessary string length plus the terminated null char
  2243. ReturnLen++;
  2244. }
  2245. goto gsnTryExit;
  2246. }
  2247. // conversions are necessary, make a local copy of the string
  2248. // because we have to party on it.
  2249. ASSERT(!pSrcCopy);
  2250. // get the source string length
  2251. Length = wcslen(lpszLongPath) + 1;
  2252. pSrcCopy = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( VDM_TAG ),
  2253. Length * sizeof(WCHAR)
  2254. );
  2255. if (!pSrcCopy) {
  2256. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2257. goto gsnTryExit;
  2258. }
  2259. wcsncpy(pSrcCopy, lpszLongPath, Length);
  2260. // pFirst points to the first char of the very first LFN in the path
  2261. // pLast points to the char right after the last char of the very
  2262. // first LFN in the path. *pLast could be UNICODE_NULL
  2263. pFirst = pSrcCopy + (pFirst - lpszLongPath);
  2264. pLast = pSrcCopy + (pLast - lpszLongPath);
  2265. //
  2266. // We allow lpszShortPath be overlapped with lpszLongPath so
  2267. // allocate a local buffer.
  2268. pDst = lpszShortPath;
  2269. if (cchBuffer > 0 && ARGUMENT_PRESENT(lpszShortPath) &&
  2270. (lpszShortPath >= lpszLongPath &&lpszShortPath < lpszLongPath + Length ||
  2271. lpszShortPath < lpszLongPath && lpszShortPath + cchBuffer >= lpszLongPath))
  2272. {
  2273. ASSERT(!Buffer);
  2274. Buffer = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( VDM_TAG ),
  2275. cchBuffer * sizeof(WCHAR));
  2276. if (!Buffer){
  2277. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2278. goto gsnTryExit;
  2279. }
  2280. pDst = Buffer;
  2281. }
  2282. pSrc = pSrcCopy;
  2283. ReturnLen = 0;
  2284. do {
  2285. // there are three pointers involve in the conversion loop:
  2286. // pSrc, pFirst and pLast. Their relationship
  2287. // is:
  2288. //
  2289. // "c:\long~1.1\\foo.bar\\long~2.2\\bar"
  2290. // ^ ^ ^ ^
  2291. // | | | |
  2292. // | pSrc pFirst pLast
  2293. // pSrcCopy
  2294. //
  2295. // pSrcCopy always points to the very first char of the entire
  2296. // path.
  2297. //
  2298. // chars between pSrc(included) and pFirst(not included)
  2299. // do not need conversion so we simply copy them.
  2300. // chars between pFirst(included) and pLast(not included)
  2301. // need conversion.
  2302. //
  2303. Length = (ULONG)(pFirst - pSrc);
  2304. if (Length) {
  2305. ReturnLen += Length;
  2306. if (cchBuffer > ReturnLen && ARGUMENT_PRESENT(lpszShortPath)) {
  2307. RtlMoveMemory(pDst, pSrc, Length * sizeof(WCHAR));
  2308. pDst += Length;
  2309. }
  2310. }
  2311. wch = *pLast;
  2312. *pLast = UNICODE_NULL;
  2313. FindHandle = FindFirstFileW(pSrcCopy, &FindData);
  2314. *pLast = wch;
  2315. if (INVALID_HANDLE_VALUE != FindHandle) {
  2316. FindClose(FindHandle);
  2317. // if no short name could be found, copy the original name.
  2318. // the origian name starts with pFirst(included) and ends
  2319. // with pLast(excluded).
  2320. if (!(Length = wcslen(FindData.cAlternateFileName)))
  2321. Length = (ULONG)(pLast - pFirst);
  2322. else
  2323. pFirst = FindData.cAlternateFileName;
  2324. ReturnLen += Length;
  2325. if (cchBuffer > ReturnLen && ARGUMENT_PRESENT(lpszShortPath))
  2326. {
  2327. RtlMoveMemory(pDst, pFirst, Length * sizeof(WCHAR));
  2328. pDst += Length;
  2329. }
  2330. }
  2331. else {
  2332. // part of the path does not exist, fail the function
  2333. //
  2334. ReturnLen = 0;
  2335. break;
  2336. }
  2337. // move to next path name
  2338. pSrc = pLast;
  2339. if (*pLast == UNICODE_NULL)
  2340. break;
  2341. }while (FindLFNorSFN_U(pSrc, &pFirst, &pLast, TRUE));
  2342. // if ReturnLen == 0, we fail somewhere inside while loop.
  2343. if (ReturnLen) {
  2344. // (*pSrc == UNICODE_NULL) means the last pathname is a LFN which
  2345. // has been dealt with. otherwise, the substring pointed by
  2346. // pSrc is a legal short path name and we have to copy it
  2347. //Length could be zero
  2348. Length = wcslen(pSrc);
  2349. ReturnLen += Length;
  2350. if (cchBuffer > ReturnLen && ARGUMENT_PRESENT(lpszShortPath))
  2351. {
  2352. //include the terminated null char
  2353. RtlMoveMemory(pDst, pSrc, (Length + 1)* sizeof(WCHAR));
  2354. if (Buffer)
  2355. RtlMoveMemory(lpszShortPath, Buffer, (ReturnLen + 1) * sizeof(WCHAR));
  2356. }
  2357. else
  2358. // not enough buffer, the return value counts the terminated NULL
  2359. ReturnLen++;
  2360. }
  2361. gsnTryExit:;
  2362. }
  2363. finally {
  2364. if (Buffer)
  2365. RtlFreeHeap(RtlProcessHeap(), 0, Buffer);
  2366. if (pSrcCopy)
  2367. RtlFreeHeap(RtlProcessHeap(), 0, pSrcCopy);
  2368. // restore the error mode
  2369. SetErrorMode(PrevErrorMode);
  2370. }
  2371. return ReturnLen;
  2372. }
  2373. /**
  2374. function to create VDM environment for the new executable.
  2375. Input: lpEnvironmen = optinal environment strings prototype in UNICODE.
  2376. If it is NULL, this function use the environment
  2377. block attached to the process
  2378. pAStringEnv = pointer to a ANSI_STRING to receive the
  2379. new environment strings.
  2380. pUStringEnv = pointer to a UNICODE_STRING to receive the
  2381. new environment strings.
  2382. Output: FALSE if the creattion failed.
  2383. TRUE creation successful, pAStringEnv has been setup.
  2384. This function was provided so that BaseCheckVdm can have correct
  2385. environment(includes the newly create NTVDM process). This was done
  2386. because before command.com gets the next command, users can have
  2387. tons of things specified in config.sys and autoexec.bat which
  2388. may rely on current directory of each drive.
  2389. **/
  2390. BOOL BaseCreateVDMEnvironment(
  2391. PWCHAR lpEnvironment,
  2392. ANSI_STRING * pAStringEnv,
  2393. UNICODE_STRING *pUStringEnv
  2394. )
  2395. {
  2396. WCHAR *pEnv, *pDst, *EnvStrings=NULL,* pTmp, *pNewEnv=NULL;
  2397. DWORD cchEnv, dw, Length, dwRemain;
  2398. NTSTATUS Status;
  2399. UINT NameType;
  2400. BOOL bRet = FALSE;
  2401. SIZE_T EnvSize;
  2402. if (!ARGUMENT_PRESENT(pAStringEnv) || !ARGUMENT_PRESENT(pUStringEnv)){
  2403. SetLastError(ERROR_INVALID_PARAMETER);
  2404. return FALSE;
  2405. }
  2406. try {
  2407. // the environment strings are shared by every thread of the same
  2408. // process. Since we have no idea of what the caller process
  2409. // is, we have to grab the entire environment to our local buffer in one
  2410. // shot then we can walk through the strings.
  2411. // Note that if another thread makes call to RtlSetEnvironmentVariable
  2412. // then we are out of sync. It is a problem of process structure and
  2413. // I don't want to think about it now.
  2414. // The funny thing is that we have to assume the environment
  2415. // is a block of strings(otherwise, how can we do it?)t, nothing more and
  2416. // nothing less. If someday and somebody dares to change it, he will be
  2417. // the one to blame. If the caller(CreateProcess)
  2418. // provides the environment, we assume it is safe to walk through it.
  2419. //
  2420. if (lpEnvironment == NULL) {
  2421. // create a new environment and inherit the current process env
  2422. Status = RtlCreateEnvironment(TRUE, (PVOID *)&EnvStrings);
  2423. if (!NT_SUCCESS(Status))
  2424. goto bveTryExit;
  2425. }
  2426. else
  2427. EnvStrings = lpEnvironment;
  2428. if (EnvStrings == NULL) {
  2429. SetLastError(ERROR_BAD_ENVIRONMENT);
  2430. goto bveTryExit;
  2431. }
  2432. // figure out how long the environment is
  2433. // why can Rtl just provides such a function for us?
  2434. //
  2435. cchEnv = 0;
  2436. pEnv = EnvStrings;
  2437. // environment is double-null terminated
  2438. while (!(*pEnv++ == UNICODE_NULL && *pEnv == UNICODE_NULL))
  2439. cchEnv++;
  2440. // count the last two NULLs
  2441. cchEnv += 2;
  2442. // we don't want to change the original environment, so
  2443. // make a local buffer for it.
  2444. EnvSize = (cchEnv + MAX_PATH) * sizeof(WCHAR);
  2445. Status = NtAllocateVirtualMemory( NtCurrentProcess(),
  2446. &pNewEnv,
  2447. 0,
  2448. &EnvSize,
  2449. MEM_COMMIT,
  2450. PAGE_READWRITE
  2451. );
  2452. if (!NT_SUCCESS(Status) ) {
  2453. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2454. pNewEnv = NULL;
  2455. goto bveTryExit;
  2456. }
  2457. // give the last two for null
  2458. dwRemain = MAX_PATH - 2;
  2459. // now walk through the environment string
  2460. pEnv = EnvStrings;
  2461. // the new environmet will be
  2462. pDst = pNewEnv;
  2463. while (*pEnv != UNICODE_NULL) {
  2464. // current directory environment has the form as:
  2465. // "=d:=d:\pathname" where d: is the drive designator.
  2466. if (pEnv[0] == L'=')
  2467. {
  2468. if ((pEnv[1] >= L'A' && pEnv[1] <= L'Z' || pEnv[1] >= L'a' && pEnv[1] <= L'z') &&
  2469. pEnv[2] == L':' && pEnv[3] == L'=' && wcslen(pEnv) >= 7)
  2470. {
  2471. // hack hack!!!!
  2472. // if the path points to the root directory,
  2473. // bypass the conversion. Dos or Wow keeps current directory
  2474. // for every valid drive. If we do the conversion for
  2475. // every current directory, it could take several
  2476. // seconds on removable drives, especially, on
  2477. // floppy drives.
  2478. if (pEnv[7] == UNICODE_NULL &&
  2479. (pEnv[6] == L'\\' || pEnv[6] == L'/') &&
  2480. pEnv[5] == L':' &&
  2481. (pEnv[4] >= L'A' && pEnv[4] <= L'Z' ||
  2482. pEnv[4] >= L'a' && pEnv[4] <= L'z'))
  2483. {
  2484. NameType = ENV_NAME_TYPE_NO_PATH;
  2485. }
  2486. else
  2487. {
  2488. // copy "=N:=", where N is the drive letter
  2489. *pDst++ = *pEnv++;*pDst++ = *pEnv++;
  2490. *pDst++ = *pEnv++;*pDst++ = *pEnv++;
  2491. NameType = ENV_NAME_TYPE_SINGLE_PATH;
  2492. }
  2493. }
  2494. else {
  2495. // a weird environment was detected.
  2496. // treat it as no path
  2497. NameType = ENV_NAME_TYPE_NO_PATH;
  2498. }
  2499. }
  2500. else {
  2501. pTmp = pEnv;
  2502. // copy down the name and the '='
  2503. while (*pEnv != UNICODE_NULL && (*pDst++ = *pEnv++) != L'=')
  2504. ;
  2505. NameType = BaseGetEnvNameType_U(pTmp, (DWORD)(pEnv - pTmp) - 1);
  2506. }
  2507. if (NameType == ENV_NAME_TYPE_NO_PATH) {
  2508. while ((*pDst++ = *pEnv++) != UNICODE_NULL)
  2509. ;
  2510. }
  2511. else if (NameType == ENV_NAME_TYPE_SINGLE_PATH) {
  2512. Length = wcslen(pEnv) + 1;
  2513. dw = GetShortPathNameW(pEnv, pDst, Length + dwRemain);
  2514. // if the conversion failed, we simply pass down the original
  2515. // one no matter what the reason is. This is done because we
  2516. // are doing the environment strings.
  2517. if (dw == 0 || dw >= Length + dwRemain){
  2518. RtlMoveMemory(pDst, pEnv, Length * sizeof(WCHAR));
  2519. dw = Length - 1;
  2520. }
  2521. pDst += dw + 1;
  2522. pEnv += Length;
  2523. if (dw > Length)
  2524. dwRemain -= dw - Length;
  2525. }
  2526. else {
  2527. // multiple path name found.
  2528. // the character ';' is used for seperator
  2529. pTmp = pEnv;
  2530. while(*pEnv != UNICODE_NULL) {
  2531. if (*pEnv == L';') {
  2532. // length not include the ';'
  2533. Length = (DWORD)(pEnv - pTmp);
  2534. if (Length > 0) {
  2535. *pEnv = UNICODE_NULL;
  2536. dw = GetShortPathNameW(pTmp, pDst, Length + 1 + dwRemain);
  2537. // again, if the conversion failed, use the original one
  2538. if (dw == 0 || dw > Length + dwRemain) {
  2539. RtlMoveMemory(pDst, pTmp, Length * sizeof(WCHAR));
  2540. dw = Length;
  2541. }
  2542. pDst += dw;
  2543. *pDst++ = *pEnv++ = L';';
  2544. if (dw > Length)
  2545. dwRemain -= dw - Length;
  2546. }
  2547. // skip all consecutive ';'
  2548. while (*pEnv == L';')
  2549. *pDst++ = *pEnv++;
  2550. pTmp = pEnv;
  2551. }
  2552. else
  2553. pEnv++;
  2554. }
  2555. // convert the last one
  2556. if ((Length = (DWORD)(pEnv - pTmp)) != 0) {
  2557. dw = GetShortPathNameW(pTmp, pDst, Length+1 + dwRemain);
  2558. if (dw == 0 || dw > Length) {
  2559. RtlMoveMemory(pDst, pTmp, Length * sizeof(WCHAR));
  2560. dw = Length;
  2561. }
  2562. pDst += dw;
  2563. if (dw > Length)
  2564. dwRemain -= dw - Length;
  2565. }
  2566. *pDst++ = *pEnv++;
  2567. }
  2568. }
  2569. *pDst++ = UNICODE_NULL;
  2570. cchEnv = (ULONG)((ULONG_PTR)pDst - (ULONG_PTR)pNewEnv);
  2571. pUStringEnv->MaximumLength = pUStringEnv->Length = (USHORT)cchEnv;
  2572. pUStringEnv->Buffer = pNewEnv;
  2573. Status = RtlUnicodeStringToAnsiString(pAStringEnv,
  2574. pUStringEnv,
  2575. TRUE
  2576. );
  2577. if (!NT_SUCCESS(Status)) {
  2578. BaseSetLastNTError(Status);
  2579. } else {
  2580. pNewEnv = NULL;
  2581. bRet = TRUE;
  2582. }
  2583. bveTryExit:;
  2584. }
  2585. finally {
  2586. if (lpEnvironment == NULL && EnvStrings != NULL) {
  2587. RtlDestroyEnvironment(EnvStrings);
  2588. }
  2589. if (pNewEnv != NULL) {
  2590. pUStringEnv->Length = pUStringEnv->MaximumLength = 0;
  2591. pUStringEnv->Buffer = NULL;
  2592. pAStringEnv->Length = pAStringEnv->MaximumLength = 0;
  2593. pAStringEnv->Buffer = NULL;
  2594. EnvSize = 0;
  2595. Status = NtFreeVirtualMemory (NtCurrentProcess(),
  2596. &pNewEnv,
  2597. &EnvSize,
  2598. MEM_RELEASE);
  2599. ASSERT (NT_SUCCESS (Status));
  2600. }
  2601. }
  2602. return bRet;
  2603. }
  2604. /**
  2605. Destroy the environment block created by BaseCreateVDMEnvironment
  2606. Input: ANSI_STRING * pAnsiStringVDMEnv
  2607. Environment block in ANSI, should be freed via
  2608. RtlFreeAnsiString
  2609. UNICODE_STRING * pUnicodeStringEnv
  2610. Environment block in UNICODE. The Buffer should
  2611. be freed with RtlFreeHeap.
  2612. Output: should always be TRUE.
  2613. **/
  2614. BOOL
  2615. BaseDestroyVDMEnvironment(
  2616. ANSI_STRING *pAStringEnv,
  2617. UNICODE_STRING *pUStringEnv
  2618. )
  2619. {
  2620. if (pAStringEnv->Buffer)
  2621. RtlFreeAnsiString(pAStringEnv);
  2622. if (pUStringEnv->Buffer) {
  2623. NTSTATUS Status;
  2624. SIZE_T RegionSize;
  2625. //
  2626. // Free the specified environment variable block.
  2627. //
  2628. RegionSize = 0;
  2629. Status = NtFreeVirtualMemory( NtCurrentProcess(),
  2630. &pUStringEnv->Buffer,
  2631. &RegionSize,
  2632. MEM_RELEASE
  2633. );
  2634. }
  2635. return TRUE;
  2636. }
  2637. /**
  2638. This function returns the name type of the given environment variable name
  2639. The name type has three possibilities. Each one represents if the
  2640. given name can have pathnames as its value.
  2641. ENV_NAME_TYPE_NO_PATH: no pathname can be its value
  2642. ENV_NAME_TYPE_SINGLE_PATH: single pathname
  2643. ENV_NAME_MULTIPLE_PATH: multiple path
  2644. SIDE NOTE:
  2645. Currently, nt can not installed on a long path and it seems
  2646. that systemroot and windir are never be in long path.
  2647. **/
  2648. UINT
  2649. BaseGetEnvNameType_U(WCHAR * Name, DWORD NameLength)
  2650. {
  2651. // so far we only take care of five predefined names:
  2652. // PATH
  2653. // WINDIR and
  2654. // SYSTEMROOT.
  2655. // TEMP
  2656. // TMP
  2657. //
  2658. static ENV_INFO EnvInfoTable[STD_ENV_NAME_COUNT] = {
  2659. {ENV_NAME_TYPE_MULTIPLE_PATH, ENV_NAME_PATH_LEN, ENV_NAME_PATH},
  2660. {ENV_NAME_TYPE_SINGLE_PATH, ENV_NAME_WINDIR_LEN, ENV_NAME_WINDIR},
  2661. {ENV_NAME_TYPE_SINGLE_PATH, ENV_NAME_SYSTEMROOT_LEN, ENV_NAME_SYSTEMROOT},
  2662. {ENV_NAME_TYPE_MULTIPLE_PATH, ENV_NAME_TEMP_LEN, ENV_NAME_TEMP},
  2663. {ENV_NAME_TYPE_MULTIPLE_PATH, ENV_NAME_TMP_LEN, ENV_NAME_TMP}
  2664. };
  2665. UINT NameType;
  2666. int i;
  2667. NameType = ENV_NAME_TYPE_NO_PATH;
  2668. for (i = 0; i < STD_ENV_NAME_COUNT; i++) {
  2669. if (EnvInfoTable[i].NameLength == NameLength &&
  2670. !_wcsnicmp(EnvInfoTable[i].Name, Name, NameLength)) {
  2671. NameType = EnvInfoTable[i].NameType;
  2672. break;
  2673. }
  2674. }
  2675. return NameType;
  2676. }
  2677. DWORD
  2678. APIENTRY
  2679. GetLongPathNameA(
  2680. IN LPCSTR lpszShortPath,
  2681. IN LPSTR lpLongPath,
  2682. IN DWORD cchBuffer
  2683. )
  2684. {
  2685. UNICODE_STRING UString, UStringRet;
  2686. ANSI_STRING AString;
  2687. NTSTATUS Status;
  2688. LPWSTR lpLongPathW = NULL;
  2689. WCHAR TempPathW[MAX_PATH];
  2690. DWORD ReturnValue, ReturnValueW;
  2691. if (lpszShortPath == NULL) {
  2692. SetLastError(ERROR_INVALID_PARAMETER);
  2693. return 0;
  2694. }
  2695. AString.Buffer = NULL;
  2696. UString.Buffer = NULL;
  2697. ReturnValue = 0;
  2698. ReturnValueW = 0;
  2699. try {
  2700. if (!Basep8BitStringToDynamicUnicodeString(&UString, lpszShortPath )) {
  2701. goto glpTryExit;
  2702. }
  2703. // we have to get the real converted path in order to find out
  2704. // the required length. An UNICODE char does not necessarily convert
  2705. // to one ANSI char(A DBCS is basically TWO ANSI char!!!!!).
  2706. // First, we use the buffer allocated from the stack. If the buffer
  2707. // is too small, we then allocate it from heap.
  2708. // A check of (lpLongPathW && TempPathW != lpLongPathW) will reveal
  2709. // if we have allocated a buffer from heap and need to release it.
  2710. lpLongPathW = TempPathW;
  2711. ReturnValueW = GetLongPathNameW(UString.Buffer, lpLongPathW, sizeof(TempPathW) / sizeof(WCHAR));
  2712. if (ReturnValueW >= sizeof(TempPathW) / sizeof(WCHAR))
  2713. {
  2714. // the stack-based buffer is too small. Allocate a new buffer
  2715. // from heap.
  2716. lpLongPathW = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( VDM_TAG ),
  2717. ReturnValueW * sizeof(WCHAR)
  2718. );
  2719. if (lpLongPathW) {
  2720. ReturnValueW = GetLongPathNameW(UString.Buffer, lpLongPathW, ReturnValueW);
  2721. }
  2722. else {
  2723. ReturnValueW = 0;
  2724. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2725. }
  2726. }
  2727. if (ReturnValueW)
  2728. {
  2729. // we are here because we have something interesting left to do.
  2730. // Convert the UNICODE path name to ANSI(or OEM).
  2731. UString.MaximumLength = (USHORT)((ReturnValueW + 1) * sizeof(WCHAR));
  2732. UStringRet.Buffer = lpLongPathW;
  2733. UStringRet.Length = (USHORT)(ReturnValueW * sizeof(WCHAR));
  2734. Status = BasepUnicodeStringTo8BitString(&AString,
  2735. &UStringRet,
  2736. TRUE
  2737. );
  2738. if (!NT_SUCCESS(Status))
  2739. {
  2740. BaseSetLastNTError(Status);
  2741. ReturnValue=0;
  2742. goto glpTryExit;
  2743. }
  2744. // now AString.Length contains the size of the converted path
  2745. // name. If the caller provides enough buffer, copy the
  2746. // path name.
  2747. ReturnValue = AString.Length;
  2748. if (ARGUMENT_PRESENT(lpLongPath) && cchBuffer > ReturnValue)
  2749. {
  2750. RtlMoveMemory(lpLongPath, AString.Buffer, ReturnValue);
  2751. // terminate the buffer with NULL char.
  2752. lpLongPath[ReturnValue] = '\0';
  2753. }
  2754. else
  2755. {
  2756. // either the caller does not provide a buffer or
  2757. // the provided buffer is too small, return the required size,
  2758. // including the terminated null char.
  2759. ReturnValue++;
  2760. }
  2761. }
  2762. glpTryExit:;
  2763. }
  2764. finally {
  2765. if (UString.Buffer)
  2766. RtlFreeUnicodeString(&UString);
  2767. if (AString.Buffer)
  2768. RtlFreeAnsiString(&AString);
  2769. if (lpLongPathW && lpLongPathW != TempPathW)
  2770. RtlFreeHeap(RtlProcessHeap(), 0, lpLongPathW);
  2771. }
  2772. return ReturnValue;
  2773. }
  2774. DWORD
  2775. APIENTRY
  2776. GetLongPathNameW(
  2777. IN LPCWSTR lpszShortPath,
  2778. IN LPWSTR lpszLongPath,
  2779. IN DWORD cchBuffer
  2780. )
  2781. {
  2782. LPCWSTR pcs;
  2783. DWORD ReturnLen, Length;
  2784. LPWSTR pSrc, pSrcCopy, pFirst, pLast, Buffer, pDst;
  2785. WCHAR wch;
  2786. HANDLE FindHandle;
  2787. WIN32_FIND_DATAW FindData;
  2788. UINT PrevErrorMode;
  2789. if (!ARGUMENT_PRESENT(lpszShortPath)) {
  2790. SetLastError(ERROR_INVALID_PARAMETER);
  2791. return 0;
  2792. }
  2793. //
  2794. // override the error mode since we will be touching the media.
  2795. // This is to prevent file system's pop-up when the given path does not
  2796. // exist or the media is not available.
  2797. // we are doing this because we can not depend on the caller's current
  2798. // error mode. NOTE: the old error mode must be restored.
  2799. PrevErrorMode = SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
  2800. try {
  2801. Buffer = NULL;
  2802. pSrcCopy = NULL;
  2803. // first make sure the given path exist.
  2804. //
  2805. if (0xFFFFFFFF == GetFileAttributesW(lpszShortPath))
  2806. {
  2807. // last error has been set by GetFileAttributes
  2808. ReturnLen = 0;
  2809. goto glnTryExit;
  2810. }
  2811. pcs = SkipPathTypeIndicator_U(lpszShortPath);
  2812. if (!pcs || *pcs == UNICODE_NULL || !FindLFNorSFN_U((LPWSTR)pcs, &pFirst, &pLast, FALSE))
  2813. {
  2814. // The path is ok and does not need conversion at all.
  2815. // Check if we need to do copy
  2816. ReturnLen = wcslen(lpszShortPath);
  2817. if (cchBuffer > ReturnLen && ARGUMENT_PRESENT(lpszLongPath))
  2818. {
  2819. if (lpszLongPath != lpszShortPath)
  2820. RtlMoveMemory(lpszLongPath, lpszShortPath,
  2821. (ReturnLen + 1)* sizeof(WCHAR)
  2822. );
  2823. }
  2824. else {
  2825. // No buffer or buffer too small, the return size
  2826. // has to count the terminated NULL char
  2827. ReturnLen++;
  2828. }
  2829. goto glnTryExit;
  2830. }
  2831. // conversions are necessary, make a local copy of the string
  2832. // because we have to party on it.
  2833. ASSERT(!pSrcCopy);
  2834. Length = wcslen(lpszShortPath) + 1;
  2835. pSrcCopy = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( VDM_TAG ),
  2836. Length * sizeof(WCHAR)
  2837. );
  2838. if (!pSrcCopy) {
  2839. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2840. goto glnTryExit;
  2841. }
  2842. RtlMoveMemory(pSrcCopy, lpszShortPath, Length * sizeof(WCHAR));
  2843. // pFirst points to the first char of the very first SFN in the path
  2844. // pLast points to the char right after the last char of the very
  2845. // first SFN in the path. *pLast could be UNICODE_NULL
  2846. pFirst = pSrcCopy + (pFirst - lpszShortPath);
  2847. pLast = pSrcCopy + (pLast - lpszShortPath);
  2848. //
  2849. // We allow lpszShortPath be overlapped with lpszLongPath so
  2850. // allocate a local buffer if necessary:
  2851. // (1) the caller does provide a legitimate buffer and
  2852. // (2) the buffer overlaps with lpszShortName
  2853. pDst = lpszLongPath;
  2854. if (cchBuffer && ARGUMENT_PRESENT(lpszLongPath) &&
  2855. (lpszLongPath >= lpszShortPath && lpszLongPath < lpszShortPath + Length ||
  2856. lpszLongPath < lpszShortPath && lpszLongPath + cchBuffer >= lpszShortPath))
  2857. {
  2858. ASSERT(!Buffer);
  2859. Buffer = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( VDM_TAG ),
  2860. cchBuffer * sizeof(WCHAR));
  2861. if (!Buffer){
  2862. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2863. goto glnTryExit;
  2864. }
  2865. pDst = Buffer;
  2866. }
  2867. pSrc = pSrcCopy;
  2868. ReturnLen = 0;
  2869. do {
  2870. // there are three pointers involve in the conversion loop:
  2871. // pSrc, pFirst and pLast. Their relationship
  2872. // is:
  2873. //
  2874. // "c:\long~1.1\\foo.bar\\long~2.2\\bar"
  2875. // ^ ^ ^ ^
  2876. // | | | |
  2877. // | pSrc pFirst pLast
  2878. // pSrcCopy
  2879. //
  2880. // pSrcCopy always points to the very first char of the entire
  2881. // path.
  2882. //
  2883. // chars between pSrc(included) and pFirst(not included)
  2884. // do not need conversion so we simply copy them.
  2885. // chars between pFirst(included) and pLast(not included)
  2886. // need conversion.
  2887. //
  2888. Length = (ULONG)(pFirst - pSrc);
  2889. ReturnLen += Length;
  2890. if (Length && cchBuffer > ReturnLen && ARGUMENT_PRESENT(lpszShortPath))
  2891. {
  2892. RtlMoveMemory(pDst, pSrc, Length * sizeof(WCHAR));
  2893. pDst += Length;
  2894. }
  2895. // now try to convert the name, chars between pFirst and (pLast - 1)
  2896. wch = *pLast;
  2897. *pLast = UNICODE_NULL;
  2898. FindHandle = FindFirstFileW(pSrcCopy, &FindData);
  2899. *pLast = wch;
  2900. if (FindHandle != INVALID_HANDLE_VALUE){
  2901. FindClose(FindHandle);
  2902. // if no long name, copy the original name
  2903. // starts with pFirst(included) and ends with pLast(excluded)
  2904. if (!(Length = wcslen(FindData.cFileName)))
  2905. Length = (ULONG)(pLast - pFirst);
  2906. else
  2907. pFirst = FindData.cFileName;
  2908. ReturnLen += Length;
  2909. if (cchBuffer > ReturnLen && ARGUMENT_PRESENT(lpszLongPath))
  2910. {
  2911. RtlMoveMemory(pDst, pFirst, Length * sizeof(WCHAR));
  2912. pDst += Length;
  2913. }
  2914. }
  2915. else {
  2916. // invalid path, reset the length, mark the error and
  2917. // bail out of the loop. We will be copying the source
  2918. // to destination later.
  2919. //
  2920. ReturnLen = 0;
  2921. break;
  2922. }
  2923. pSrc = pLast;
  2924. if (*pSrc == UNICODE_NULL)
  2925. break;
  2926. } while (FindLFNorSFN_U(pSrc, &pFirst, &pLast, FALSE));
  2927. if (ReturnLen) {
  2928. //copy the rest of the path from pSrc. This may only contain
  2929. //a single NULL char
  2930. Length = wcslen(pSrc);
  2931. ReturnLen += Length;
  2932. if (cchBuffer > ReturnLen && ARGUMENT_PRESENT(lpszLongPath))
  2933. {
  2934. RtlMoveMemory(pDst, pSrc, (Length + 1) * sizeof(WCHAR));
  2935. if (Buffer)
  2936. RtlMoveMemory(lpszLongPath, Buffer, (ReturnLen + 1) * sizeof(WCHAR));
  2937. }
  2938. else
  2939. ReturnLen++;
  2940. }
  2941. glnTryExit:
  2942. ;
  2943. }
  2944. finally {
  2945. if (pSrcCopy)
  2946. RtlFreeHeap(RtlProcessHeap(), 0, pSrcCopy);
  2947. if (Buffer)
  2948. RtlFreeHeap(RtlProcessHeap(), 0, Buffer);
  2949. }
  2950. // restore error mode.
  2951. SetErrorMode(PrevErrorMode);
  2952. return ReturnLen;
  2953. }
  2954. /**
  2955. Search for SFN(Short File Name) or LFN(Long File Name) in the
  2956. given path depends on FindLFN.
  2957. Input: LPWSTR Path
  2958. The given path name. Does not have to be fully qualified.
  2959. However, path type separaters are not allowed.
  2960. LPWSTR* ppFirst
  2961. To return the pointer points to the first char
  2962. of the name found.
  2963. LPWSTR* ppLast
  2964. To return the pointer points the char right after
  2965. the last char of the name found.
  2966. BOOL FindLFN
  2967. TRUE to search for LFN, otherwise, search for SFN
  2968. Output:
  2969. TRUE
  2970. if the target file name type is found, ppFirst and
  2971. ppLast are filled with pointers.
  2972. FALSE
  2973. if the target file name type not found.
  2974. Remark: "\\." and "\\.." are special cases. When encountered, they
  2975. are ignored and the function continue to search
  2976. **/
  2977. BOOL
  2978. FindLFNorSFN_U(
  2979. LPWSTR Path,
  2980. LPWSTR* ppFirst,
  2981. LPWSTR* ppLast,
  2982. BOOL FindLFN
  2983. )
  2984. {
  2985. LPWSTR pFirst, pLast;
  2986. BOOL TargetFound;
  2987. ASSERT(Path);
  2988. pFirst = Path;
  2989. TargetFound = FALSE;
  2990. while(TRUE) {
  2991. //skip over leading path separator
  2992. // it is legal to have multiple path separators in between
  2993. // name such as "foobar\\\\\\multiplepathchar"
  2994. while (*pFirst != UNICODE_NULL && (*pFirst == L'\\' || *pFirst == L'/'))
  2995. pFirst++;
  2996. if (*pFirst == UNICODE_NULL)
  2997. break;
  2998. pLast = pFirst + 1;
  2999. while (*pLast != UNICODE_NULL && *pLast != L'\\' && *pLast != L'/')
  3000. pLast++;
  3001. if (FindLFN)
  3002. TargetFound = !IsShortName_U(pFirst, (int)(pLast - pFirst));
  3003. else
  3004. TargetFound = !IsLongName_U(pFirst, (int)(pLast - pFirst));
  3005. if (TargetFound) {
  3006. if(ppFirst && ppLast) {
  3007. *ppFirst = pFirst;
  3008. // pLast point to the last char of the path/file name
  3009. *ppLast = pLast;
  3010. }
  3011. break;
  3012. }
  3013. if (*pLast == UNICODE_NULL)
  3014. break;
  3015. pFirst = pLast + 1;
  3016. }
  3017. return TargetFound;
  3018. }
  3019. LPCWSTR
  3020. SkipPathTypeIndicator_U(
  3021. LPCWSTR Path
  3022. )
  3023. {
  3024. RTL_PATH_TYPE RtlPathType;
  3025. LPCWSTR pFirst;
  3026. DWORD Count;
  3027. RtlPathType = RtlDetermineDosPathNameType_U(Path);
  3028. switch (RtlPathType) {
  3029. // form: "\\server_name\share_name\rest_of_the_path"
  3030. case RtlPathTypeUncAbsolute:
  3031. case RtlPathTypeLocalDevice:
  3032. pFirst = Path + 2;
  3033. Count = 2;
  3034. // guard for UNICODE_NULL is necessary because
  3035. // RtlDetermineDosPathNameType_U doesn't really
  3036. // verify an UNC name.
  3037. while (Count && *pFirst != UNICODE_NULL) {
  3038. if (*pFirst == L'\\' || *pFirst == L'/')
  3039. Count--;
  3040. pFirst++;
  3041. }
  3042. break;
  3043. // form: "\\."
  3044. case RtlPathTypeRootLocalDevice:
  3045. pFirst = NULL;
  3046. break;
  3047. // form: "D:\rest_of_the_path"
  3048. case RtlPathTypeDriveAbsolute:
  3049. pFirst = Path + 3;
  3050. break;
  3051. // form: "D:rest_of_the_path"
  3052. case RtlPathTypeDriveRelative:
  3053. pFirst = Path + 2;
  3054. break;
  3055. // form: "\rest_of_the_path"
  3056. case RtlPathTypeRooted:
  3057. pFirst = Path + 1;
  3058. break;
  3059. // form: "rest_of_the_path"
  3060. case RtlPathTypeRelative:
  3061. pFirst = Path;
  3062. break;
  3063. default:
  3064. pFirst = NULL;
  3065. break;
  3066. }
  3067. return pFirst;
  3068. }
  3069. /**
  3070. This function determines if the given name is a valid short name.
  3071. This function only does "obvious" testing since there are not precise
  3072. ways to cover all the file systems(each file system has its own
  3073. file name domain(for example, FAT allows all extended chars and space char
  3074. while NTFS **may** not).
  3075. The main purpose is to help the caller decide if a long to short name
  3076. conversion is necessary. When in doubt, this function simply tells the
  3077. caller that the given name is NOT a short name so that caller would
  3078. do whatever it takes to convert the name.
  3079. This function applies strict rules in deciding if the given name
  3080. is a valid short name. For example, a name containing any extended chars
  3081. is treated as invalid; a name with embedded space chars is also treated
  3082. as invalid.
  3083. A name is a valid short name if ALL the following conditions are met:
  3084. (1). total length <= 13.
  3085. (2). 0 < base name length <= 8.
  3086. (3). extention name length <= 3.
  3087. (4). only one '.' is allowed and must not be the first char.
  3088. (5). every char must be legal defined by the IllegalMask array.
  3089. null path, "." and ".." are treated valid.
  3090. Input: LPCWSTR Name - points to the name to be checked. It does not
  3091. have to be NULL terminated.
  3092. int Length - Length of the name, not including teminated NULL char.
  3093. output: TRUE - if the given name is a short file name.
  3094. FALSE - if the given name is not a short file name
  3095. **/
  3096. // bit set -> char is illegal
  3097. DWORD IllegalMask[] =
  3098. {
  3099. // code 0x00 - 0x1F --> all illegal
  3100. 0xFFFFFFFF,
  3101. // code 0x20 - 0x3f --> 0x20,0x22,0x2A-0x2C,0x2F and 0x3A-0x3F are illegal
  3102. 0xFC009C05,
  3103. // code 0x40 - 0x5F --> 0x5B-0x5D are illegal
  3104. 0x38000000,
  3105. // code 0x60 - 0x7F --> 0x7C is illegal
  3106. 0x10000000
  3107. };
  3108. BOOL
  3109. IsShortName_U(
  3110. LPCWSTR Name,
  3111. int Length
  3112. )
  3113. {
  3114. int Index;
  3115. BOOL ExtensionFound;
  3116. DWORD dwStatus;
  3117. UNICODE_STRING UnicodeName;
  3118. ANSI_STRING AnsiString;
  3119. UCHAR AnsiBuffer[MAX_PATH];
  3120. UCHAR Char;
  3121. ASSERT(Name);
  3122. // total length must less than 13(8.3 = 8 + 1 + 3 = 12)
  3123. if (Length > 12)
  3124. return FALSE;
  3125. // "" or "." or ".."
  3126. if (!Length)
  3127. return TRUE;
  3128. if (L'.' == *Name)
  3129. {
  3130. // "." or ".."
  3131. if (1 == Length || (2 == Length && L'.' == Name[1]))
  3132. return TRUE;
  3133. else
  3134. // '.' can not be the first char(base name length is 0)
  3135. return FALSE;
  3136. }
  3137. UnicodeName.Buffer = (LPWSTR)Name;
  3138. UnicodeName.Length =
  3139. UnicodeName.MaximumLength = (USHORT)(Length * sizeof(WCHAR));
  3140. AnsiString.Buffer = AnsiBuffer;
  3141. AnsiString.Length = 0;
  3142. AnsiString.MaximumLength = MAX_PATH; // make a dangerous assumption
  3143. dwStatus = BasepUnicodeStringTo8BitString(&AnsiString,
  3144. &UnicodeName,
  3145. FALSE);
  3146. if (! NT_SUCCESS(dwStatus)) {
  3147. return(FALSE);
  3148. }
  3149. // all trivial cases are tested, now we have to walk through the name
  3150. ExtensionFound = FALSE;
  3151. for (Index = 0; Index < AnsiString.Length; Index++)
  3152. {
  3153. Char = AnsiString.Buffer[Index];
  3154. // Skip over and Dbcs characters
  3155. if (IsDBCSLeadByte(Char)) {
  3156. //
  3157. // 1) if we're looking at base part ( !ExtensionPresent ) and the 8th byte
  3158. // is in the dbcs leading byte range, it's error ( Index == 7 ). If the
  3159. // length of base part is more than 8 ( Index > 7 ), it's definitely error.
  3160. //
  3161. // 2) if the last byte ( Index == DbcsName.Length - 1 ) is in the dbcs leading
  3162. // byte range, it's error
  3163. //
  3164. if ((!ExtensionFound && (Index >= 7)) ||
  3165. (Index == AnsiString.Length - 1)) {
  3166. return FALSE;
  3167. }
  3168. Index += 1;
  3169. continue;
  3170. }
  3171. // make sure the char is legal
  3172. if (Char > 0x7F || IllegalMask[Char / 32] & (1 << (Char % 32)))
  3173. return FALSE;
  3174. if ('.' == Char)
  3175. {
  3176. // (1) can have only one '.'
  3177. // (2) can not have more than 3 chars following.
  3178. if (ExtensionFound || Length - (Index + 1) > 3)
  3179. {
  3180. return FALSE;
  3181. }
  3182. ExtensionFound = TRUE;
  3183. }
  3184. // base length > 8 chars
  3185. if (Index >= 8 && !ExtensionFound)
  3186. return FALSE;
  3187. }
  3188. return TRUE;
  3189. }
  3190. /**
  3191. This function determines if the given name is a valid long name.
  3192. This function only does "obvious" testing since there are not precise
  3193. ways to cover all the file systems(each file system has its own
  3194. file name domain(for example, FAT allows all extended chars and space char
  3195. while NTFS **may** not)
  3196. This function helps the caller to determine if a short to long name
  3197. conversion is necessary. When in doubt, this function simply tells the
  3198. caller that the given name is NOT a long name so that caller would
  3199. do whatever it takes to convert the name.
  3200. A name is a valid long name if one of the following conditions is met:
  3201. (1). total length >= 13.
  3202. (2). 0 == base name length || base name length > 8.
  3203. (3). extention name length > 3.
  3204. (4). '.' is the first char.
  3205. (5). muitlple '.'
  3206. null path, "." and ".." are treat as valid long name.
  3207. Input: LPCWSTR Name - points to the name to be checked. It does not
  3208. have to be NULL terminated.
  3209. int Length - Length of the name, not including teminated NULL char.
  3210. output: TRUE - if the given name is a long file name.
  3211. FALSE - if the given name is not a long file name
  3212. **/
  3213. BOOL
  3214. IsLongName_U(
  3215. LPCWSTR Name,
  3216. int Length
  3217. )
  3218. {
  3219. int Index;
  3220. BOOL ExtensionFound;
  3221. // (1) NULL path
  3222. // (2) total length > 12
  3223. // (3) . is the first char (cover "." and "..")
  3224. if (!Length || Length > 12 || L'.' == *Name)
  3225. return TRUE;
  3226. ExtensionFound = FALSE;
  3227. for (Index = 0; Index < Length; Index++)
  3228. {
  3229. if (L'.' == Name[Index])
  3230. {
  3231. // multiple . or extension longer than 3
  3232. if (ExtensionFound || Length - (Index + 1) > 3)
  3233. return TRUE;
  3234. ExtensionFound = TRUE;
  3235. }
  3236. // base length longer than 8
  3237. if (Index >= 8 && !ExtensionFound)
  3238. return TRUE;
  3239. }
  3240. return FALSE;
  3241. }