Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

8891 lines
273 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. process.c
  5. Abstract:
  6. This module implements Win32 Thread Object APIs
  7. Author:
  8. Mark Lucovsky (markl) 21-Sep-1990
  9. Revision History:
  10. --*/
  11. #include "basedll.h"
  12. #pragma hdrstop
  13. #include <winsafer.h>
  14. #include <softpub.h>
  15. #define MEDIUM_PATH (64)
  16. static WCHAR pszFullQualifiedSetupEXE[100];
  17. static PWSTR g_pszFullQualifiedSetupEXE = NULL;
  18. RTL_QUERY_REGISTRY_TABLE BasepAppCertTable[] = {
  19. {(PRTL_QUERY_REGISTRY_ROUTINE )BasepConfigureAppCertDlls, RTL_QUERY_REGISTRY_SUBKEY,
  20. L"AppCertDlls", &BasepAppCertDllsList,
  21. REG_NONE, NULL, 0},
  22. {NULL, 0,
  23. NULL, NULL,
  24. REG_NONE, NULL, 0}
  25. };
  26. #define IsEmbeddedNT() (BOOLEAN)(USER_SHARED_DATA->SuiteMask & (1 << EmbeddedNT))
  27. BOOL
  28. BuildSubSysCommandLine(
  29. LPWSTR SubSysName,
  30. LPCWSTR lpApplicationName,
  31. LPCWSTR lpCommandLine,
  32. PUNICODE_STRING SubSysCommandLine
  33. );
  34. PVOID
  35. BasepIsRealtimeAllowed(
  36. BOOLEAN LeaveEnabled
  37. );
  38. #ifdef WX86
  39. PWCHAR
  40. BasepWx86KnownExe(
  41. LPCWSTR ExeName
  42. )
  43. /*++
  44. Routine Description:
  45. Checks for Wx86 Known Exes which wx86 applications must run
  46. compatible binaries. We currently have Known exes for
  47. regedit.exe, regsvr32.exe, and msiexec.exe
  48. Arguments:
  49. ExeName - name to check for match.
  50. Return Value:
  51. if the name needs to be swapped, a buffer is allocated off
  52. of the process heap filled with new name and returned.
  53. otherwise NULL is returned.
  54. --*/
  55. {
  56. UNICODE_STRING NameUnicode;
  57. PWCHAR pwch, pwcNewName = NULL;
  58. //
  59. // Compare the base name, and see if its regedit.exe
  60. // Note that we are expecting a fully qualified path name.
  61. //
  62. pwch = wcsrchr(ExeName, L'\\');
  63. if (pwch && *pwch++ && *pwch ) {
  64. if (!_wcsicmp(pwch, L"regedit.exe")) {
  65. pwcNewName = L"\\wiregedt.exe";
  66. } else {
  67. if (!_wcsicmp(pwch, L"regsvr32.exe")) {
  68. pwcNewName = L"\\regsvr32.exe";
  69. } else {
  70. if (!_wcsicmp(pwch, L"msiexec.exe")) {
  71. pwcNewName = L"\\msiexec.exe";
  72. } else {
  73. return NULL;
  74. }
  75. }
  76. }
  77. } else {
  78. return NULL;
  79. }
  80. //
  81. // It matches, so formulate new name
  82. //
  83. pwch = RtlAllocateHeap(RtlProcessHeap(),
  84. MAKE_TAG( TMP_TAG ),
  85. MAX_PATH + sizeof(WCHAR)
  86. );
  87. if (!pwch) {
  88. return NULL;
  89. }
  90. NameUnicode.Buffer = pwch;
  91. NameUnicode.MaximumLength = MAX_PATH + sizeof(WCHAR);
  92. RtlCopyUnicodeString(&NameUnicode, &BaseWindowsSystemDirectory);
  93. if (NameUnicode.Buffer[(NameUnicode.Length>>1)-1] == (WCHAR)'\\') {
  94. NameUnicode.Buffer[(NameUnicode.Length>>1)-1] = UNICODE_NULL;
  95. NameUnicode.Length -= sizeof(WCHAR);
  96. }
  97. RtlAppendUnicodeToString(&NameUnicode, pwcNewName);
  98. return pwch;
  99. }
  100. #endif
  101. BOOL
  102. BasepIsSetupInvokedByWinLogon(
  103. PCWSTR pwszFullQualifiedApplicationPath)
  104. {
  105. if (GetModuleHandle(TEXT("winlogon.EXE"))) // winlogon is running
  106. {
  107. //
  108. // set the global pointer g_pszFullQualifiedSetupEXE
  109. //
  110. if (g_pszFullQualifiedSetupEXE == NULL)
  111. {
  112. //
  113. // we assume that the name of setup program is "setup.exe". This may change in the future
  114. // and the best way is to query RegistryValue of \\HKLM\SYSTEM\Setup\CmdLine
  115. // and get the firstpart of the value, attach ".exe" if it does not have an ext
  116. //
  117. LPWSTR pwszSetupExe = L"setup.exe";
  118. ULONG ulReservedLength = sizeof(WCHAR) + // trailing backSlash
  119. wcslen(pwszSetupExe); //trailing NULL is included
  120. ULONG ulSizeOfBuf = sizeof(pszFullQualifiedSetupEXE)/sizeof(WCHAR);
  121. ULONG ulLength = GetSystemDirectoryW(pszFullQualifiedSetupEXE, ulSizeOfBuf - ulReservedLength);
  122. //
  123. // very unlikely failed because of UNSUFFICIENT_BUFFER_SIZE
  124. // but kind of buggy here
  125. //
  126. if ((ulLength == 0) || (ulLength > ulSizeOfBuf - ulReservedLength))
  127. return FALSE;
  128. if (pszFullQualifiedSetupEXE[ulLength] != L'\\') // set trailing slash
  129. pszFullQualifiedSetupEXE[ulLength] = L'\\';
  130. wcscpy(pszFullQualifiedSetupEXE + ulLength, pwszSetupExe);
  131. g_pszFullQualifiedSetupEXE = pszFullQualifiedSetupEXE;
  132. }
  133. if (_wcsicmp(pwszFullQualifiedApplicationPath, g_pszFullQualifiedSetupEXE) == 0)
  134. return TRUE;
  135. }
  136. return FALSE;
  137. }
  138. PFNWAITFORINPUTIDLE UserWaitForInputIdleRoutine = NULL;
  139. #define DEFAULT_WAIT_FOR_INPUT_IDLE_TIMEOUT 30000
  140. BOOL
  141. BasepIsImageVersionOk(
  142. IN ULONG ImageMajorVersion,
  143. IN ULONG ImageMinorVersion
  144. )
  145. {
  146. //
  147. // Make sure image is at least 3.10
  148. //
  149. if ( ( ImageMajorVersion < 3 ) ||
  150. ( ImageMajorVersion == 3 && ImageMinorVersion < 10 ) ) {
  151. return FALSE;
  152. }
  153. //
  154. // And not greater than what we are
  155. //
  156. if ( ( ImageMajorVersion > USER_SHARED_DATA->NtMajorVersion ) ||
  157. ( ImageMajorVersion == USER_SHARED_DATA->NtMajorVersion &&
  158. ImageMinorVersion > USER_SHARED_DATA->NtMinorVersion
  159. )
  160. ) {
  161. return FALSE;
  162. }
  163. return TRUE;
  164. }
  165. NTSTATUS
  166. BasepIsProcessAllowed(LPCWSTR lpApplicationName)
  167. /*++
  168. Validate that the image lpApplicationName
  169. is listed in certified/authorized executables
  170. --*/
  171. {
  172. NTSTATUS Status;
  173. UNICODE_STRING BackupUnicodeString;
  174. PUNICODE_STRING pStaticString;
  175. LPWSTR DllNameBuf;
  176. ULONG BackupStringSize;
  177. PLIST_ENTRY Head, Next;
  178. static BOOL fInitialized = FALSE;
  179. static BOOL fCertifyEnabled = TRUE;
  180. static NTSTATUS CertifyErrorCode = STATUS_ACCESS_DENIED;
  181. static HINSTANCE hEmbeddedCertDll = NULL;
  182. static NTSTATUS (WINAPI *fEmbeddedCertFunc)(LPCWSTR lpApplicationName) = NULL;
  183. //
  184. // Initialization occures when this routine is first entered. After init
  185. // is done, fInitialized is TRUE, and one of the following must hold
  186. // - Certification is OFF, and dwCertifyErrorCode indicates whether this
  187. // is because no certification is needed, or due to an initialization
  188. // error.
  189. // - Certification is ON, call the EmbeddedNT and/or Plugin dlls to verify
  190. //
  191. InitDone:
  192. if ( fInitialized ) {
  193. PBASEP_APPCERT_ENTRY p;
  194. NTSTATUS tempStatus;
  195. ULONG Reason;
  196. if ( !fCertifyEnabled ) {
  197. return CertifyErrorCode;
  198. }
  199. ASSERT( fEmbeddedCertFunc || !IsListEmpty( &BasepAppCertDllsList ) );
  200. Status = STATUS_SUCCESS;
  201. if ( fEmbeddedCertFunc ) {
  202. Status = (*fEmbeddedCertFunc)( lpApplicationName );
  203. return Status;
  204. }
  205. Head = &BasepAppCertDllsList;
  206. Reason = APPCERT_CREATION_ALLOWED;
  207. //
  208. // Two phase notification scheme. In the first phase we get every dll to
  209. // vote whether the process should be created. In the second phase we
  210. // let them know if the process is going to get created or not.
  211. //
  212. //
  213. // Phase 1 : Voting
  214. //
  215. Next = Head->Flink;
  216. while (Next != Head) {
  217. p = CONTAINING_RECORD( Next,
  218. BASEP_APPCERT_ENTRY,
  219. Entry
  220. );
  221. ASSERT(p->fPluginCertFunc != NULL);
  222. tempStatus = (*(p->fPluginCertFunc))( lpApplicationName, APPCERT_IMAGE_OK_TO_RUN );
  223. if (!NT_SUCCESS(tempStatus)) {
  224. Status = tempStatus;
  225. Reason = APPCERT_CREATION_DENIED;
  226. }
  227. Next = Next->Flink;
  228. }
  229. //
  230. // Phase 2: Announce Results
  231. //
  232. Next = Head->Flink;
  233. while (Next != Head) {
  234. p = CONTAINING_RECORD( Next,
  235. BASEP_APPCERT_ENTRY,
  236. Entry
  237. );
  238. ASSERT(p->fPluginCertFunc != NULL);
  239. (*(p->fPluginCertFunc))( lpApplicationName, Reason );
  240. Next = Next->Flink;
  241. }
  242. return Status;
  243. }
  244. //
  245. // Start initialization
  246. //
  247. RtlEnterCriticalSection(&gcsAppCert);
  248. //
  249. // check if someone did init while we waited on the crit sect
  250. //
  251. if (fInitialized) {
  252. goto Initialized;
  253. }
  254. //
  255. // Initialize locals
  256. //
  257. Status = STATUS_SUCCESS;
  258. RtlZeroMemory( &BackupUnicodeString, sizeof(BackupUnicodeString) );
  259. DllNameBuf = NULL;
  260. //
  261. // check if this is EmbeddedNT
  262. //
  263. if (IsEmbeddedNT()) {
  264. HINSTANCE hDll;
  265. ULONG Length;
  266. //
  267. // LoadDll calls a routine that uses &NtCurrentTeb()->StaticUnicodeString
  268. // When we are called from CreateProcessA (e.g. the debuggers), the
  269. // application command line is stored in this area. Therefore,
  270. // we need to save / restore it around the call to LoadLibrary
  271. //
  272. pStaticString = &NtCurrentTeb()->StaticUnicodeString;
  273. BackupUnicodeString.MaximumLength = pStaticString->MaximumLength;
  274. BackupUnicodeString.Length = pStaticString->Length;
  275. BackupStringSize = pStaticString->Length + sizeof(UNICODE_NULL);
  276. if (BackupStringSize > BackupUnicodeString.MaximumLength) {
  277. BackupStringSize = BackupUnicodeString.MaximumLength;
  278. }
  279. BackupUnicodeString.Buffer = RtlAllocateHeap(RtlProcessHeap(),
  280. MAKE_TAG( TMP_TAG ),
  281. BackupStringSize);
  282. if (BackupUnicodeString.Buffer == NULL) {
  283. Status = STATUS_NO_MEMORY;
  284. goto Cleanup;
  285. }
  286. RtlMoveMemory(BackupUnicodeString.Buffer,
  287. pStaticString->Buffer,
  288. BackupStringSize);
  289. //
  290. // build the full path DLL name
  291. //
  292. DllNameBuf = RtlAllocateHeap(RtlProcessHeap(),
  293. MAKE_TAG( TMP_TAG ),
  294. (MAX_PATH + 1) << 1);
  295. if (DllNameBuf == NULL) {
  296. Status = STATUS_NO_MEMORY;
  297. goto Cleanup;
  298. }
  299. Length = GetSystemDirectoryW(
  300. DllNameBuf,
  301. MAX_PATH - 1 - sizeof(CERTAPP_EMBEDDED_DLL_NAME)/2);
  302. if (!Length ||
  303. Length > (MAX_PATH - 1 - sizeof(CERTAPP_EMBEDDED_DLL_NAME)/2) ) {
  304. Status = STATUS_UNSUCCESSFUL;
  305. goto Cleanup;
  306. }
  307. if (DllNameBuf[ Length - 1 ] != L'\\') {
  308. DllNameBuf[ Length++ ] = L'\\';
  309. }
  310. RtlMoveMemory(
  311. &DllNameBuf[ Length ],
  312. CERTAPP_EMBEDDED_DLL_NAME,
  313. sizeof(CERTAPP_EMBEDDED_DLL_NAME));
  314. hDll = LoadLibraryW( DllNameBuf );
  315. if (hDll == NULL) {
  316. //
  317. // The library was not loaded, return.
  318. //
  319. Status = STATUS_UNSUCCESSFUL;
  320. goto Cleanup;
  321. }
  322. //
  323. // get the entry point
  324. //
  325. fEmbeddedCertFunc = (NTSTATUS (WINAPI *)(LPCWSTR))
  326. GetProcAddress(hDll,
  327. CERTAPP_EMBEDDED_DLL_EP
  328. );
  329. if (fEmbeddedCertFunc == NULL) {
  330. //
  331. // Unable to retrieve routine address, fail.
  332. //
  333. Status = STATUS_UNSUCCESSFUL;
  334. }
  335. goto Cleanup;
  336. } else {
  337. //
  338. // On non-embedded NT
  339. // Do a quick test of top level key to find out if app cert is on.
  340. //
  341. static const UNICODE_STRING UnicodeString =
  342. RTL_CONSTANT_STRING(CERTAPP_KEY_NAME);
  343. static const OBJECT_ATTRIBUTES obja =
  344. RTL_CONSTANT_OBJECT_ATTRIBUTES(&UnicodeString, OBJ_CASE_INSENSITIVE);
  345. HANDLE hKey;
  346. if ( !NT_SUCCESS(NtOpenKey(&hKey,
  347. KEY_QUERY_VALUE,
  348. (POBJECT_ATTRIBUTES) &obja))) {
  349. goto Cleanup;
  350. } else {
  351. NtClose(hKey);
  352. }
  353. }
  354. //
  355. // Backup static string if we haven't done so before. see comment above
  356. //
  357. if (BackupUnicodeString.Buffer == NULL) {
  358. pStaticString = &NtCurrentTeb()->StaticUnicodeString;
  359. BackupUnicodeString.MaximumLength = pStaticString->MaximumLength;
  360. BackupUnicodeString.Length = pStaticString->Length;
  361. BackupStringSize = pStaticString->Length + sizeof(UNICODE_NULL);
  362. if (BackupStringSize > BackupUnicodeString.MaximumLength) {
  363. BackupStringSize = BackupUnicodeString.MaximumLength;
  364. }
  365. BackupUnicodeString.Buffer = RtlAllocateHeap(RtlProcessHeap(),
  366. MAKE_TAG( TMP_TAG ),
  367. BackupStringSize);
  368. if (BackupUnicodeString.Buffer == NULL) {
  369. Status = STATUS_NO_MEMORY;
  370. goto Cleanup;
  371. }
  372. RtlMoveMemory(BackupUnicodeString.Buffer,
  373. pStaticString->Buffer,
  374. BackupStringSize);
  375. }
  376. //
  377. // load and initialize the list of certification DLLs
  378. //
  379. Status = RtlQueryRegistryValues( RTL_REGISTRY_CONTROL,
  380. L"Session Manager",
  381. BasepAppCertTable,
  382. NULL,
  383. NULL
  384. );
  385. if (!NT_SUCCESS(Status)) {
  386. if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
  387. //
  388. // If the registry Key is missing AppCert is turned off
  389. //
  390. Status = STATUS_SUCCESS;
  391. }
  392. }
  393. Cleanup:
  394. if (DllNameBuf) {
  395. RtlFreeHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG), DllNameBuf);
  396. }
  397. if (BackupUnicodeString.Buffer) {
  398. RtlMoveMemory(
  399. pStaticString->Buffer,
  400. BackupUnicodeString.Buffer,
  401. BackupStringSize);
  402. pStaticString->Length = BackupUnicodeString.Length;
  403. RtlFreeHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG), BackupUnicodeString.Buffer);
  404. }
  405. if (NT_SUCCESS( Status ) && (fEmbeddedCertFunc || !IsListEmpty( &BasepAppCertDllsList))) {
  406. fCertifyEnabled = TRUE;
  407. } else {
  408. fCertifyEnabled = FALSE;
  409. CertifyErrorCode = Status;
  410. }
  411. fInitialized = TRUE;
  412. Initialized:
  413. RtlLeaveCriticalSection(&gcsAppCert);
  414. goto InitDone;
  415. }
  416. BOOL
  417. IsShimInfrastructureDisabled(
  418. void
  419. )
  420. {
  421. static int g_nDisableShims = -1;
  422. // -1 means we didn't check for disabled shims yet
  423. // 0 means the shim infrastructure is enabled
  424. // 1 means the shim infrastructure is disabled
  425. static const UNICODE_STRING KeyNameAppCompat =
  426. RTL_CONSTANT_STRING(L"\\Registry\\MACHINE\\System\\CurrentControlSet\\Control\\Session Manager\\AppCompatibility");
  427. static const UNICODE_STRING ValueNameDisableShims =
  428. RTL_CONSTANT_STRING(L"DisableAppCompat");
  429. static const OBJECT_ATTRIBUTES objaAppCompat =
  430. RTL_CONSTANT_OBJECT_ATTRIBUTES(&KeyNameAppCompat, OBJ_CASE_INSENSITIVE);
  431. HANDLE hKey;
  432. BYTE ValueBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(DWORD)];
  433. PKEY_VALUE_PARTIAL_INFORMATION pKeyValueInformation =
  434. (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer;
  435. DWORD ValueLength;
  436. NTSTATUS Status;
  437. //
  438. // First see if we already checked the registry
  439. //
  440. if (g_nDisableShims == 1) {
  441. return TRUE;
  442. }
  443. if (g_nDisableShims == 0) {
  444. return FALSE;
  445. }
  446. //
  447. // Now see if the shim infrastructure is disabled for this machine
  448. //
  449. Status = NtOpenKey(&hKey, KEY_QUERY_VALUE, (POBJECT_ATTRIBUTES) &objaAppCompat);
  450. if (NT_SUCCESS(Status)) {
  451. Status = NtQueryValueKey(hKey,
  452. (PUNICODE_STRING) &ValueNameDisableShims,
  453. KeyValuePartialInformation,
  454. pKeyValueInformation,
  455. sizeof(ValueBuffer),
  456. &ValueLength);
  457. NtClose(hKey);
  458. if (NT_SUCCESS(Status) &&
  459. pKeyValueInformation->Type == REG_DWORD &&
  460. pKeyValueInformation->DataLength == sizeof(DWORD)) {
  461. if (*((PDWORD) pKeyValueInformation->Data) > 0) {
  462. g_nDisableShims = 1;
  463. return TRUE;
  464. }
  465. }
  466. }
  467. g_nDisableShims = 0;
  468. return FALSE;
  469. }
  470. //
  471. // the code below should never be called on non-386 platform
  472. //
  473. NTSTATUS
  474. BasepCheckBadapp(
  475. HANDLE hFile,
  476. WCHAR* pwszApplication, // IN
  477. WCHAR* pEnvironment, // IN
  478. PVOID* ppData, // OUT
  479. PDWORD pcbData, // OUT
  480. PVOID* ppSxsData, // OUT
  481. PDWORD pcbSxsData // OUT
  482. )
  483. {
  484. typedef BOOL (STDAPICALLTYPE *PFNCheckRunApp)(
  485. HANDLE FileHandle,
  486. WCHAR* pwszPath,
  487. WCHAR* pEnvironment,
  488. DWORD dwReason,
  489. PVOID* ppData,
  490. PDWORD pcbData,
  491. PVOID* ppDataSxs,
  492. PDWORD pcbDataSxs);
  493. NTSTATUS RetStatus;
  494. NTSTATUS Status;
  495. HANDLE ModuleHandle;
  496. static PFNCheckRunApp pfnCheckRunApp = NULL;
  497. PUNICODE_STRING pStaticString;
  498. UNICODE_STRING BackupUnicodeString;
  499. ULONG BackupStringSize;
  500. WCHAR Apphelp_dllBuffer[MAX_PATH];
  501. UNICODE_STRING Apphelp_dllPath;
  502. DWORD dwReason = 0; // reason for having avoided cache
  503. static const UNICODE_STRING Apphelp_dllModuleName = RTL_CONSTANT_STRING(L"\\system32\\Apphelp.dll");
  504. static const STRING CheckRunAppProcedureName = RTL_CONSTANT_STRING("ApphelpCheckRunApp");
  505. //
  506. // Do nothing if the shim infrastructure is disabled
  507. //
  508. if (IsShimInfrastructureDisabled()) {
  509. return STATUS_SUCCESS;
  510. }
  511. //
  512. // We can't re-enter this code even within the same thread.
  513. // Such an occasion is when apphelp needs to do ShellExecute
  514. // which comes back here -- clobbering our state
  515. //
  516. pStaticString = &NtCurrentTeb()->StaticUnicodeString;
  517. BackupUnicodeString.MaximumLength = pStaticString->MaximumLength;
  518. BackupUnicodeString.Length = pStaticString->Length;
  519. BackupStringSize = pStaticString->Length + sizeof(UNICODE_NULL);
  520. if (BackupStringSize > BackupUnicodeString.MaximumLength) {
  521. BackupStringSize = BackupUnicodeString.MaximumLength;
  522. }
  523. BackupUnicodeString.Buffer = RtlAllocateHeap(RtlProcessHeap(),
  524. MAKE_TAG(TMP_TAG),
  525. BackupStringSize);
  526. if (BackupUnicodeString.Buffer == NULL) {
  527. //
  528. // we failed to allocate memory to save the static string
  529. // return success and try to run an app
  530. //
  531. return STATUS_SUCCESS;
  532. }
  533. RtlMoveMemory(BackupUnicodeString.Buffer,
  534. pStaticString->Buffer,
  535. BackupStringSize);
  536. //
  537. // Check our internal cache -- no touching apphelp.dll before we check with the cache
  538. //
  539. if (BaseCheckAppcompatCache(pwszApplication, hFile, pEnvironment, &dwReason)) {
  540. RetStatus = STATUS_SUCCESS;
  541. //
  542. // we can't just return here since we need to restore the static
  543. // unicode string, so we go around the code that calls into apphelp
  544. //
  545. goto CheckDone;
  546. }
  547. if (pfnCheckRunApp == (PFNCheckRunApp)(LONG_PTR)-1) {
  548. // We've tried before and could not get the fn ptr
  549. RetStatus = STATUS_SUCCESS;
  550. goto CheckDone;
  551. }
  552. RtlEnterCriticalSection(&gcsAppCompat);
  553. if (NULL == pfnCheckRunApp) {
  554. //
  555. // BaseWindowsDirectory is the unicode string that houses windows directory
  556. //
  557. DWORD dwLength;
  558. WCHAR* pModuleName = Apphelp_dllModuleName.Buffer;
  559. dwLength = BaseWindowsDirectory.Length + Apphelp_dllModuleName.Length + sizeof(UNICODE_NULL);
  560. if (dwLength > sizeof(Apphelp_dllBuffer)) {
  561. Status = STATUS_BUFFER_TOO_SMALL; // error, we don't support case when windows dir + apphelp location > MAX_PATH
  562. }
  563. else {
  564. Apphelp_dllPath.Buffer = Apphelp_dllBuffer;
  565. Apphelp_dllPath.Length = 0;
  566. Apphelp_dllPath.MaximumLength = sizeof(Apphelp_dllBuffer);
  567. RtlCopyUnicodeString(&Apphelp_dllPath, &BaseWindowsDirectory);
  568. if (L'\\' == Apphelp_dllPath.Buffer[Apphelp_dllPath.Length/sizeof(WCHAR) - 1]) {
  569. ++pModuleName; // skip over the first backslash character
  570. }
  571. RtlAppendUnicodeToString(&Apphelp_dllPath, pModuleName);
  572. Status = LdrLoadDll(NULL,
  573. NULL,
  574. &Apphelp_dllPath,
  575. &ModuleHandle);
  576. }
  577. if (NT_SUCCESS(Status)) {
  578. // loaded apphelp, get proc
  579. Status = LdrGetProcedureAddress(ModuleHandle,
  580. &CheckRunAppProcedureName,
  581. 0,
  582. (PVOID*)&pfnCheckRunApp);
  583. if (!NT_SUCCESS(Status)) {
  584. //
  585. // Couldn't get the fn ptr. Make sure we won't try again
  586. //
  587. LdrUnloadDll(ModuleHandle);
  588. pfnCheckRunApp = (PFNCheckRunApp)(LONG_PTR)-1;
  589. }
  590. } else {
  591. //
  592. // No Apphelp.dll, so don't try again
  593. //
  594. pfnCheckRunApp = (PFNCheckRunApp)(LONG_PTR)-1;
  595. }
  596. }
  597. RtlLeaveCriticalSection(&gcsAppCompat);
  598. RetStatus = STATUS_SUCCESS;
  599. if (pfnCheckRunApp && (pfnCheckRunApp != (PFNCheckRunApp)(LONG_PTR)- 1)) {
  600. //
  601. // We have the proc here, do the checking
  602. //
  603. if (!pfnCheckRunApp(hFile,
  604. pwszApplication,
  605. pEnvironment,
  606. dwReason,
  607. ppData,
  608. pcbData,
  609. ppSxsData,
  610. pcbSxsData)) {
  611. RetStatus = STATUS_ACCESS_DENIED;
  612. }
  613. }
  614. CheckDone:
  615. //
  616. // Store appcompat data -- only returns something if we are running an app!
  617. //
  618. // now restore
  619. RtlMoveMemory(pStaticString->Buffer,
  620. BackupUnicodeString.Buffer,
  621. BackupStringSize);
  622. pStaticString->Length = BackupUnicodeString.Length;
  623. RtlFreeHeap(RtlProcessHeap(), MAKE_TAG(TMP_TAG), BackupUnicodeString.Buffer);
  624. return RetStatus;
  625. }
  626. BOOL
  627. WINAPI
  628. CreateProcessInternalA(
  629. HANDLE hUserToken,
  630. LPCSTR lpApplicationName,
  631. LPSTR lpCommandLine,
  632. LPSECURITY_ATTRIBUTES lpProcessAttributes,
  633. LPSECURITY_ATTRIBUTES lpThreadAttributes,
  634. BOOL bInheritHandles,
  635. DWORD dwCreationFlags,
  636. LPVOID lpEnvironment,
  637. LPCSTR lpCurrentDirectory,
  638. LPSTARTUPINFOA lpStartupInfo,
  639. LPPROCESS_INFORMATION lpProcessInformation,
  640. PHANDLE hRestrictedUserToken
  641. )
  642. /*++
  643. ANSI thunk to CreateProcessW
  644. --*/
  645. {
  646. NTSTATUS Status;
  647. PUNICODE_STRING CommandLine;
  648. UNICODE_STRING ApplicationName;
  649. UNICODE_STRING CurrentDirectory;
  650. STARTUPINFOW StartupInfo;
  651. ANSI_STRING AnsiString;
  652. UNICODE_STRING Unicode;
  653. UNICODE_STRING DynamicCommandLine;
  654. UNICODE_STRING NullUnicodeString;
  655. BOOL ReturnStatus;
  656. if (ARGUMENT_PRESENT (lpCommandLine)) {
  657. if (!Basep8BitStringToDynamicUnicodeString( &DynamicCommandLine,
  658. lpCommandLine )) {
  659. return FALSE;
  660. }
  661. } else {
  662. DynamicCommandLine.Buffer = NULL;
  663. CommandLine = &NullUnicodeString;
  664. CommandLine->Buffer = NULL;
  665. }
  666. ApplicationName.Buffer = NULL;
  667. ApplicationName.Buffer = NULL;
  668. CurrentDirectory.Buffer = NULL;
  669. RtlMoveMemory(&StartupInfo,lpStartupInfo,sizeof(*lpStartupInfo));
  670. ASSERT(sizeof(StartupInfo) == sizeof(*lpStartupInfo));
  671. StartupInfo.lpReserved = NULL;
  672. StartupInfo.lpDesktop = NULL;
  673. StartupInfo.lpTitle = NULL;
  674. try {
  675. try {
  676. if (ARGUMENT_PRESENT(lpApplicationName)) {
  677. if (!Basep8BitStringToDynamicUnicodeString( &ApplicationName,
  678. lpApplicationName )) {
  679. ReturnStatus = FALSE;
  680. goto tryexit;
  681. }
  682. }
  683. if (ARGUMENT_PRESENT(lpCurrentDirectory)) {
  684. if (!Basep8BitStringToDynamicUnicodeString( &CurrentDirectory,
  685. lpCurrentDirectory )) {
  686. ReturnStatus = FALSE;
  687. goto tryexit;
  688. }
  689. }
  690. if (ARGUMENT_PRESENT(lpStartupInfo->lpReserved)) {
  691. //
  692. // Win95 does not touch reserved, and Intergraph Voxtel passes
  693. // garbage for this. Handle this by probing lpReserved, and if
  694. // the pointer is bad, ignore it
  695. //
  696. try {
  697. RtlInitAnsiString(&AnsiString,lpStartupInfo->lpReserved);
  698. }
  699. except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION
  700. ? EXCEPTION_EXECUTE_HANDLER
  701. : EXCEPTION_CONTINUE_SEARCH) {
  702. goto bail_on_reserved;
  703. }
  704. Unicode.MaximumLength = (USHORT)RtlAnsiStringToUnicodeSize(&AnsiString) ;
  705. StartupInfo.lpReserved = RtlAllocateHeap( RtlProcessHeap(),
  706. MAKE_TAG( TMP_TAG ),
  707. Unicode.MaximumLength);
  708. if ( !StartupInfo.lpReserved ) {
  709. BaseSetLastNTError(STATUS_NO_MEMORY);
  710. ReturnStatus = FALSE;
  711. goto tryexit;
  712. }
  713. Unicode.Buffer = StartupInfo.lpReserved;
  714. Status = RtlAnsiStringToUnicodeString(&Unicode,&AnsiString,FALSE);
  715. if ( !NT_SUCCESS(Status) ) {
  716. BaseSetLastNTError(Status);
  717. ReturnStatus = FALSE;
  718. goto tryexit;
  719. }
  720. }
  721. bail_on_reserved:
  722. if (ARGUMENT_PRESENT(lpStartupInfo->lpDesktop)) {
  723. RtlInitAnsiString(&AnsiString,lpStartupInfo->lpDesktop);
  724. Unicode.MaximumLength = (USHORT)RtlAnsiStringToUnicodeSize(&AnsiString) ;
  725. StartupInfo.lpDesktop = RtlAllocateHeap( RtlProcessHeap(),
  726. MAKE_TAG( TMP_TAG ),
  727. Unicode.MaximumLength);
  728. if ( !StartupInfo.lpDesktop ) {
  729. BaseSetLastNTError(STATUS_NO_MEMORY);
  730. ReturnStatus = FALSE;
  731. goto tryexit;
  732. }
  733. Unicode.Buffer = StartupInfo.lpDesktop;
  734. Status = RtlAnsiStringToUnicodeString(&Unicode,&AnsiString,FALSE);
  735. if ( !NT_SUCCESS(Status) ) {
  736. BaseSetLastNTError(Status);
  737. ReturnStatus = FALSE;
  738. goto tryexit;
  739. }
  740. }
  741. if (ARGUMENT_PRESENT(lpStartupInfo->lpTitle)) {
  742. RtlInitAnsiString(&AnsiString,lpStartupInfo->lpTitle);
  743. Unicode.MaximumLength = (USHORT)RtlAnsiStringToUnicodeSize(&AnsiString) ;
  744. StartupInfo.lpTitle = RtlAllocateHeap( RtlProcessHeap(),
  745. MAKE_TAG( TMP_TAG ),
  746. Unicode.MaximumLength);
  747. if ( !StartupInfo.lpTitle ) {
  748. BaseSetLastNTError(STATUS_NO_MEMORY);
  749. ReturnStatus = FALSE;
  750. goto tryexit;
  751. }
  752. Unicode.Buffer = StartupInfo.lpTitle;
  753. Status = RtlAnsiStringToUnicodeString(&Unicode,&AnsiString,FALSE);
  754. if ( !NT_SUCCESS(Status) ) {
  755. BaseSetLastNTError(Status);
  756. ReturnStatus = FALSE;
  757. goto tryexit;
  758. }
  759. }
  760. }
  761. except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION
  762. ? EXCEPTION_EXECUTE_HANDLER
  763. : EXCEPTION_CONTINUE_SEARCH) {
  764. BaseSetLastNTError(GetExceptionCode());
  765. ReturnStatus = FALSE;
  766. goto tryexit;
  767. }
  768. ReturnStatus = CreateProcessInternalW(
  769. hUserToken,
  770. ApplicationName.Buffer,
  771. DynamicCommandLine.Buffer ? DynamicCommandLine.Buffer
  772. : CommandLine->Buffer,
  773. lpProcessAttributes,
  774. lpThreadAttributes,
  775. bInheritHandles,
  776. dwCreationFlags,
  777. lpEnvironment,
  778. CurrentDirectory.Buffer,
  779. &StartupInfo,
  780. lpProcessInformation,
  781. hRestrictedUserToken
  782. );
  783. tryexit:;
  784. }
  785. finally {
  786. RtlFreeUnicodeString(&DynamicCommandLine);
  787. RtlFreeUnicodeString(&ApplicationName);
  788. RtlFreeUnicodeString(&CurrentDirectory);
  789. RtlFreeHeap(RtlProcessHeap(), 0,StartupInfo.lpReserved);
  790. RtlFreeHeap(RtlProcessHeap(), 0,StartupInfo.lpDesktop);
  791. RtlFreeHeap(RtlProcessHeap(), 0,StartupInfo.lpTitle);
  792. }
  793. return ReturnStatus;
  794. }
  795. BOOL
  796. WINAPI
  797. CreateProcessA(
  798. LPCSTR lpApplicationName,
  799. LPSTR lpCommandLine,
  800. LPSECURITY_ATTRIBUTES lpProcessAttributes,
  801. LPSECURITY_ATTRIBUTES lpThreadAttributes,
  802. BOOL bInheritHandles,
  803. DWORD dwCreationFlags,
  804. LPVOID lpEnvironment,
  805. LPCSTR lpCurrentDirectory,
  806. LPSTARTUPINFOA lpStartupInfo,
  807. LPPROCESS_INFORMATION lpProcessInformation
  808. )
  809. /*++
  810. ANSI thunk to CreateProcessW
  811. --*/
  812. {
  813. return CreateProcessInternalA(
  814. NULL, // Create new process with the token on the creator process
  815. lpApplicationName,
  816. lpCommandLine,
  817. lpProcessAttributes,
  818. lpThreadAttributes,
  819. bInheritHandles,
  820. dwCreationFlags,
  821. lpEnvironment,
  822. lpCurrentDirectory,
  823. lpStartupInfo,
  824. lpProcessInformation,
  825. NULL // Do not return the restricted token
  826. );
  827. }
  828. void
  829. WINAPI
  830. RegisterWaitForInputIdle(
  831. IN PFNWAITFORINPUTIDLE WaitForInputIdleRoutine
  832. )
  833. {
  834. //
  835. // Soft link in the USER call back for the routine needed for WinExec()
  836. // synchronization. The only reason this is a soft link is so we can
  837. // run char mode without gui.
  838. //
  839. UserWaitForInputIdleRoutine = WaitForInputIdleRoutine;
  840. }
  841. void
  842. StuffStdHandle(
  843. HANDLE ProcessHandle,
  844. HANDLE StdHandle,
  845. PHANDLE TargetHandleAddress
  846. )
  847. {
  848. NTSTATUS Status;
  849. HANDLE TargetStdHandle;
  850. SIZE_T NumberOfBytesWritten;
  851. if (StdHandle == NULL) {
  852. return;
  853. }
  854. Status = NtDuplicateObject (NtCurrentProcess(),
  855. StdHandle,
  856. ProcessHandle,
  857. &TargetStdHandle,
  858. DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES,
  859. 0,
  860. 0);
  861. if (!NT_SUCCESS( Status )) {
  862. return;
  863. }
  864. Status = NtWriteVirtualMemory (ProcessHandle,
  865. TargetHandleAddress,
  866. &TargetStdHandle,
  867. sizeof( TargetStdHandle ),
  868. &NumberOfBytesWritten);
  869. return;
  870. }
  871. static HANDLE AdvApi32ModuleHandle = (HANDLE) (ULONG_PTR) -1;
  872. NTSTATUS
  873. BasepCheckWinSaferRestrictions(
  874. IN HANDLE hUserToken OPTIONAL,
  875. IN LPCWSTR lpApplicationName,
  876. IN HANDLE FileImageHandle OPTIONAL,
  877. OUT LPDWORD pdwJobMemberLevel,
  878. OUT PHANDLE phRestrictedToken,
  879. OUT PHANDLE phAssignmentJob
  880. )
  881. // Note: May return -1 for the ERROR_ACCESS_DISABLED_BY_POLICY case.
  882. {
  883. #define SAFER_USER_KEY_NAME L"\\Software\\Policies\\Microsoft\\Windows\\Safer\\CodeIdentifiers"
  884. typedef BOOL (WINAPI *ComputeAccessTokenFromCodeAuthzLevelT) (
  885. IN SAFER_LEVEL_HANDLE LevelObject,
  886. IN HANDLE InAccessToken OPTIONAL,
  887. OUT PHANDLE OutAccessToken,
  888. IN DWORD dwFlags,
  889. IN LPVOID lpReserved
  890. );
  891. typedef BOOL (WINAPI *IdentifyCodeAuthzLevelWT) (
  892. IN DWORD dwCheckFlags,
  893. IN PSAFER_CODE_PROPERTIES CodeProperties,
  894. OUT SAFER_LEVEL_HANDLE *pLevelObject,
  895. IN LPVOID lpReserved
  896. );
  897. typedef BOOL (WINAPI *CloseCodeAuthzLevelT) (
  898. IN SAFER_LEVEL_HANDLE hLevelObject);
  899. typedef BOOL (WINAPI *CodeAuthzRecordEventLogEntryT) (
  900. IN SAFER_LEVEL_HANDLE hAuthzLevel,
  901. IN LPCWSTR szTargetPath,
  902. IN LPVOID lpReserved
  903. );
  904. NTSTATUS Status;
  905. SAFER_CODE_PROPERTIES codeproperties;
  906. SAFER_LEVEL_HANDLE hAuthzLevel;
  907. HANDLE hProcessToken = NULL;
  908. HANDLE hThreadToken = NULL;
  909. HANDLE hEffectiveToken = NULL;
  910. static DWORD dwSaferAuthenticodeFlag = 0;
  911. const static SID_IDENTIFIER_AUTHORITY NtAuthority =
  912. SECURITY_NT_AUTHORITY;
  913. const static UNICODE_STRING UnicodeSafeBootKeyName =
  914. RTL_CONSTANT_STRING(L"\\Registry\\MACHINE\\System\\CurrentControlSet\\Control\\SafeBoot\\Option");
  915. const static UNICODE_STRING UnicodeSafeBootValueName =
  916. RTL_CONSTANT_STRING(L"OptionValue");
  917. const static OBJECT_ATTRIBUTES ObjectAttributesSafeBoot =
  918. RTL_CONSTANT_OBJECT_ATTRIBUTES(&UnicodeSafeBootKeyName, OBJ_CASE_INSENSITIVE);
  919. const static UNICODE_STRING UnicodeKeyName =
  920. RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\Policies\\Microsoft\\Windows\\Safer\\CodeIdentifiers");
  921. const static UNICODE_STRING UnicodeTransparentValueName =
  922. RTL_CONSTANT_STRING(L"TransparentEnabled");
  923. const static OBJECT_ATTRIBUTES ObjectAttributesCodeIdentifiers =
  924. RTL_CONSTANT_OBJECT_ATTRIBUTES(&UnicodeKeyName, OBJ_CASE_INSENSITIVE);
  925. const static UNICODE_STRING ModuleName =
  926. RTL_CONSTANT_STRING(L"ADVAPI32.DLL");
  927. const static ANSI_STRING ProcedureNameIdentify =
  928. RTL_CONSTANT_STRING("SaferIdentifyLevel");
  929. const static ANSI_STRING ProcedureNameCompute =
  930. RTL_CONSTANT_STRING("SaferComputeTokenFromLevel");
  931. const static ANSI_STRING ProcedureNameClose =
  932. RTL_CONSTANT_STRING("SaferCloseLevel");
  933. const static ANSI_STRING ProcedureNameLogEntry =
  934. RTL_CONSTANT_STRING("SaferRecordEventLogEntry");
  935. const static UNICODE_STRING SaferAuthenticodeValueName =
  936. RTL_CONSTANT_STRING(L"AuthenticodeEnabled");
  937. static IdentifyCodeAuthzLevelWT lpfnIdentifyCodeAuthzLevelW;
  938. static ComputeAccessTokenFromCodeAuthzLevelT
  939. lpfnComputeAccessTokenFromCodeAuthzLevel;
  940. static CloseCodeAuthzLevelT lpfnCloseCodeAuthzLevel;
  941. static CodeAuthzRecordEventLogEntryT lpfnCodeAuthzRecordEventLogEntry;
  942. //
  943. // Verify that our required arguments were supplied.
  944. //
  945. if (!ARGUMENT_PRESENT(lpApplicationName) || !*lpApplicationName) {
  946. return STATUS_INVALID_PARAMETER;
  947. }
  948. if (!ARGUMENT_PRESENT(pdwJobMemberLevel) ||
  949. !ARGUMENT_PRESENT(phRestrictedToken) ||
  950. !ARGUMENT_PRESENT(phAssignmentJob)) {
  951. return STATUS_ACCESS_VIOLATION;
  952. }
  953. //
  954. // Enter a critical section for the entire trust evalation.
  955. // (We borrow the critical section used by AppCert).
  956. //
  957. RtlEnterCriticalSection(&gcsAppCert);
  958. //
  959. // If either of these two cases are true, then we should bail out
  960. // as quickly as possible because we know that WinSafer evaluations
  961. // should definitely not occur for this process anymore.
  962. //
  963. if (AdvApi32ModuleHandle == NULL) {
  964. // We tried to load ADVAPI32.DLL once before, but failed.
  965. Status = STATUS_ENTRYPOINT_NOT_FOUND;
  966. goto ExitHandler;
  967. } else if (AdvApi32ModuleHandle == LongToHandle(-2)) {
  968. // Indicates that DLL checking should never be done for this process.
  969. Status = STATUS_SUCCESS;
  970. goto ExitHandler;
  971. }
  972. //
  973. // We only need the process token if no token is supplied.
  974. //
  975. if (hUserToken == NULL) {
  976. //
  977. // Open and save the thread token.
  978. //
  979. Status = NtOpenThreadToken(
  980. NtCurrentThread(),
  981. MAXIMUM_ALLOWED,
  982. TRUE,
  983. &hThreadToken);
  984. if (Status == STATUS_NO_TOKEN) {
  985. // The thread is not impersonating. It is ok to fall thru.
  986. } else if (!NT_SUCCESS(Status)) {
  987. goto ExitHandler;
  988. } else {
  989. HANDLE NewToken = NULL;
  990. //
  991. // Revert to self.
  992. //
  993. Status = NtSetInformationThread(
  994. NtCurrentThread(),
  995. ThreadImpersonationToken,
  996. (PVOID)&NewToken,
  997. (ULONG)sizeof(HANDLE)
  998. );
  999. //
  1000. // This should never happen unless kernel gives up on us.
  1001. //
  1002. if ( !NT_SUCCESS(Status) ) {
  1003. NtClose(hThreadToken);
  1004. hThreadToken = NULL;
  1005. goto ExitHandler;
  1006. }
  1007. }
  1008. //
  1009. // Open a handle to the current process's access token.
  1010. // We care only about the process token, and not the
  1011. // thread impersonation token.
  1012. //
  1013. Status = NtOpenProcessToken(
  1014. NtCurrentProcess(),
  1015. TOKEN_DUPLICATE | TOKEN_QUERY,
  1016. &hProcessToken);
  1017. if (Status == STATUS_ACCESS_DENIED) {
  1018. // Failed to open with query and duplicate privs. Retry with
  1019. // only query privileges, which might be enough to do simply
  1020. // determine that we should not allow futher loading. But without
  1021. // duplicate access, we won't be able to restrict tokens later.
  1022. Status = NtOpenProcessToken(
  1023. NtCurrentProcess(),
  1024. TOKEN_QUERY,
  1025. &hProcessToken);
  1026. }
  1027. if (hThreadToken != NULL) {
  1028. //
  1029. // Set the thread token to the saved one.
  1030. //
  1031. NTSTATUS lStatus = NtSetInformationThread(
  1032. NtCurrentThread(),
  1033. ThreadImpersonationToken,
  1034. (PVOID)&hThreadToken,
  1035. (ULONG)sizeof(HANDLE)
  1036. );
  1037. NtClose(hThreadToken);
  1038. hThreadToken = NULL;
  1039. //
  1040. // This should never happen unless kernel gives up on us.
  1041. //
  1042. if ( !NT_SUCCESS(lStatus) ) {
  1043. Status = lStatus;
  1044. goto ExitHandler2;
  1045. }
  1046. }
  1047. if (!NT_SUCCESS(Status)) {
  1048. if (AdvApi32ModuleHandle == LongToHandle(-1)) {
  1049. // If this is our first pass through, then it is unlikely
  1050. // that any later attempts will succeed, so remember that.
  1051. AdvApi32ModuleHandle = LongToHandle(-2);
  1052. Status = STATUS_SUCCESS;
  1053. }
  1054. goto ExitHandler;
  1055. }
  1056. hEffectiveToken = hProcessToken;
  1057. } else {
  1058. hEffectiveToken = hUserToken;
  1059. }
  1060. //
  1061. // Load ADVAPI32.DLL and get pointers to our functions.
  1062. //
  1063. if (AdvApi32ModuleHandle == LongToHandle(-1)) {
  1064. HANDLE TempModuleHandle;
  1065. //
  1066. // Check if this process's access token is running as
  1067. // the Local SYSTEM account, and disable enforcement if so.
  1068. //
  1069. {
  1070. BYTE tokenuserbuff[sizeof(TOKEN_USER) + 128];
  1071. PTOKEN_USER ptokenuser = (PTOKEN_USER) tokenuserbuff;
  1072. BYTE localsystembuff[128];
  1073. PSID LocalSystemSid = (PSID) localsystembuff;
  1074. ULONG ulReturnLength;
  1075. Status = NtQueryInformationToken(
  1076. hEffectiveToken, TokenUser,
  1077. tokenuserbuff, sizeof(tokenuserbuff),
  1078. &ulReturnLength);
  1079. if (NT_SUCCESS(Status)) {
  1080. Status = RtlInitializeSid(
  1081. LocalSystemSid,
  1082. (PSID_IDENTIFIER_AUTHORITY) &NtAuthority, 1);
  1083. ASSERTMSG("InitializeSid should not fail.", NT_SUCCESS(Status));
  1084. *RtlSubAuthoritySid(LocalSystemSid, 0) = SECURITY_LOCAL_SYSTEM_RID;
  1085. if (RtlEqualSid(ptokenuser->User.Sid, LocalSystemSid)) {
  1086. goto FailSuccessfully;
  1087. }
  1088. }
  1089. }
  1090. //
  1091. // If we are booting in safe mode and the user is a member of
  1092. // the local Administrators group, then disable enforcement.
  1093. // Notice that Windows itself does not perform any implicit
  1094. // restriction of only allowing Administrators to log in during
  1095. // Safe mode boot, so we must perform the test ourself.
  1096. //
  1097. {
  1098. HANDLE hKeySafeBoot;
  1099. BYTE QueryBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 64];
  1100. PKEY_VALUE_PARTIAL_INFORMATION pKeyValueInfo =
  1101. (PKEY_VALUE_PARTIAL_INFORMATION) QueryBuffer;
  1102. DWORD dwActualSize;
  1103. BOOLEAN bSafeModeBoot = FALSE;
  1104. // We open the key for SET access (in addition to QUERY)
  1105. // because only Administrators should be able to modify values
  1106. // under this key. This allows us to combine our test of
  1107. // being an Administrator and having booted in Safe mode.
  1108. Status = NtOpenKey(&hKeySafeBoot, KEY_QUERY_VALUE | KEY_SET_VALUE,
  1109. (POBJECT_ATTRIBUTES) &ObjectAttributesSafeBoot);
  1110. if (NT_SUCCESS(Status)) {
  1111. Status = NtQueryValueKey(
  1112. hKeySafeBoot,
  1113. (PUNICODE_STRING) &UnicodeSafeBootValueName,
  1114. KeyValuePartialInformation,
  1115. pKeyValueInfo,
  1116. sizeof(QueryBuffer),
  1117. &dwActualSize);
  1118. NtClose(hKeySafeBoot);
  1119. if (NT_SUCCESS(Status)) {
  1120. if (pKeyValueInfo->Type == REG_DWORD &&
  1121. pKeyValueInfo->DataLength == sizeof(DWORD) &&
  1122. *((PDWORD) pKeyValueInfo->Data) > 0) {
  1123. bSafeModeBoot = TRUE;
  1124. }
  1125. }
  1126. }
  1127. if (bSafeModeBoot) {
  1128. AdvApi32ModuleHandle = LongToHandle(-2);
  1129. FailSuccessfully:
  1130. Status = STATUS_SUCCESS;
  1131. goto ExitHandler2;
  1132. }
  1133. }
  1134. //
  1135. // Allow a way for policy to enable whether transparent
  1136. // enforcement should be enabled or not (default to disable).
  1137. // Note that the following values have meanings:
  1138. // 0 = Transparent WinSafer enforcement disabled.
  1139. // 1 = means enable transparent EXE enforcement
  1140. // >1 = means enable transparent EXE and DLL enforcement.
  1141. //
  1142. {
  1143. // BUG 240635: change to use existence of policy instead.
  1144. HANDLE hKeyEnabled;
  1145. BYTE QueryBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 64];
  1146. PKEY_VALUE_PARTIAL_INFORMATION pKeyValueInfo =
  1147. (PKEY_VALUE_PARTIAL_INFORMATION) QueryBuffer;
  1148. DWORD dwActualSize;
  1149. BOOLEAN bPolicyEnabled = FALSE;
  1150. Status = NtOpenKey(&hKeyEnabled, KEY_QUERY_VALUE,
  1151. (POBJECT_ATTRIBUTES) &ObjectAttributesCodeIdentifiers);
  1152. if (NT_SUCCESS(Status)) {
  1153. Status = NtQueryValueKey(
  1154. hKeyEnabled,
  1155. (PUNICODE_STRING) &UnicodeTransparentValueName,
  1156. KeyValuePartialInformation,
  1157. pKeyValueInfo, sizeof(QueryBuffer), &dwActualSize);
  1158. if (NT_SUCCESS(Status)) {
  1159. if (pKeyValueInfo->Type == REG_DWORD &&
  1160. pKeyValueInfo->DataLength == sizeof(DWORD) &&
  1161. *((PDWORD) pKeyValueInfo->Data) > 0) {
  1162. bPolicyEnabled = TRUE;
  1163. }
  1164. }
  1165. //
  1166. // do authenticode checks only if a regvalue is set
  1167. //
  1168. Status = NtQueryValueKey(
  1169. hKeyEnabled,
  1170. (PUNICODE_STRING) &SaferAuthenticodeValueName,
  1171. KeyValuePartialInformation,
  1172. pKeyValueInfo, sizeof(QueryBuffer), &dwActualSize);
  1173. if (NT_SUCCESS(Status)) {
  1174. if (pKeyValueInfo->Type == REG_DWORD &&
  1175. pKeyValueInfo->DataLength == sizeof(DWORD) &&
  1176. *((PDWORD) pKeyValueInfo->Data) > 0) {
  1177. dwSaferAuthenticodeFlag = SAFER_CRITERIA_AUTHENTICODE;
  1178. }
  1179. }
  1180. NtClose(hKeyEnabled);
  1181. }
  1182. //
  1183. // There was no machine policy. Check if user policy is enabled.
  1184. //
  1185. if (!bPolicyEnabled) {
  1186. UNICODE_STRING CurrentUserKeyPath;
  1187. UNICODE_STRING SubKeyNameUser;
  1188. OBJECT_ATTRIBUTES ObjectAttributesUser;
  1189. //
  1190. // Get the prefix for the user key.
  1191. //
  1192. Status = RtlFormatCurrentUserKeyPath( &CurrentUserKeyPath );
  1193. if (NT_SUCCESS( Status ) ) {
  1194. SubKeyNameUser.Length = 0;
  1195. SubKeyNameUser.MaximumLength = CurrentUserKeyPath.Length +
  1196. sizeof(WCHAR) +
  1197. sizeof(SAFER_USER_KEY_NAME);
  1198. //
  1199. // Allocate memory big enough to hold the unicode string.
  1200. //
  1201. SubKeyNameUser.Buffer = RtlAllocateHeap(
  1202. RtlProcessHeap(),
  1203. MAKE_TAG( TMP_TAG ),
  1204. SubKeyNameUser.MaximumLength);
  1205. if (SubKeyNameUser.Buffer != NULL) {
  1206. //
  1207. // Copy the prefix into the string.
  1208. // This is of the type Registry\S-1-5-21-xxx-xxx-xxx-xxx.
  1209. //
  1210. Status = RtlAppendUnicodeStringToString(
  1211. &SubKeyNameUser,
  1212. &CurrentUserKeyPath );
  1213. if (NT_SUCCESS( Status ) ) {
  1214. //
  1215. // Append the Safer suffix.
  1216. //
  1217. Status = RtlAppendUnicodeToString(
  1218. &SubKeyNameUser,
  1219. SAFER_USER_KEY_NAME );
  1220. if (NT_SUCCESS( Status ) ) {
  1221. InitializeObjectAttributes(
  1222. &ObjectAttributesUser,
  1223. &SubKeyNameUser,
  1224. OBJ_CASE_INSENSITIVE,
  1225. NULL,
  1226. NULL
  1227. );
  1228. Status = NtOpenKey( &hKeyEnabled,KEY_QUERY_VALUE,
  1229. (POBJECT_ATTRIBUTES) &ObjectAttributesUser);
  1230. if (NT_SUCCESS(Status)) {
  1231. Status = NtQueryValueKey(
  1232. hKeyEnabled,
  1233. (PUNICODE_STRING) &UnicodeTransparentValueName,
  1234. KeyValuePartialInformation,
  1235. pKeyValueInfo, sizeof(QueryBuffer), &dwActualSize);
  1236. if (NT_SUCCESS(Status)) {
  1237. if (pKeyValueInfo->Type == REG_DWORD &&
  1238. pKeyValueInfo->DataLength == sizeof(DWORD) &&
  1239. *((PDWORD) pKeyValueInfo->Data) > 0) {
  1240. bPolicyEnabled = TRUE;
  1241. }
  1242. }
  1243. }
  1244. }
  1245. }
  1246. RtlFreeHeap(RtlProcessHeap(), 0, SubKeyNameUser.Buffer);
  1247. }
  1248. RtlFreeUnicodeString( &CurrentUserKeyPath );
  1249. }
  1250. }
  1251. if (!bPolicyEnabled) {
  1252. AdvApi32ModuleHandle = LongToHandle(-2);
  1253. goto FailSuccessfully;
  1254. }
  1255. }
  1256. //
  1257. // Finally load the library. We'll pass a special flag in
  1258. // DllCharacteristics to eliminate WinSafer checking on advapi.
  1259. //
  1260. {
  1261. ULONG DllCharacteristics = IMAGE_FILE_SYSTEM;
  1262. Status = LdrLoadDll(UNICODE_NULL,
  1263. &DllCharacteristics,
  1264. (PUNICODE_STRING) &ModuleName,
  1265. &TempModuleHandle);
  1266. if (!NT_SUCCESS(Status)) {
  1267. Status = STATUS_ENTRYPOINT_NOT_FOUND;
  1268. AdvApi32ModuleHandle = NULL;
  1269. goto ExitHandler2;
  1270. }
  1271. }
  1272. //
  1273. // Get function pointers to the APIs that we'll need. If we fail
  1274. // to get pointers for any of them, then just unload advapi and
  1275. // ignore all future attempts to load it within this process.
  1276. //
  1277. Status = LdrGetProcedureAddress(
  1278. TempModuleHandle,
  1279. (PANSI_STRING) &ProcedureNameIdentify,
  1280. 0,
  1281. (PVOID*)&lpfnIdentifyCodeAuthzLevelW);
  1282. if (!NT_SUCCESS(Status) || !lpfnIdentifyCodeAuthzLevelW) {
  1283. //
  1284. // Couldn't get the fn ptr. Make sure we won't try again
  1285. //
  1286. AdvapiLoadFailure:
  1287. LdrUnloadDll(TempModuleHandle);
  1288. AdvApi32ModuleHandle = NULL;
  1289. Status = STATUS_ENTRYPOINT_NOT_FOUND;
  1290. goto ExitHandler2;
  1291. }
  1292. Status = LdrGetProcedureAddress(
  1293. TempModuleHandle,
  1294. (PANSI_STRING) &ProcedureNameCompute,
  1295. 0,
  1296. (PVOID*)&lpfnComputeAccessTokenFromCodeAuthzLevel);
  1297. if (!NT_SUCCESS(Status) ||
  1298. !lpfnComputeAccessTokenFromCodeAuthzLevel) {
  1299. goto AdvapiLoadFailure;
  1300. }
  1301. Status = LdrGetProcedureAddress(
  1302. TempModuleHandle,
  1303. (PANSI_STRING) &ProcedureNameClose,
  1304. 0,
  1305. (PVOID*)&lpfnCloseCodeAuthzLevel);
  1306. if (!NT_SUCCESS(Status) || !lpfnCloseCodeAuthzLevel) {
  1307. goto AdvapiLoadFailure;
  1308. }
  1309. Status = LdrGetProcedureAddress(
  1310. TempModuleHandle,
  1311. (PANSI_STRING) &ProcedureNameLogEntry,
  1312. 0,
  1313. (PVOID*)&lpfnCodeAuthzRecordEventLogEntry);
  1314. if (!NT_SUCCESS(Status) || !lpfnCodeAuthzRecordEventLogEntry) {
  1315. goto AdvapiLoadFailure;
  1316. }
  1317. AdvApi32ModuleHandle = TempModuleHandle;
  1318. }
  1319. //
  1320. // Prepare the code properties struct.
  1321. //
  1322. RtlZeroMemory(&codeproperties, sizeof(codeproperties));
  1323. codeproperties.cbSize = sizeof(codeproperties);
  1324. codeproperties.dwCheckFlags =
  1325. (SAFER_CRITERIA_IMAGEPATH | SAFER_CRITERIA_IMAGEHASH | dwSaferAuthenticodeFlag);
  1326. codeproperties.ImagePath = lpApplicationName;
  1327. codeproperties.dwWVTUIChoice = WTD_UI_NONE; //harmless if AUTHZCRITERIA_AUTHENTICODE is not passed in
  1328. codeproperties.hImageFileHandle = FileImageHandle;
  1329. //
  1330. // Ask the system to find the Authorization Level that classifies it.
  1331. //
  1332. ASSERT(lpfnIdentifyCodeAuthzLevelW != NULL);
  1333. if (lpfnIdentifyCodeAuthzLevelW(
  1334. 1, // 1 structure
  1335. &codeproperties, // details to identify
  1336. &hAuthzLevel, // Safer level
  1337. NULL)) { // reserved.
  1338. // We found an Authorization Level applicable to this application.
  1339. HANDLE hRestrictedToken = NULL;
  1340. DWORD dwSaferFlags = 0;
  1341. HANDLE hActualJobObject = NULL;
  1342. DWORD dwJobMemberLevel = 0;
  1343. //
  1344. // Generate the Restricted Token that we will use.
  1345. //
  1346. ASSERT(lpfnComputeAccessTokenFromCodeAuthzLevel != NULL);
  1347. if (!lpfnComputeAccessTokenFromCodeAuthzLevel(
  1348. hAuthzLevel, // Safer Level
  1349. hEffectiveToken,
  1350. &hRestrictedToken, // target token
  1351. SAFER_TOKEN_NULL_IF_EQUAL | // flags
  1352. SAFER_TOKEN_WANT_FLAGS,
  1353. &dwSaferFlags)) { // reserved
  1354. DWORD dwLastError = GetLastError();
  1355. ASSERT(lpfnCloseCodeAuthzLevel != NULL);
  1356. if (dwLastError == ERROR_ACCESS_DISABLED_BY_POLICY) {
  1357. lpfnCodeAuthzRecordEventLogEntry(
  1358. hAuthzLevel, lpApplicationName, NULL);
  1359. Status = -1;
  1360. } else {
  1361. Status = STATUS_ACCESS_DENIED;
  1362. }
  1363. lpfnCloseCodeAuthzLevel(hAuthzLevel);
  1364. goto ExitHandler2;
  1365. }
  1366. ASSERT(lpfnCloseCodeAuthzLevel != NULL);
  1367. lpfnCloseCodeAuthzLevel(hAuthzLevel);
  1368. //
  1369. // If the identified Authorization Level needs to be run
  1370. // within an isolation Job Object, then do the Job setup.
  1371. //
  1372. if ((dwSaferFlags & SAFER_POLICY_JOBID_MASK) != 0) {
  1373. JOB_SET_ARRAY jobsetarray[2];
  1374. DWORD dwNumJobSetMembers = 0;
  1375. //
  1376. // Verify that the job member level is one that we support.
  1377. //
  1378. dwJobMemberLevel = (dwSaferFlags & SAFER_POLICY_JOBID_MASK);
  1379. if (dwJobMemberLevel != SAFER_POLICY_JOBID_UNTRUSTED &&
  1380. dwJobMemberLevel != SAFER_POLICY_JOBID_CONSTRAINED) {
  1381. NtClose(hRestrictedToken);
  1382. Status = STATUS_ACCESS_DENIED;
  1383. goto ExitHandler2;
  1384. }
  1385. Status = NtIsProcessInJob(GetCurrentProcess(), NULL);
  1386. if (Status == STATUS_PROCESS_IN_JOB) {
  1387. //
  1388. // The parent process is already within a job, so
  1389. // we will assume that its job is one of the WinSafer
  1390. // jobs and is thus within a WinSafer "jobset" and
  1391. // that NtCreateProcessEx can directly transition to it.
  1392. //
  1393. *phAssignmentJob = NULL;
  1394. } else if (Status == STATUS_PROCESS_NOT_IN_JOB) {
  1395. //
  1396. // The parent process is not in any job (nor jobset)
  1397. // so we must create all of the Jobs and place then
  1398. // within a new Jobset.
  1399. //
  1400. //if (dwJobMemberLevel >= AUTHZPOL_SAFERFLAGS_JOBID_UNTRUSTED)
  1401. {
  1402. HANDLE hThisJobObject;
  1403. JOBOBJECT_BASIC_UI_RESTRICTIONS RestrictUI;
  1404. Status = NtCreateJobObject(
  1405. &hThisJobObject,
  1406. JOB_OBJECT_ALL_ACCESS,
  1407. NULL);
  1408. if (!NT_SUCCESS(Status)) {
  1409. goto JobCreationFailure;
  1410. }
  1411. RestrictUI.UIRestrictionsClass =
  1412. JOB_OBJECT_UILIMIT_DESKTOP |
  1413. JOB_OBJECT_UILIMIT_DISPLAYSETTINGS |
  1414. JOB_OBJECT_UILIMIT_EXITWINDOWS |
  1415. JOB_OBJECT_UILIMIT_GLOBALATOMS |
  1416. JOB_OBJECT_UILIMIT_HANDLES |
  1417. JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS;
  1418. if (!SetInformationJobObject(
  1419. hThisJobObject,
  1420. JobObjectBasicUIRestrictions,
  1421. &RestrictUI,
  1422. sizeof(JOBOBJECT_BASIC_UI_RESTRICTIONS))) {
  1423. NtClose(hThisJobObject);
  1424. Status = STATUS_ACCESS_DENIED;
  1425. goto JobCreationFailure;
  1426. }
  1427. jobsetarray[dwNumJobSetMembers].MemberLevel =
  1428. SAFER_POLICY_JOBID_UNTRUSTED;
  1429. jobsetarray[dwNumJobSetMembers].Flags = 0;
  1430. jobsetarray[dwNumJobSetMembers].JobHandle = hThisJobObject;
  1431. dwNumJobSetMembers++;
  1432. if (dwJobMemberLevel == SAFER_POLICY_JOBID_UNTRUSTED) {
  1433. hActualJobObject = hThisJobObject;
  1434. }
  1435. }
  1436. //if (dwJobMemberLevel >= AUTHZPOL_SAFERFLAGS_JOBID_CONSTRAINED)
  1437. {
  1438. HANDLE hThisJobObject;
  1439. JOBOBJECT_BASIC_UI_RESTRICTIONS RestrictUI;
  1440. Status = NtCreateJobObject(
  1441. &hThisJobObject,
  1442. JOB_OBJECT_ALL_ACCESS,
  1443. NULL);
  1444. if (!NT_SUCCESS(Status)) {
  1445. goto JobCreationFailure;
  1446. }
  1447. RestrictUI.UIRestrictionsClass =
  1448. JOB_OBJECT_UILIMIT_DESKTOP |
  1449. JOB_OBJECT_UILIMIT_DISPLAYSETTINGS |
  1450. JOB_OBJECT_UILIMIT_EXITWINDOWS |
  1451. JOB_OBJECT_UILIMIT_GLOBALATOMS |
  1452. JOB_OBJECT_UILIMIT_HANDLES |
  1453. JOB_OBJECT_UILIMIT_SYSTEMPARAMETERS;
  1454. if (!SetInformationJobObject(
  1455. hThisJobObject,
  1456. JobObjectBasicUIRestrictions,
  1457. &RestrictUI,
  1458. sizeof(JOBOBJECT_BASIC_UI_RESTRICTIONS))) {
  1459. NtClose(hThisJobObject);
  1460. Status = STATUS_ACCESS_DENIED;
  1461. goto JobCreationFailure;
  1462. }
  1463. jobsetarray[dwNumJobSetMembers].MemberLevel =
  1464. SAFER_POLICY_JOBID_CONSTRAINED;
  1465. jobsetarray[dwNumJobSetMembers].Flags = 0;
  1466. jobsetarray[dwNumJobSetMembers].JobHandle = hThisJobObject;
  1467. dwNumJobSetMembers++;
  1468. if (dwJobMemberLevel == SAFER_POLICY_JOBID_CONSTRAINED) {
  1469. hActualJobObject = hThisJobObject;
  1470. }
  1471. }
  1472. //
  1473. // Create the Job Set that will hold all of the Job Objects.
  1474. //
  1475. ASSERT(dwNumJobSetMembers > 1 &&
  1476. dwNumJobSetMembers <= sizeof(jobsetarray) / sizeof(jobsetarray[0]));
  1477. ASSERT(hActualJobObject != NULL);
  1478. Status = NtCreateJobSet(dwNumJobSetMembers, jobsetarray, 0);
  1479. if (!NT_SUCCESS(Status)) {
  1480. JobCreationFailure:
  1481. for (; dwNumJobSetMembers > 0; dwNumJobSetMembers--) {
  1482. NtClose(jobsetarray[dwNumJobSetMembers - 1].JobHandle);
  1483. }
  1484. NtClose(hRestrictedToken);
  1485. goto ExitHandler2;
  1486. }
  1487. //
  1488. // Close all Job Handles except the one that we are returning.
  1489. //
  1490. for (; dwNumJobSetMembers > 0; dwNumJobSetMembers--) {
  1491. if (jobsetarray[dwNumJobSetMembers - 1].JobHandle != hActualJobObject)
  1492. NtClose(jobsetarray[dwNumJobSetMembers - 1].JobHandle);
  1493. }
  1494. dwJobMemberLevel = 0;
  1495. } else if (!NT_SUCCESS(Status)) {
  1496. // Some other failure.
  1497. goto ExitHandler2;
  1498. } else {
  1499. Status = STATUS_UNSUCCESSFUL;
  1500. goto ExitHandler2;
  1501. }
  1502. }
  1503. //
  1504. // Pass back the restricted token, and the Job handle/level.
  1505. //
  1506. ASSERTMSG("Only one may be specified (job handle or job member)\n",
  1507. hActualJobObject == NULL || dwJobMemberLevel == 0);
  1508. *phRestrictedToken = hRestrictedToken;
  1509. *phAssignmentJob = hActualJobObject;
  1510. *pdwJobMemberLevel = dwJobMemberLevel;
  1511. Status = STATUS_SUCCESS;
  1512. } else {
  1513. //
  1514. // Failed to identify an Authorization Level for this
  1515. // application so it will run without restrictions.
  1516. //
  1517. *phRestrictedToken = NULL;
  1518. *phAssignmentJob = NULL;
  1519. *pdwJobMemberLevel = 0;
  1520. Status = STATUS_SUCCESS;
  1521. }
  1522. ExitHandler2:
  1523. if (hProcessToken != NULL)
  1524. {
  1525. NtClose(hProcessToken);
  1526. }
  1527. ExitHandler:
  1528. RtlLeaveCriticalSection(&gcsAppCert);
  1529. return Status;
  1530. }
  1531. NTSTATUS
  1532. BasepReplaceProcessThreadTokens(
  1533. IN HANDLE NewTokenHandle,
  1534. IN HANDLE ProcessHandle,
  1535. IN HANDLE ThreadHandle
  1536. )
  1537. {
  1538. typedef BOOL (WINAPI *CodeAuthzReplaceProcessThreadTokensT) (
  1539. IN HANDLE NewTokenHandle,
  1540. IN HANDLE ProcessHandle,
  1541. IN HANDLE ThreadHandle);
  1542. NTSTATUS Status;
  1543. static const ANSI_STRING ProcedureNameReplaceTokens =
  1544. RTL_CONSTANT_STRING("SaferiReplaceProcessThreadTokens");
  1545. static CodeAuthzReplaceProcessThreadTokensT
  1546. lpfnCodeAuthzReplaceProcessThreadTokens = NULL;
  1547. //
  1548. // Enter a critical section for the entire trust evalation.
  1549. // (We borrow the critical section used by AppCert).
  1550. //
  1551. RtlEnterCriticalSection(&gcsAppCert);
  1552. //
  1553. // Get a pointer to our private function in ADVAPI32.DLL.
  1554. //
  1555. if (!lpfnCodeAuthzReplaceProcessThreadTokens) {
  1556. if (!AdvApi32ModuleHandle ||
  1557. AdvApi32ModuleHandle == LongToHandle(-1) ||
  1558. AdvApi32ModuleHandle == LongToHandle(-2))
  1559. {
  1560. // ADVAPI32 has not been loaded yet, or it was loaded
  1561. // but we already failed to get one of our entrypoints.
  1562. Status = STATUS_ENTRYPOINT_NOT_FOUND;
  1563. goto ExitHandler;
  1564. }
  1565. Status = LdrGetProcedureAddress(
  1566. AdvApi32ModuleHandle,
  1567. (PANSI_STRING) &ProcedureNameReplaceTokens,
  1568. 0,
  1569. (PVOID*)&lpfnCodeAuthzReplaceProcessThreadTokens);
  1570. if (!NT_SUCCESS(Status) ||
  1571. !lpfnCodeAuthzReplaceProcessThreadTokens) {
  1572. //
  1573. // Couldn't get the fn ptr. Make sure we won't try again
  1574. //
  1575. LdrUnloadDll(AdvApi32ModuleHandle);
  1576. AdvApi32ModuleHandle = NULL;
  1577. Status = STATUS_ENTRYPOINT_NOT_FOUND;
  1578. goto ExitHandler;
  1579. }
  1580. }
  1581. //
  1582. // Actually call the function and return the results.
  1583. //
  1584. ASSERT(lpfnCodeAuthzReplaceProcessThreadTokens != NULL);
  1585. if (!lpfnCodeAuthzReplaceProcessThreadTokens(
  1586. NewTokenHandle,
  1587. ProcessHandle,
  1588. ThreadHandle)) {
  1589. Status = STATUS_UNSUCCESSFUL;
  1590. } else {
  1591. Status = STATUS_SUCCESS;
  1592. }
  1593. ExitHandler:
  1594. RtlLeaveCriticalSection(&gcsAppCert);
  1595. return Status;
  1596. }
  1597. #if defined(_WIN64) || defined(BUILD_WOW6432)
  1598. BOOL
  1599. NtVdm64CreateProcess(
  1600. BOOL fPrefixMappedApplicationName,
  1601. LPCWSTR lpApplicationName,
  1602. LPCWSTR lpCommandLine,
  1603. LPSECURITY_ATTRIBUTES lpProcessAttributes,
  1604. LPSECURITY_ATTRIBUTES lpThreadAttributes,
  1605. BOOL bInheritHandles,
  1606. DWORD dwCreationFlags,
  1607. LPVOID lpEnvironment,
  1608. LPCWSTR lpCurrentDirectory,
  1609. LPSTARTUPINFOW lpStartupInfo,
  1610. LPPROCESS_INFORMATION lpProcessInformation
  1611. );
  1612. #endif
  1613. #define PRIORITY_CLASS_MASK (NORMAL_PRIORITY_CLASS|IDLE_PRIORITY_CLASS| \
  1614. HIGH_PRIORITY_CLASS|REALTIME_PRIORITY_CLASS| \
  1615. BELOW_NORMAL_PRIORITY_CLASS|ABOVE_NORMAL_PRIORITY_CLASS)
  1616. BOOL
  1617. WINAPI
  1618. CreateProcessInternalW(
  1619. HANDLE hUserToken,
  1620. LPCWSTR lpApplicationName,
  1621. LPWSTR lpCommandLine,
  1622. LPSECURITY_ATTRIBUTES lpProcessAttributes,
  1623. LPSECURITY_ATTRIBUTES lpThreadAttributes,
  1624. BOOL bInheritHandles,
  1625. DWORD dwCreationFlags,
  1626. LPVOID lpEnvironment,
  1627. LPCWSTR lpCurrentDirectory,
  1628. LPSTARTUPINFOW lpStartupInfo,
  1629. LPPROCESS_INFORMATION lpProcessInformation,
  1630. PHANDLE hRestrictedUserToken
  1631. )
  1632. /*++
  1633. Routine Description:
  1634. This is the worker routine for CreateProcess and CreateProcessAsUser.
  1635. CreateProcessAsUser supplies a User token to be stamped on the new process.
  1636. CreateProcess supplies NULL and the current process token is used.
  1637. A process and thread object are created and a handle opened to each
  1638. object using CreateProcessInternal. Note that WinExec and LoadModule are
  1639. still supported, but are implemented as a call to CreateProcess.
  1640. Arguments:
  1641. hUserToken - Supplies an optional token handle to be set on the new process.
  1642. Process token is used is this parameter is NULL.
  1643. lpApplicationName - Supplies an optional pointer to a null terminated
  1644. character string that contains the name of the image file to
  1645. execute. This is a fully qualified DOS path name. If not
  1646. specified, then the image file name is the first whitespace
  1647. delimited token on the command line.
  1648. lpCommandLine - Supplies a null terminated character string that
  1649. contains the command line for the application to be executed.
  1650. The entire command line is made available to the new process
  1651. using GetCommandLine. If the lpApplicationName parameter was
  1652. not specified, then the first token of the command line
  1653. specifies file name of the application (note that this token
  1654. begins at the beginning of the command line and ends at the
  1655. first "white space" character). If the file name does not
  1656. contain an extension (the presence of a "."), then .EXE is
  1657. assumed. If the file name does not contain a directory path,
  1658. Windows will search for the executable file in:
  1659. - The current directory
  1660. - The windows directory
  1661. - The windows system directory
  1662. - The directories listed in the path environment variable
  1663. This parameter is optional onlu if the lpApplicationName
  1664. parameter is specified. In this case the command line the
  1665. application receives will be the application name.
  1666. lpProcessAttributes - An optional parameter that may be used to
  1667. specify the attributes of the new process. If the parameter is
  1668. not specified, then the process is created without a security
  1669. descriptor, and the resulting handle is not inherited on process
  1670. creation:
  1671. SECURITY_ATTRIBUTES Structure:
  1672. DWORD nLength - Specifies the length of this structure. Must be
  1673. set to sizeof( SECURITY_ATTRUBUTES ).
  1674. LPVOID lpSecurityDescriptor - Points to a security descriptor for
  1675. the object (must be NULL for Win32, used on NT/Win32). The
  1676. security descriptor controls the sharing of an object.
  1677. BOOL bInheritHandle - Supplies a flag that indicates whether
  1678. or not the returned handle is to be inherited by a new
  1679. process during process creation. A value of TRUE
  1680. indicates that the new process will inherit the handle.
  1681. lpThreadAttributes - An optional parameter that may be used to specify
  1682. the attributes of the new thread. If the parameter is not
  1683. specified, then the thread is created without a security
  1684. descriptor, and the resulting handle is not inherited on
  1685. process creation.
  1686. dwCreationFlags - Supplies additional flags that control the creation
  1687. of the process.
  1688. dwCreationFlags Flags:
  1689. DEBUG_PROCESS - If this flag bit is set, then the creating
  1690. process is treated as a debugger, and the process being
  1691. created is created as a debugee. All debug events occuring
  1692. in the debugee are reported to the debugger. If this bit is
  1693. clear, but the calling process is a debugee, then the
  1694. process becomes a debugee of the calling processes debugger.
  1695. If this bit is clear and the calling processes is not a
  1696. debugee then no debug related actions occur.
  1697. DEBUG_ONLY_THIS_PROCESS - If this flag is set, then the
  1698. DEBUG_PROCESS flag bit must also be set. The calling
  1699. process is is treated as a debugger, and the new process is
  1700. created as its debuggee. If the new process creates
  1701. additional processes, no debug related activities (with
  1702. respect to the debugger) occur.
  1703. CREATE_SUSPENDED - The process is created, but the initial thread
  1704. of the process remains suspended. The creator can resume this
  1705. thread using ResumeThread. Until this is done, code in the
  1706. process will not execute.
  1707. CREATE_UNICODE_ENVIRONMENT - If set, the environment pointer
  1708. points to a Unicode environment block. Otherwise, the
  1709. block is ANSI (actually OEM.)
  1710. bInheritHandles - Supplies a flag that specifies whether or not the
  1711. new process is to inherit handles to objects visible to the
  1712. calling process. A value of TRUE causes handles to be inherited
  1713. by the new process. If TRUE was specified, then for each handle
  1714. visible to the calling process, if the handle was created with
  1715. the inherit handle option, the handle is inherited to the new
  1716. process. The handle has the same granted access in the new
  1717. process as it has in the calling process, and the value of the
  1718. handle is the same.
  1719. lpEnvironment - An optional parameter, that if specified, supplies a
  1720. pointer to an environment block. If the parameter is not
  1721. specified, the environment block of the current process is used.
  1722. This environment block is made available to the new process
  1723. using GetEnvironmentStrings.
  1724. lpCurrentDirectory - An optional parameter, that if specified,
  1725. supplies a string representing the current drive and directory
  1726. for the new process. The string must be a fully qualified
  1727. pathname that includes a drive letter. If the parameter is not
  1728. specified, then the new process is created with the same current
  1729. drive and directory as the calling process. This option is
  1730. provided primarily for shells that want to start an application
  1731. and specify its initial drive and working directory.
  1732. lpStartupInfo - Supplies information that specified how the
  1733. applications window is to be shown. This structure is described
  1734. in the Win32 User Interface API Book.
  1735. lpProcessInformation - Returns identification information about the
  1736. new process.
  1737. PROCESS_INFORMATION Structure:
  1738. HANDLE hProcess - Returns a handle to the newly created process.
  1739. Through the handle, all operations on process objects are
  1740. allowed.
  1741. HANDLE hThread - Returns a handle to the newly created thread.
  1742. Through the handle, all operations on thread objects are
  1743. allowed.
  1744. DWORD dwProcessId - Returns a global process id that may be used
  1745. to identify a process. The value is valid from the time the
  1746. process is created until the time the process is terminated.
  1747. DWORD dwThreadId - Returns a global thread id that may be used
  1748. to identify a thread. The value is valid from the time the
  1749. thread is created until the time the thread is terminated.
  1750. hRestrictedUserToken - Returns a restricted token if a UsetToken was
  1751. supplied. This is applicable for the CreateProcessAsUser case.
  1752. The token is released by CreateProcessAsUser.
  1753. Return Value:
  1754. TRUE - The operation was successful
  1755. FALSE/NULL - The operation failed. Extended error status is available
  1756. using GetLastError.
  1757. --*/
  1758. {
  1759. NTSTATUS Status;
  1760. OBJECT_ATTRIBUTES Obja;
  1761. POBJECT_ATTRIBUTES pObja;
  1762. HANDLE ProcessHandle, ThreadHandle, VdmWaitHandle = NULL;
  1763. HANDLE FileHandle, SectionHandle;
  1764. CLIENT_ID ClientId;
  1765. UNICODE_STRING PathName;
  1766. IO_STATUS_BLOCK IoStatusBlock;
  1767. BOOLEAN TranslationStatus;
  1768. RTL_RELATIVE_NAME RelativeName;
  1769. PVOID FreeBuffer;
  1770. LPWSTR NameBuffer;
  1771. LPWSTR WhiteScan;
  1772. ULONG Length,i;
  1773. PROCESS_BASIC_INFORMATION ProcessInfo;
  1774. SECTION_IMAGE_INFORMATION ImageInformation;
  1775. NTSTATUS StackStatus;
  1776. BOOLEAN bStatus;
  1777. INITIAL_TEB InitialTeb;
  1778. CONTEXT ThreadContext;
  1779. PPEB Peb;
  1780. BASE_API_MSG m;
  1781. PBASE_CREATEPROCESS_MSG a = &m.u.CreateProcess;
  1782. PBASE_CHECKVDM_MSG b = &m.u.CheckVDM;
  1783. PWCH TempNull = NULL;
  1784. WCHAR TempChar;
  1785. UNICODE_STRING VdmNameString;
  1786. PVOID BaseAddress;
  1787. ULONG VdmReserve;
  1788. SIZE_T BigVdmReserve;
  1789. ULONG iTask=0;
  1790. LPWSTR CurdirBuffer, CurdirFilePart;
  1791. DWORD CurdirLength,CurdirLength2;
  1792. ULONG VDMCreationState=0;
  1793. ULONG VdmBinaryType = 0;
  1794. BOOL bMeowBinary = FALSE;
  1795. UNICODE_STRING SubSysCommandLine;
  1796. PIMAGE_NT_HEADERS NtHeaders;
  1797. DWORD dwNoWindow = (dwCreationFlags & CREATE_NO_WINDOW);
  1798. ANSI_STRING AnsiStringVDMEnv;
  1799. UNICODE_STRING UnicodeStringVDMEnv;
  1800. WCHAR ImageFileDebuggerCommand[ MAX_PATH ];
  1801. LPWSTR QuotedBuffer;
  1802. BOOLEAN QuoteInsert;
  1803. BOOLEAN QuoteCmdLine = FALSE;
  1804. BOOLEAN QuoteFound;
  1805. BOOL bSaferChecksNeeded = FALSE;
  1806. BOOLEAN SearchRetry;
  1807. BOOLEAN IsWowBinary = FALSE;
  1808. STARTUPINFOW StartupInfo;
  1809. DWORD LastError;
  1810. DWORD fileattr;
  1811. PROCESS_PRIORITY_CLASS PriClass;
  1812. PVOID State;
  1813. HANDLE DebugPortHandle = NULL;
  1814. PVOID pAppCompatDataTemp;
  1815. PVOID pAppCompatData = NULL;
  1816. DWORD cbAppCompatData = 0; // for the future
  1817. BOOLEAN bVdmRetry = FALSE;
  1818. DWORD Flags;
  1819. PVOID pAppCompatSxsData = NULL;
  1820. DWORD cbAppCompatSxsData = 0;
  1821. SXS_OVERRIDE_STREAM AppCompatSxsManifest;
  1822. PCSR_CAPTURE_HEADER CaptureBuffer = NULL;
  1823. SIZE_T SxsConglomeratedBufferSizeBytes;
  1824. PBYTE SxsConglomeratedByteBuffer = NULL; // this contains all the of the below in one large right-sized heap allocation
  1825. // if we compute its size wrong, other code (if it gets it right..) should
  1826. // do more heap allocation
  1827. ULONG sxsi; // for loop counter
  1828. RTL_UNICODE_STRING_BUFFER SxsWin32ManifestPathBuffer;
  1829. RTL_UNICODE_STRING_BUFFER SxsWin32PolicyPathBuffer;
  1830. RTL_UNICODE_STRING_BUFFER SxsWin32AssemblyDirectoryBuffer;
  1831. RTL_UNICODE_STRING_BUFFER SxsNtManifestPathBuffer;
  1832. RTL_UNICODE_STRING_BUFFER SxsNtPolicyPathBuffer;
  1833. const PRTL_UNICODE_STRING_BUFFER SxsStringBuffers[] = {
  1834. // The order here does not matter.
  1835. &SxsWin32ManifestPathBuffer,
  1836. &SxsWin32PolicyPathBuffer,
  1837. &SxsWin32AssemblyDirectoryBuffer,
  1838. &SxsNtManifestPathBuffer,
  1839. &SxsNtPolicyPathBuffer
  1840. };
  1841. UNICODE_STRING SxsWin32ExePath;
  1842. UNICODE_STRING SxsNtExePath;
  1843. BASE_MSG_SXS_HANDLES SxsExeHandles = {0};
  1844. BASE_MSG_SXS_HANDLES SxsManifestFileHandles = {0};
  1845. CONST SXS_CONSTANT_WIN32_NT_PATH_PAIR SxsExePathPair = { &SxsWin32ExePath, &SxsNtExePath };
  1846. CONST SXS_WIN32_NT_PATH_PAIR SxsManifestPathPair = { &SxsWin32ManifestPathBuffer, &SxsNtManifestPathBuffer };
  1847. CONST SXS_WIN32_NT_PATH_PAIR SxsPolicyPathPair = { &SxsWin32PolicyPathBuffer, &SxsNtPolicyPathBuffer };
  1848. BASE_MSG_SXS_HANDLES SxsPolicyHandles = {0};
  1849. PWSTR ExePathFullBuffer = NULL;
  1850. DWORD dwJobMemberLevel = 0;
  1851. HANDLE hSaferAssignmentJob = NULL;
  1852. HANDLE hSaferRestrictedToken = NULL;
  1853. DWORD dwBasePushProcessParametersFlags = 0;
  1854. #if defined(BUILD_WOW6432) || defined(_WIN64)
  1855. BOOLEAN ComPlusILImage;
  1856. LPCWSTR lpOriginalApplicationName = lpApplicationName;
  1857. LPWSTR lpOriginalCommandLine = lpCommandLine;
  1858. #endif
  1859. #if defined(WX86)
  1860. HANDLE Wx86Info = NULL;
  1861. #endif
  1862. #if defined WX86
  1863. BOOLEAN UseKnownWx86Dll;
  1864. UseKnownWx86Dll = NtCurrentTeb()->Wx86Thread.UseKnownWx86Dll;
  1865. NtCurrentTeb()->Wx86Thread.UseKnownWx86Dll = FALSE;
  1866. #endif
  1867. RtlZeroMemory(&a->Sxs, sizeof(a->Sxs));
  1868. RtlZeroMemory(lpProcessInformation,sizeof(*lpProcessInformation));
  1869. if (ARGUMENT_PRESENT( hRestrictedUserToken )) {
  1870. *hRestrictedUserToken = NULL;
  1871. }
  1872. // Private VDM flag should be ignored; Its meant for internal use only.
  1873. dwCreationFlags &= (ULONG)~CREATE_NO_WINDOW;
  1874. if ((dwCreationFlags & (DETACHED_PROCESS | CREATE_NEW_CONSOLE)) ==
  1875. (DETACHED_PROCESS | CREATE_NEW_CONSOLE)) {
  1876. SetLastError(ERROR_INVALID_PARAMETER);
  1877. return FALSE;
  1878. }
  1879. AnsiStringVDMEnv.Buffer = NULL;
  1880. UnicodeStringVDMEnv.Buffer = NULL;
  1881. //
  1882. // the lowest specified priority class is used.
  1883. //
  1884. if (dwCreationFlags & IDLE_PRIORITY_CLASS ) {
  1885. PriClass.PriorityClass = PROCESS_PRIORITY_CLASS_IDLE;
  1886. }
  1887. else if (dwCreationFlags & BELOW_NORMAL_PRIORITY_CLASS ) {
  1888. PriClass.PriorityClass = PROCESS_PRIORITY_CLASS_BELOW_NORMAL;
  1889. }
  1890. else if (dwCreationFlags & NORMAL_PRIORITY_CLASS ) {
  1891. PriClass.PriorityClass = PROCESS_PRIORITY_CLASS_NORMAL;
  1892. }
  1893. else if (dwCreationFlags & ABOVE_NORMAL_PRIORITY_CLASS ) {
  1894. PriClass.PriorityClass = PROCESS_PRIORITY_CLASS_ABOVE_NORMAL;
  1895. }
  1896. else if (dwCreationFlags & HIGH_PRIORITY_CLASS ) {
  1897. PriClass.PriorityClass = PROCESS_PRIORITY_CLASS_HIGH;
  1898. }
  1899. else if (dwCreationFlags & REALTIME_PRIORITY_CLASS ) {
  1900. if ( BasepIsRealtimeAllowed(FALSE) ) {
  1901. PriClass.PriorityClass = PROCESS_PRIORITY_CLASS_REALTIME;
  1902. }
  1903. else {
  1904. PriClass.PriorityClass = PROCESS_PRIORITY_CLASS_HIGH;
  1905. }
  1906. }
  1907. else {
  1908. PriClass.PriorityClass = PROCESS_PRIORITY_CLASS_UNKNOWN;
  1909. }
  1910. PriClass.Foreground = FALSE;
  1911. dwCreationFlags = (dwCreationFlags & ~PRIORITY_CLASS_MASK );
  1912. //
  1913. // Default separate/shared VDM option if not explicitly specified.
  1914. //
  1915. if (dwCreationFlags & CREATE_SEPARATE_WOW_VDM) {
  1916. if (dwCreationFlags & CREATE_SHARED_WOW_VDM) {
  1917. SetLastError(ERROR_INVALID_PARAMETER);
  1918. return FALSE;
  1919. }
  1920. }
  1921. else
  1922. if ((dwCreationFlags & CREATE_SHARED_WOW_VDM) == 0) {
  1923. if (BaseStaticServerData->DefaultSeparateVDM) {
  1924. dwCreationFlags |= CREATE_SEPARATE_WOW_VDM;
  1925. }
  1926. }
  1927. if ((dwCreationFlags & CREATE_SEPARATE_WOW_VDM) == 0) {
  1928. //
  1929. // If the creator is running inside a job object, always
  1930. // set SEPERATE_WOW_VDM so the VDM is part of the job.
  1931. //
  1932. JOBOBJECT_BASIC_UI_RESTRICTIONS UiRestrictions;
  1933. Status = NtQueryInformationJobObject(NULL,
  1934. JobObjectBasicUIRestrictions,
  1935. &UiRestrictions,
  1936. sizeof(UiRestrictions),
  1937. NULL);
  1938. if (Status != STATUS_ACCESS_DENIED) {
  1939. //
  1940. // Anything other than STATUS_ACCESS_DENIED indicates the
  1941. // current process is inside a job.
  1942. //
  1943. dwCreationFlags = (dwCreationFlags & (~CREATE_SHARED_WOW_VDM)) |
  1944. CREATE_SEPARATE_WOW_VDM;
  1945. }
  1946. }
  1947. //
  1948. // If ANSI environment, convert to Unicode
  1949. //
  1950. if (lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT) ) {
  1951. PUCHAR s;
  1952. STRING Ansi;
  1953. UNICODE_STRING Unicode;
  1954. MEMORY_BASIC_INFORMATION MemoryInformation;
  1955. Ansi.Buffer = s = lpEnvironment;
  1956. while (*s || *(s+1)) // find end of block
  1957. s++;
  1958. Ansi.Length = (USHORT)(s - Ansi.Buffer) + 1;
  1959. Ansi.MaximumLength = Ansi.Length + 1;
  1960. MemoryInformation.RegionSize = Ansi.MaximumLength * sizeof(WCHAR);
  1961. Unicode.Buffer = NULL;
  1962. Status = NtAllocateVirtualMemory( NtCurrentProcess(),
  1963. &Unicode.Buffer,
  1964. 0,
  1965. &MemoryInformation.RegionSize,
  1966. MEM_COMMIT,
  1967. PAGE_READWRITE
  1968. );
  1969. if (!NT_SUCCESS(Status) ) {
  1970. BaseSetLastNTError(Status);
  1971. return FALSE;
  1972. }
  1973. Unicode.MaximumLength = (USHORT)MemoryInformation.RegionSize;
  1974. Status = RtlAnsiStringToUnicodeString(&Unicode, &Ansi, FALSE);
  1975. if (!NT_SUCCESS(Status) ) {
  1976. NtFreeVirtualMemory( NtCurrentProcess(),
  1977. &Unicode.Buffer,
  1978. &MemoryInformation.RegionSize,
  1979. MEM_RELEASE
  1980. );
  1981. BaseSetLastNTError(Status);
  1982. return FALSE;
  1983. }
  1984. lpEnvironment = Unicode.Buffer;
  1985. }
  1986. FileHandle = NULL;
  1987. SectionHandle = NULL;
  1988. ProcessHandle = NULL;
  1989. ThreadHandle = NULL;
  1990. FreeBuffer = NULL;
  1991. NameBuffer = NULL;
  1992. VdmNameString.Buffer = NULL;
  1993. BaseAddress = (PVOID)1;
  1994. VdmReserve = 0;
  1995. CurdirBuffer = NULL;
  1996. CurdirFilePart = NULL;
  1997. SubSysCommandLine.Buffer = NULL;
  1998. QuoteFound = FALSE;
  1999. QuoteInsert = FALSE;
  2000. QuotedBuffer = NULL;
  2001. try {
  2002. //
  2003. // Make a copy of the startup info so we can change it.
  2004. //
  2005. StartupInfo = *lpStartupInfo;
  2006. //
  2007. // STARTF_USEHOTKEY means hStdInput is really the hotkey value.
  2008. // STARTF_HASSHELLDATA means std handles are used for shell-private
  2009. // data. This flag is used if an icon is passed to ShellExecuteEx.
  2010. // As a result they cannot be specified with STARTF_USESTDHANDLES.
  2011. // Consistent with Win95, USESTDHANDLES is ignored.
  2012. //
  2013. if (StartupInfo.dwFlags & STARTF_USESTDHANDLES &&
  2014. StartupInfo.dwFlags & (STARTF_USEHOTKEY | STARTF_HASSHELLDATA)) {
  2015. StartupInfo.dwFlags &= ~STARTF_USESTDHANDLES;
  2016. }
  2017. VdmRetry:
  2018. //
  2019. // None of this cleanup/reinit occurs for launching a Win32 or Win64 .exe,
  2020. // but they generally do occur for launching 16bit, .bat, etc.
  2021. //
  2022. if (NameBuffer) {
  2023. RtlFreeHeap(RtlProcessHeap(), 0, NameBuffer);
  2024. NameBuffer = NULL;
  2025. }
  2026. if (FreeBuffer) {
  2027. RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
  2028. FreeBuffer = NULL;
  2029. }
  2030. if (FileHandle) {
  2031. NtClose(FileHandle);
  2032. FileHandle = NULL;
  2033. }
  2034. LastError = 0;
  2035. SearchRetry = TRUE;
  2036. QuoteInsert = FALSE;
  2037. QuoteCmdLine = FALSE;
  2038. if (!ARGUMENT_PRESENT( lpApplicationName )) {
  2039. //
  2040. // Locate the image
  2041. //
  2042. // forgot to free NameBuffer before goto VdmRetry???
  2043. ASSERT(NameBuffer == NULL);
  2044. NameBuffer = RtlAllocateHeap( RtlProcessHeap(),
  2045. MAKE_TAG( TMP_TAG ),
  2046. MAX_PATH * sizeof( WCHAR ));
  2047. if ( !NameBuffer ) {
  2048. BaseSetLastNTError(STATUS_NO_MEMORY);
  2049. return FALSE;
  2050. }
  2051. lpApplicationName = lpCommandLine;
  2052. TempNull = (PWCH)lpApplicationName;
  2053. WhiteScan = (LPWSTR)lpApplicationName;
  2054. //
  2055. // check for lead quote
  2056. //
  2057. if ( *WhiteScan == L'\"' ) {
  2058. SearchRetry = FALSE;
  2059. WhiteScan++;
  2060. lpApplicationName = WhiteScan;
  2061. while(*WhiteScan) {
  2062. if ( *WhiteScan == (WCHAR)'\"' ) {
  2063. TempNull = (PWCH)WhiteScan;
  2064. QuoteFound = TRUE;
  2065. break;
  2066. }
  2067. WhiteScan++;
  2068. TempNull = (PWCH)WhiteScan;
  2069. }
  2070. }
  2071. else {
  2072. retrywsscan:
  2073. lpApplicationName = lpCommandLine;
  2074. while(*WhiteScan) {
  2075. if ( *WhiteScan == (WCHAR)' ' ||
  2076. *WhiteScan == (WCHAR)'\t' ) {
  2077. TempNull = (PWCH)WhiteScan;
  2078. break;
  2079. }
  2080. WhiteScan++;
  2081. TempNull = (PWCH)WhiteScan;
  2082. }
  2083. }
  2084. TempChar = *TempNull;
  2085. *TempNull = UNICODE_NULL;
  2086. #ifdef WX86
  2087. //
  2088. // Wx86 applications must use x86 version of known exes
  2089. // for compatibility.
  2090. //
  2091. if (UseKnownWx86Dll) {
  2092. LPWSTR KnownName;
  2093. NtCurrentTeb()->Wx86Thread.UseKnownWx86Dll = FALSE;
  2094. KnownName = BasepWx86KnownExe(lpApplicationName);
  2095. if (KnownName) {
  2096. lpApplicationName = KnownName;
  2097. }
  2098. }
  2099. #endif
  2100. Length = SearchPathW(
  2101. NULL,
  2102. lpApplicationName,
  2103. L".exe",
  2104. MAX_PATH,
  2105. NameBuffer,
  2106. NULL
  2107. )*2;
  2108. if (Length != 0 && Length < MAX_PATH * sizeof( WCHAR )) {
  2109. //
  2110. // SearchPathW worked, but file might be a directory
  2111. // if this happens, we need to keep trying
  2112. //
  2113. fileattr = GetFileAttributesW(NameBuffer);
  2114. if ( fileattr != 0xffffffff &&
  2115. (fileattr & FILE_ATTRIBUTE_DIRECTORY) ) {
  2116. Length = 0;
  2117. } else {
  2118. Length++;
  2119. Length++;
  2120. }
  2121. }
  2122. if ( !Length || Length >= MAX_PATH<<1 ) {
  2123. //
  2124. // If we search pathed, then return file not found.
  2125. // otherwise, try to be more specific.
  2126. //
  2127. RTL_PATH_TYPE PathType;
  2128. HANDLE hFile;
  2129. PathType = RtlDetermineDosPathNameType_U(lpApplicationName);
  2130. if ( PathType != RtlPathTypeRelative ) {
  2131. //
  2132. // The failed open should set get last error properly.
  2133. //
  2134. hFile = CreateFileW(
  2135. lpApplicationName,
  2136. GENERIC_READ,
  2137. FILE_SHARE_READ | FILE_SHARE_WRITE,
  2138. NULL,
  2139. OPEN_EXISTING,
  2140. FILE_ATTRIBUTE_NORMAL,
  2141. NULL
  2142. );
  2143. if ( hFile != INVALID_HANDLE_VALUE ) {
  2144. CloseHandle(hFile);
  2145. BaseSetLastNTError(STATUS_OBJECT_NAME_NOT_FOUND);
  2146. }
  2147. }
  2148. else {
  2149. BaseSetLastNTError(STATUS_OBJECT_NAME_NOT_FOUND);
  2150. }
  2151. //
  2152. // remember initial last error value for the retry scan path
  2153. //
  2154. if ( LastError ) {
  2155. SetLastError(LastError);
  2156. }
  2157. else {
  2158. LastError = GetLastError();
  2159. }
  2160. //
  2161. // restore the command line
  2162. //
  2163. *TempNull = TempChar;
  2164. lpApplicationName = NameBuffer;
  2165. //
  2166. // If we still have command line left, then keep going
  2167. // the point is to march through the command line looking
  2168. // for whitespace so we can try to find an image name
  2169. // launches of things like:
  2170. // c:\word 95\winword.exe /embedding -automation
  2171. // require this. Our first iteration will stop at c:\word, our next
  2172. // will stop at c:\word 95\winword.exe
  2173. //
  2174. if (*WhiteScan && SearchRetry) {
  2175. WhiteScan++;
  2176. TempNull = WhiteScan;
  2177. QuoteInsert = TRUE;
  2178. QuoteFound = TRUE;
  2179. goto retrywsscan;
  2180. }
  2181. return FALSE;
  2182. }
  2183. //
  2184. // restore the command line
  2185. //
  2186. *TempNull = TempChar;
  2187. lpApplicationName = NameBuffer;
  2188. //
  2189. // check whether it is setup.exe started by winlogon.exe
  2190. //
  2191. if (BasepIsSetupInvokedByWinLogon(lpApplicationName))
  2192. {
  2193. // validate the flag
  2194. if (!(dwCreationFlags & CREATE_IGNORE_SYSTEM_DEFAULT))
  2195. {
  2196. //
  2197. // BUGBUBGUBGUBUGBUGBUGUBGBUGUBGUB
  2198. // Winlogon does not set the flag correctly
  2199. // in phase1, ignore it(now)
  2200. // in phase2, ASSERT it
  2201. // BUGBUBGUBGUBUGBUGBUGUBGBUGUBGUB
  2202. //
  2203. dwCreationFlags |= CREATE_IGNORE_SYSTEM_DEFAULT;
  2204. }
  2205. }
  2206. }
  2207. else
  2208. if (!ARGUMENT_PRESENT( lpCommandLine ) || *lpCommandLine == UNICODE_NULL ) {
  2209. QuoteCmdLine = TRUE;
  2210. lpCommandLine = (LPWSTR)lpApplicationName;
  2211. }
  2212. #ifdef WX86
  2213. //
  2214. // Wx86 applications must use x86 version of known exes
  2215. // for compatibility.
  2216. //
  2217. if (UseKnownWx86Dll) {
  2218. LPWSTR KnownName;
  2219. NtCurrentTeb()->Wx86Thread.UseKnownWx86Dll = FALSE;
  2220. KnownName = BasepWx86KnownExe(lpApplicationName);
  2221. if (KnownName) {
  2222. RtlFreeHeap(RtlProcessHeap(), 0, NameBuffer);
  2223. NameBuffer = KnownName;
  2224. lpApplicationName = KnownName;
  2225. }
  2226. }
  2227. #endif
  2228. //
  2229. // Translate to an NT name.
  2230. //
  2231. TranslationStatus = RtlDosPathNameToNtPathName_U(
  2232. lpApplicationName,
  2233. &PathName,
  2234. NULL,
  2235. &RelativeName
  2236. );
  2237. if ( !TranslationStatus ) {
  2238. SetLastError(ERROR_PATH_NOT_FOUND);
  2239. return FALSE;
  2240. }
  2241. // forgot to free FreeBuffer before goto VdmRetry????
  2242. ASSERT(FreeBuffer == NULL);
  2243. FreeBuffer = PathName.Buffer;
  2244. RtlInitUnicodeString(&SxsWin32ExePath, lpApplicationName);
  2245. {
  2246. RTL_PATH_TYPE SxsWin32ExePathType = RtlDetermineDosPathNameType_U(lpApplicationName);
  2247. if ((SxsWin32ExePathType != RtlPathTypeDriveAbsolute) &&
  2248. (SxsWin32ExePathType != RtlPathTypeUncAbsolute)) {
  2249. if (ExePathFullBuffer == NULL) {
  2250. // It seems that with VDM things, we can rerun this code with a new lpApplication, so
  2251. // we protect against double-allocating the buffer and just allocate a big
  2252. // MAX_PATH one the first time through, assuming it's good enough for the 2ndary times
  2253. // too.
  2254. ExePathFullBuffer = RtlAllocateHeap(RtlProcessHeap(), 0, (MAX_PATH + 1) * sizeof(WCHAR));
  2255. if (ExePathFullBuffer == NULL) {
  2256. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2257. return FALSE;
  2258. }
  2259. }
  2260. RtlGetFullPathName_U(lpApplicationName, (MAX_PATH + 1) * sizeof(WCHAR), ExePathFullBuffer, NULL);
  2261. RtlInitUnicodeString(&SxsWin32ExePath, ExePathFullBuffer);
  2262. }
  2263. }
  2264. SxsNtExePath = PathName;
  2265. if ( RelativeName.RelativeName.Length ) {
  2266. PathName = *(PUNICODE_STRING)&RelativeName.RelativeName;
  2267. }
  2268. else {
  2269. RelativeName.ContainingDirectory = NULL;
  2270. }
  2271. InitializeObjectAttributes(
  2272. &Obja,
  2273. &PathName,
  2274. OBJ_CASE_INSENSITIVE,
  2275. RelativeName.ContainingDirectory,
  2276. NULL
  2277. );
  2278. //
  2279. // Open the file for red and execute access
  2280. //
  2281. Status = NtOpenFile(
  2282. &FileHandle,
  2283. SYNCHRONIZE | FILE_EXECUTE | FILE_READ_ATTRIBUTES | FILE_READ_DATA,
  2284. &Obja,
  2285. &IoStatusBlock,
  2286. FILE_SHARE_READ | FILE_SHARE_DELETE,
  2287. FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE
  2288. );
  2289. if (!NT_SUCCESS(Status) ) {
  2290. //
  2291. // We failed. Open the file for lesser access.
  2292. //
  2293. Status = NtOpenFile(
  2294. &FileHandle,
  2295. SYNCHRONIZE | FILE_EXECUTE,
  2296. &Obja,
  2297. &IoStatusBlock,
  2298. FILE_SHARE_READ | FILE_SHARE_DELETE,
  2299. FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE
  2300. );
  2301. if (!NT_SUCCESS(Status) ) {
  2302. //
  2303. // if we failed, see if this is a device. If it is a device,
  2304. // then just return invalid image format
  2305. //
  2306. if ( RtlIsDosDeviceName_U(RTL_CONST_CAST(PWSTR)(lpApplicationName)) ) {
  2307. SetLastError(ERROR_BAD_DEVICE);
  2308. }
  2309. else {
  2310. BaseSetLastNTError(Status);
  2311. }
  2312. return FALSE;
  2313. }
  2314. }
  2315. //
  2316. // If no desktop has been specified, use the caller's
  2317. // desktop.
  2318. //
  2319. if (StartupInfo.lpDesktop == NULL) {
  2320. StartupInfo.lpDesktop =
  2321. (LPWSTR)((PRTL_USER_PROCESS_PARAMETERS)NtCurrentPeb()->
  2322. ProcessParameters)->DesktopInfo.Buffer;
  2323. }
  2324. //
  2325. // Create a section object backed by the file
  2326. //
  2327. Status = NtCreateSection(
  2328. &SectionHandle,
  2329. SECTION_ALL_ACCESS,
  2330. NULL,
  2331. NULL,
  2332. PAGE_EXECUTE,
  2333. SEC_IMAGE,
  2334. FileHandle
  2335. );
  2336. //
  2337. // App Certification DLL
  2338. //
  2339. if (NT_SUCCESS(Status)) {
  2340. Status = BasepIsProcessAllowed(lpApplicationName);
  2341. if (!NT_SUCCESS(Status)) {
  2342. BaseSetLastNTError(Status);
  2343. NtClose(SectionHandle);
  2344. return FALSE;
  2345. }
  2346. //
  2347. // If Meow subsystem is enabled and caller specified CREATE_FORECEDOS for a win32 image
  2348. // push it into the meow subsystem
  2349. //
  2350. if ((dwCreationFlags & CREATE_FORCEDOS) && BaseStaticServerData->ForceDos) {
  2351. dwCreationFlags &= ~(CREATE_SHARED_WOW_VDM | CREATE_FORCEDOS);
  2352. dwCreationFlags |= CREATE_SEPARATE_WOW_VDM;
  2353. Status = STATUS_INVALID_IMAGE_WIN_16;
  2354. bMeowBinary = TRUE;
  2355. NtClose(SectionHandle);
  2356. SectionHandle = NULL;
  2357. }
  2358. }
  2359. //
  2360. // check appcompat (aka apphelp)
  2361. //
  2362. // if we are running under debugger, bVdmRetry will be FALSE
  2363. // yet pAppCompatData may have some data (from the app itself)
  2364. // debugger will do a separate CreateProcess on debugee
  2365. //
  2366. // apphelp gets called if it is win32 app or if it is a .bat or .cmd
  2367. if(!bVdmRetry &&
  2368. (NT_SUCCESS(Status) ||
  2369. (Status == STATUS_INVALID_IMAGE_NOT_MZ && !BaseIsDosApplication(&PathName,Status)))
  2370. ) {
  2371. NTSTATUS BadAppStatus;
  2372. if (NULL != pAppCompatData) {
  2373. RtlFreeHeap(RtlProcessHeap(), 0, pAppCompatData);
  2374. pAppCompatData = NULL;
  2375. }
  2376. if (NULL != pAppCompatSxsData) {
  2377. RtlFreeHeap(RtlProcessHeap(), 0, pAppCompatSxsData);
  2378. pAppCompatSxsData = NULL;
  2379. }
  2380. //
  2381. // we only check ONCE --
  2382. // the second time around is rather meaningless - to check for posix/ntvdm/os2 emulation
  2383. //
  2384. BadAppStatus = BasepCheckBadapp(FileHandle,
  2385. PathName.Buffer,
  2386. (WCHAR*)lpEnvironment,
  2387. &pAppCompatData,
  2388. &cbAppCompatData,
  2389. &pAppCompatSxsData,
  2390. &cbAppCompatSxsData);
  2391. if (!NT_SUCCESS(BadAppStatus)) {
  2392. if (BadAppStatus == STATUS_ACCESS_DENIED) {
  2393. SetLastError(ERROR_CANCELLED);
  2394. }
  2395. else {
  2396. BaseSetLastNTError(BadAppStatus);
  2397. }
  2398. if (SectionHandle) {
  2399. NtClose(SectionHandle);
  2400. SectionHandle = NULL;
  2401. }
  2402. return FALSE;
  2403. }
  2404. }
  2405. //
  2406. // Winsafer code
  2407. //
  2408. // If this is the first time then we will have to do Safer checks.
  2409. // Note that we do not impose any restrictions on the interpreter
  2410. // itself since it is part of OS.
  2411. //
  2412. if ((!bVdmRetry) &&
  2413. ( (dwCreationFlags & CREATE_PRESERVE_CODE_AUTHZ_LEVEL) == 0 )) {
  2414. NTSTATUS SaferStatus;
  2415. {
  2416. //
  2417. // WinSafer process sandbox restrictions handling.
  2418. // Should be done for non .NET images only.
  2419. //
  2420. SaferStatus = BasepCheckWinSaferRestrictions(
  2421. hUserToken,
  2422. lpApplicationName, // same as PathName.Buffer
  2423. FileHandle,
  2424. &dwJobMemberLevel,
  2425. &hSaferRestrictedToken,
  2426. &hSaferAssignmentJob);
  2427. if (SaferStatus == -1) {
  2428. SetLastError(ERROR_ACCESS_DISABLED_BY_POLICY);
  2429. bStatus = FALSE;
  2430. leave;
  2431. } else if (!NT_SUCCESS(SaferStatus)) {
  2432. BaseSetLastNTError(SaferStatus);
  2433. bStatus = FALSE;
  2434. leave;
  2435. }
  2436. }
  2437. }
  2438. if (!NT_SUCCESS(Status)) {
  2439. switch (Status) {
  2440. // 16 bit OS/2 exe
  2441. case STATUS_INVALID_IMAGE_NE_FORMAT:
  2442. #if defined(i386) && defined(OS2_SUPPORT_ENABLED)
  2443. //
  2444. // Use OS/2 if x86 (OS/2 not supported on risc),
  2445. // and CreationFlags don't have forcedos bit
  2446. // and Registry didn't specify ForceDos
  2447. //
  2448. // else execute as a DOS bound app.
  2449. //
  2450. //
  2451. if (!(dwCreationFlags & CREATE_FORCEDOS) &&
  2452. !BaseStaticServerData->ForceDos)
  2453. {
  2454. if ( !BuildSubSysCommandLine( L"OS2 /P ",
  2455. lpApplicationName,
  2456. lpCommandLine,
  2457. &SubSysCommandLine
  2458. ) ) {
  2459. return FALSE;
  2460. }
  2461. lpCommandLine = SubSysCommandLine.Buffer;
  2462. lpApplicationName = NULL;
  2463. bVdmRetry = TRUE;
  2464. goto VdmRetry;
  2465. }
  2466. #endif
  2467. // Falls into Dos case, so that stub message will be
  2468. // printed, and bound apps will run w/o OS/2 subsytem
  2469. // Dos .exe or .com
  2470. case STATUS_INVALID_IMAGE_PROTECT:
  2471. case STATUS_INVALID_IMAGE_NOT_MZ:
  2472. ForceDos:
  2473. {
  2474. ULONG BinarySubType;
  2475. BinarySubType = BINARY_TYPE_DOS_EXE;
  2476. if (Status == STATUS_INVALID_IMAGE_PROTECT ||
  2477. Status == STATUS_INVALID_IMAGE_NE_FORMAT ||
  2478. (BinarySubType = BaseIsDosApplication(&PathName,Status)) )
  2479. {
  2480. #if defined(_WIN64) || defined(BUILD_WOW6432)
  2481. //
  2482. // If this a DOS application, then we need to pop up a dialog
  2483. // saying that this an invalid win32 application.
  2484. //
  2485. goto RaiseInvalidWin32Error;
  2486. #endif
  2487. VdmBinaryType = BINARY_TYPE_DOS;
  2488. // create the environment before going to the
  2489. // server. This was done becuase we want NTVDM
  2490. // to have the new environment when it gets
  2491. // created.
  2492. if (!BaseCreateVDMEnvironment(
  2493. lpEnvironment,
  2494. &AnsiStringVDMEnv,
  2495. &UnicodeStringVDMEnv
  2496. )) {
  2497. return FALSE;
  2498. }
  2499. if(!BaseCheckVDM(VdmBinaryType | BinarySubType,
  2500. lpApplicationName,
  2501. lpCommandLine,
  2502. lpCurrentDirectory,
  2503. &AnsiStringVDMEnv,
  2504. &m,
  2505. &iTask,
  2506. dwCreationFlags,
  2507. &StartupInfo
  2508. )) {
  2509. return FALSE;
  2510. }
  2511. // Check the return value from the server
  2512. switch (b->VDMState & VDM_STATE_MASK) {
  2513. case VDM_NOT_PRESENT:
  2514. // mark this so the server can undo
  2515. // creation if something goes wrong.
  2516. // We marked it "partially created" because
  2517. // the NTVDM has yet not been fully created.
  2518. // a call to UpdateVdmEntry to update
  2519. // process handle will signal the NTVDM
  2520. // process completed creation
  2521. VDMCreationState = VDM_PARTIALLY_CREATED;
  2522. // fail the call if NTVDM process is being
  2523. // created DETACHED.
  2524. // note that, we let it go if NTVDM process
  2525. // is already running.
  2526. if (dwCreationFlags & DETACHED_PROCESS) {
  2527. SetLastError(ERROR_ACCESS_DENIED);
  2528. return FALSE;
  2529. }
  2530. if (!BaseGetVdmConfigInfo(lpCommandLine,
  2531. iTask,
  2532. VdmBinaryType,
  2533. &VdmNameString,
  2534. &VdmReserve)) {
  2535. BaseSetLastNTError(Status);
  2536. return FALSE;
  2537. }
  2538. lpCommandLine = VdmNameString.Buffer;
  2539. lpApplicationName = NULL;
  2540. break;
  2541. case VDM_PRESENT_NOT_READY:
  2542. SetLastError (ERROR_NOT_READY);
  2543. return FALSE;
  2544. case VDM_PRESENT_AND_READY:
  2545. VDMCreationState = VDM_BEING_REUSED;
  2546. VdmWaitHandle = b->WaitObjectForParent;
  2547. break;
  2548. }
  2549. VdmReserve--; // we reserve from addr 1
  2550. if(VdmWaitHandle)
  2551. goto VdmExists;
  2552. else{
  2553. bInheritHandles = FALSE;
  2554. if (lpEnvironment &&
  2555. !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT)){
  2556. RtlDestroyEnvironment(lpEnvironment);
  2557. }
  2558. lpEnvironment = UnicodeStringVDMEnv.Buffer;
  2559. bVdmRetry = TRUE;
  2560. goto VdmRetry;
  2561. }
  2562. }
  2563. else {
  2564. //
  2565. // must be a .bat or .cmd file
  2566. //
  2567. static PWCHAR CmdPrefix = L"cmd /c ";
  2568. PWCHAR NewCommandLine;
  2569. ULONG Length;
  2570. PWCHAR Last4 = &PathName.Buffer[PathName.Length / sizeof( WCHAR )-4];
  2571. if ( PathName.Length < 8 ) {
  2572. SetLastError(ERROR_BAD_EXE_FORMAT);
  2573. return FALSE;
  2574. }
  2575. if (_wcsnicmp( Last4, L".bat", 4 ) && _wcsnicmp( Last4, L".cmd", 4 )) {
  2576. SetLastError(ERROR_BAD_EXE_FORMAT);
  2577. return FALSE;
  2578. }
  2579. Length = wcslen( CmdPrefix )
  2580. + (QuoteCmdLine || QuoteFound )
  2581. + wcslen( lpCommandLine )
  2582. + (QuoteCmdLine || QuoteFound)
  2583. + 1;
  2584. NewCommandLine = RtlAllocateHeap( RtlProcessHeap( ),
  2585. MAKE_TAG( TMP_TAG ),
  2586. Length * sizeof( WCHAR ) );
  2587. if (NewCommandLine == NULL) {
  2588. BaseSetLastNTError(STATUS_NO_MEMORY);
  2589. return FALSE;
  2590. }
  2591. wcscpy( NewCommandLine, CmdPrefix );
  2592. if (QuoteCmdLine || QuoteFound) {
  2593. wcscat( NewCommandLine, L"\"" );
  2594. }
  2595. wcscat( NewCommandLine, lpCommandLine );
  2596. if (QuoteCmdLine || QuoteFound) {
  2597. wcscat( NewCommandLine, L"\"" );
  2598. }
  2599. RtlInitUnicodeString( &SubSysCommandLine, NewCommandLine );
  2600. lpCommandLine = SubSysCommandLine.Buffer;
  2601. lpApplicationName = NULL;
  2602. bVdmRetry = TRUE;
  2603. goto VdmRetry;
  2604. }
  2605. }
  2606. // 16 bit windows exe
  2607. case STATUS_INVALID_IMAGE_WIN_16:
  2608. #if defined(BUILD_WOW6432) || defined(_WIN64)
  2609. if (lpOriginalApplicationName == NULL) {
  2610. // pass in the part of the command line after the exe name
  2611. // including whitespace
  2612. lpCommandLine = ((*TempNull == '\"') ? TempNull + 1 : TempNull);
  2613. } else {
  2614. lpCommandLine = lpOriginalCommandLine;
  2615. }
  2616. return NtVdm64CreateProcess(lpOriginalApplicationName == NULL,
  2617. lpApplicationName, // this is now the real file name we've loaded
  2618. lpCommandLine,
  2619. lpProcessAttributes,
  2620. lpThreadAttributes,
  2621. bInheritHandles,
  2622. (dwCreationFlags & ~CREATE_UNICODE_ENVIRONMENT), // the environment has already been converted to unicode
  2623. lpEnvironment,
  2624. lpCurrentDirectory,
  2625. lpStartupInfo,
  2626. lpProcessInformation
  2627. );
  2628. #endif
  2629. if (dwCreationFlags & CREATE_FORCEDOS) {
  2630. goto ForceDos;
  2631. }
  2632. IsWowBinary = TRUE;
  2633. if (!BaseCreateVDMEnvironment(lpEnvironment,
  2634. &AnsiStringVDMEnv,
  2635. &UnicodeStringVDMEnv)) {
  2636. return FALSE;
  2637. }
  2638. RetrySepWow:
  2639. VdmBinaryType = dwCreationFlags & CREATE_SEPARATE_WOW_VDM
  2640. ? BINARY_TYPE_SEPWOW : BINARY_TYPE_WIN16;
  2641. if (!BaseCheckVDM(VdmBinaryType,
  2642. lpApplicationName,
  2643. lpCommandLine,
  2644. lpCurrentDirectory,
  2645. &AnsiStringVDMEnv,
  2646. &m,
  2647. &iTask,
  2648. dwCreationFlags,
  2649. &StartupInfo
  2650. ))
  2651. {
  2652. //
  2653. // If we failed with access denied, caller may not
  2654. // be allowed allowed to access the shared wow's
  2655. // desktop, so retry as a separate wow
  2656. //
  2657. if (VdmBinaryType == BINARY_TYPE_WIN16 &&
  2658. GetLastError() == ERROR_ACCESS_DENIED)
  2659. {
  2660. dwCreationFlags |= CREATE_SEPARATE_WOW_VDM;
  2661. }
  2662. else {
  2663. return FALSE;
  2664. }
  2665. goto RetrySepWow;
  2666. }
  2667. // Check the return value from the server
  2668. switch (b->VDMState & VDM_STATE_MASK){
  2669. case VDM_NOT_PRESENT:
  2670. // mark this so the server can undo
  2671. // creation if something goes wrong.
  2672. // We marked it "partitially created" because
  2673. // the NTVDM has yet not been fully created.
  2674. // a call to UpdateVdmEntry to update
  2675. // process handle will signal the NTVDM
  2676. // process completed creation
  2677. VDMCreationState = VDM_PARTIALLY_CREATED;
  2678. // jarbats: 1/8/2001
  2679. // Tell BaseGetVdmConfigInfo to create
  2680. // vdm commandline for meow
  2681. //
  2682. if (bMeowBinary)
  2683. {
  2684. VdmReserve = 1;
  2685. }
  2686. if (!BaseGetVdmConfigInfo(
  2687. lpCommandLine,
  2688. iTask,
  2689. VdmBinaryType,
  2690. &VdmNameString,
  2691. &VdmReserve
  2692. )) {
  2693. BaseSetLastNTError(Status);
  2694. return FALSE;
  2695. }
  2696. lpCommandLine = VdmNameString.Buffer;
  2697. lpApplicationName = NULL;
  2698. //
  2699. // Wow must have a hidden console
  2700. // Throw away DETACHED_PROCESS flag which isn't
  2701. // meaningful for Win16 apps.
  2702. //
  2703. dwCreationFlags |= CREATE_NO_WINDOW;
  2704. dwCreationFlags &= ~(CREATE_NEW_CONSOLE | DETACHED_PROCESS);
  2705. //
  2706. // We're starting a WOW VDM, turn on feedback unless
  2707. // the creator passed STARTF_FORCEOFFFEEDBACK.
  2708. //
  2709. StartupInfo.dwFlags |= STARTF_FORCEONFEEDBACK;
  2710. break;
  2711. case VDM_PRESENT_NOT_READY:
  2712. SetLastError (ERROR_NOT_READY);
  2713. return FALSE;
  2714. case VDM_PRESENT_AND_READY:
  2715. VDMCreationState = VDM_BEING_REUSED;
  2716. VdmWaitHandle = b->WaitObjectForParent;
  2717. break;
  2718. }
  2719. VdmReserve--; // we reserve from addr 1
  2720. if(VdmWaitHandle)
  2721. goto VdmExists;
  2722. else {
  2723. bInheritHandles = FALSE;
  2724. // replace the environment with ours
  2725. if (lpEnvironment &&
  2726. !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT)) {
  2727. RtlDestroyEnvironment(lpEnvironment);
  2728. }
  2729. lpEnvironment = UnicodeStringVDMEnv.Buffer;
  2730. bVdmRetry = TRUE;
  2731. goto VdmRetry;
  2732. }
  2733. case STATUS_FILE_IS_OFFLINE:
  2734. SetLastError(ERROR_FILE_OFFLINE);
  2735. break;
  2736. default :
  2737. SetLastError(ERROR_BAD_EXE_FORMAT);
  2738. return FALSE;
  2739. }
  2740. }
  2741. //
  2742. // Make sure only WOW apps can have the CREATE_SEPARATE_WOW_VDM flag.
  2743. //
  2744. if (!IsWowBinary && (dwCreationFlags & CREATE_SEPARATE_WOW_VDM)) {
  2745. dwCreationFlags &= ~CREATE_SEPARATE_WOW_VDM;
  2746. }
  2747. //
  2748. // Query the section to determine the stack parameters and
  2749. // image entrypoint.
  2750. //
  2751. Status = NtQuerySection(
  2752. SectionHandle,
  2753. SectionImageInformation,
  2754. &ImageInformation,
  2755. sizeof( ImageInformation ),
  2756. NULL
  2757. );
  2758. if (!NT_SUCCESS( Status )) {
  2759. BaseSetLastNTError(Status);
  2760. return FALSE;
  2761. }
  2762. if (ImageInformation.ImageCharacteristics & IMAGE_FILE_DLL) {
  2763. SetLastError(ERROR_BAD_EXE_FORMAT);
  2764. return FALSE;
  2765. }
  2766. ImageFileDebuggerCommand[ 0 ] = UNICODE_NULL;
  2767. if (!(dwCreationFlags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS)) ||
  2768. NtCurrentPeb()->ReadImageFileExecOptions
  2769. ) {
  2770. LdrQueryImageFileExecutionOptions( &PathName,
  2771. L"Debugger",
  2772. REG_SZ,
  2773. ImageFileDebuggerCommand,
  2774. sizeof( ImageFileDebuggerCommand ),
  2775. NULL
  2776. );
  2777. }
  2778. if ((ImageInformation.Machine < USER_SHARED_DATA->ImageNumberLow) ||
  2779. (ImageInformation.Machine > USER_SHARED_DATA->ImageNumberHigh)) {
  2780. #if defined(_WIN64) || defined(BUILD_WOW6432)
  2781. if (ImageInformation.Machine == IMAGE_FILE_MACHINE_I386) {
  2782. // Fall through since this is a valid machine type.
  2783. }
  2784. else
  2785. #endif
  2786. {
  2787. ULONG_PTR ErrorParameters[2];
  2788. ULONG ErrorResponse;
  2789. #if defined(_WIN64) || defined(BUILD_WOW6432)
  2790. RaiseInvalidWin32Error:
  2791. #endif
  2792. ErrorResponse = ResponseOk;
  2793. ErrorParameters[0] = (ULONG_PTR)&PathName;
  2794. NtRaiseHardError( STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE,
  2795. 1,
  2796. 1,
  2797. ErrorParameters,
  2798. OptionOk,
  2799. &ErrorResponse
  2800. );
  2801. if ( NtCurrentPeb()->ImageSubsystemMajorVersion <= 3 ) {
  2802. SetLastError(ERROR_BAD_EXE_FORMAT);
  2803. }
  2804. else {
  2805. SetLastError(ERROR_EXE_MACHINE_TYPE_MISMATCH);
  2806. }
  2807. return FALSE;
  2808. }
  2809. }
  2810. if ( ImageInformation.SubSystemType != IMAGE_SUBSYSTEM_WINDOWS_GUI &&
  2811. ImageInformation.SubSystemType != IMAGE_SUBSYSTEM_WINDOWS_CUI ) {
  2812. // POSIX exe
  2813. NtClose(SectionHandle);
  2814. SectionHandle = NULL;
  2815. if ( ImageInformation.SubSystemType == IMAGE_SUBSYSTEM_POSIX_CUI ) {
  2816. if ( !BuildSubSysCommandLine( L"POSIX /P ",
  2817. lpApplicationName,
  2818. lpCommandLine,
  2819. &SubSysCommandLine
  2820. ) ) {
  2821. return FALSE;
  2822. }
  2823. lpCommandLine = SubSysCommandLine.Buffer;
  2824. lpApplicationName = NULL;
  2825. bVdmRetry = TRUE;
  2826. goto VdmRetry;
  2827. }
  2828. else {
  2829. SetLastError(ERROR_CHILD_NOT_COMPLETE);
  2830. return FALSE;
  2831. }
  2832. }
  2833. else {
  2834. if (!BasepIsImageVersionOk( ImageInformation.SubSystemMajorVersion,
  2835. ImageInformation.SubSystemMinorVersion) ) {
  2836. SetLastError(ERROR_BAD_EXE_FORMAT);
  2837. return FALSE;
  2838. }
  2839. }
  2840. if (ImageFileDebuggerCommand[ 0 ] != UNICODE_NULL) {
  2841. SIZE_T n;
  2842. n = wcslen( lpCommandLine );
  2843. if (n == 0) {
  2844. lpCommandLine = (LPWSTR)lpApplicationName;
  2845. n = wcslen( lpCommandLine );
  2846. }
  2847. n += wcslen( ImageFileDebuggerCommand ) + 1 + 2;
  2848. n *= sizeof( WCHAR );
  2849. SubSysCommandLine.Buffer = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( TMP_TAG ), n );
  2850. SubSysCommandLine.Length = 0;
  2851. SubSysCommandLine.MaximumLength = (USHORT)n;
  2852. RtlAppendUnicodeToString( &SubSysCommandLine, ImageFileDebuggerCommand );
  2853. RtlAppendUnicodeToString( &SubSysCommandLine, L" " );
  2854. RtlAppendUnicodeToString( &SubSysCommandLine, lpCommandLine );
  2855. #if DBG
  2856. DbgPrint( "BASE: Calling debugger with '%wZ'\n", &SubSysCommandLine );
  2857. #endif
  2858. lpCommandLine = SubSysCommandLine.Buffer;
  2859. lpApplicationName = NULL;
  2860. NtClose(SectionHandle);
  2861. SectionHandle = NULL;
  2862. RtlFreeHeap(RtlProcessHeap(), 0, NameBuffer);
  2863. NameBuffer = NULL;
  2864. RtlFreeHeap(RtlProcessHeap(), 0, FreeBuffer);
  2865. FreeBuffer = NULL;
  2866. goto VdmRetry;
  2867. }
  2868. //
  2869. // Create the process object
  2870. //
  2871. pObja = BaseFormatObjectAttributes(&Obja,lpProcessAttributes,NULL);
  2872. Flags = 0;
  2873. if (dwCreationFlags & CREATE_BREAKAWAY_FROM_JOB ) {
  2874. Flags |= PROCESS_CREATE_FLAGS_BREAKAWAY;
  2875. }
  2876. if ( dwCreationFlags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS) ) {
  2877. Status = DbgUiConnectToDbg();
  2878. if ( !NT_SUCCESS(Status) ) {
  2879. BaseSetLastNTError(Status);
  2880. return FALSE;
  2881. }
  2882. DebugPortHandle = DbgUiGetThreadDebugObject ();
  2883. if (dwCreationFlags & DEBUG_ONLY_THIS_PROCESS) {
  2884. Flags |= PROCESS_CREATE_FLAGS_NO_DEBUG_INHERIT;
  2885. }
  2886. }
  2887. if (bInheritHandles) {
  2888. Flags |= PROCESS_CREATE_FLAGS_INHERIT_HANDLES;
  2889. }
  2890. if (((ImageInformation.LoaderFlags & IMAGE_LOADER_FLAGS_COMPLUS) != 0)) {
  2891. #if defined(_WIN64) || defined(BUILD_WOW6432)
  2892. //
  2893. // Check if this is a 32-bit IL_ONLY COM+ image that needs to run natively
  2894. // on Win64.
  2895. //
  2896. if ( ImageInformation.Machine == IMAGE_FILE_MACHINE_I386 ) {
  2897. Status = BasepIsComplusILImage(
  2898. SectionHandle,
  2899. &ImageInformation,
  2900. &ComPlusILImage
  2901. );
  2902. if ((NT_SUCCESS (Status)) && (ComPlusILImage != FALSE)) {
  2903. Flags |= PROCESS_CREATE_FLAGS_OVERRIDE_ADDRESS_SPACE;
  2904. }
  2905. }
  2906. #endif
  2907. }
  2908. //
  2909. // This is temporary till we get Shim dlls support for native Win64 applications.
  2910. //
  2911. if (ImageInformation.Machine != IMAGE_FILE_MACHINE_I386) {
  2912. pAppCompatDataTemp = NULL;
  2913. } else {
  2914. pAppCompatDataTemp = pAppCompatData;
  2915. }
  2916. Status = NtCreateProcessEx(
  2917. &ProcessHandle,
  2918. PROCESS_ALL_ACCESS,
  2919. pObja,
  2920. NtCurrentProcess(),
  2921. Flags,
  2922. SectionHandle,
  2923. DebugPortHandle,
  2924. NULL,
  2925. dwJobMemberLevel // Job member level
  2926. );
  2927. if ( !NT_SUCCESS(Status) ) {
  2928. BaseSetLastNTError(Status);
  2929. return FALSE;
  2930. }
  2931. //
  2932. // NtCreateProcess will set to normal OR inherit if parent is IDLE or Below
  2933. // only override if a mask is given during the create.
  2934. //
  2935. if ( PriClass.PriorityClass != PROCESS_PRIORITY_CLASS_UNKNOWN ) {
  2936. State = NULL;
  2937. if ( PriClass.PriorityClass == PROCESS_PRIORITY_CLASS_REALTIME ) {
  2938. State = BasepIsRealtimeAllowed(TRUE);
  2939. }
  2940. Status = NtSetInformationProcess(
  2941. ProcessHandle,
  2942. ProcessPriorityClass,
  2943. (PVOID)&PriClass,
  2944. sizeof(PriClass)
  2945. );
  2946. if ( State ) {
  2947. BasepReleasePrivilege( State );
  2948. }
  2949. if ( !NT_SUCCESS(Status) ) {
  2950. BaseSetLastNTError(Status);
  2951. return FALSE;
  2952. }
  2953. }
  2954. if (dwCreationFlags & CREATE_DEFAULT_ERROR_MODE) {
  2955. UINT NewMode;
  2956. NewMode = SEM_FAILCRITICALERRORS;
  2957. NtSetInformationProcess(
  2958. ProcessHandle,
  2959. ProcessDefaultHardErrorMode,
  2960. &NewMode,
  2961. sizeof(NewMode)
  2962. );
  2963. }
  2964. //
  2965. // If the process is being created for a VDM call the server with
  2966. // process handle.
  2967. //
  2968. if (VdmBinaryType) {
  2969. VdmWaitHandle = ProcessHandle;
  2970. if (!BaseUpdateVDMEntry(UPDATE_VDM_PROCESS_HANDLE,
  2971. &VdmWaitHandle,
  2972. iTask,
  2973. VdmBinaryType
  2974. ))
  2975. {
  2976. //make sure we don't close the handle twice --
  2977. //(VdmWaitHandle == ProcessHandle) if we don't do this.
  2978. VdmWaitHandle = NULL;
  2979. return FALSE;
  2980. }
  2981. //
  2982. // For Sep wow the VdmWaitHandle = NULL (there is none!)
  2983. //
  2984. VDMCreationState |= VDM_FULLY_CREATED;
  2985. }
  2986. #if defined(i386)
  2987. //
  2988. // Reserve memory in the new process' address space if necessary
  2989. // (for vdms). This is required only for x86 system.
  2990. //
  2991. if ( VdmReserve ) {
  2992. BigVdmReserve = VdmReserve;
  2993. Status = NtAllocateVirtualMemory(
  2994. ProcessHandle,
  2995. &BaseAddress,
  2996. 0L,
  2997. &BigVdmReserve,
  2998. MEM_RESERVE,
  2999. PAGE_EXECUTE_READWRITE
  3000. );
  3001. if ( !NT_SUCCESS(Status) ){
  3002. BaseSetLastNTError(Status);
  3003. return FALSE;
  3004. }
  3005. }
  3006. #endif
  3007. //
  3008. // Abuse the StaticSize fields temporarily.
  3009. // They are somewhat private, but we are using them for temporary space, sort of.
  3010. // These are the right values for them, but we need to call the proper initialization function,
  3011. // which will store the values a second time (possibly optimized away).
  3012. //
  3013. SxsWin32ManifestPathBuffer.ByteBuffer.StaticSize = SxsWin32ExePath.Length + sizeof(SXS_MANIFEST_SUFFIX);
  3014. SxsWin32PolicyPathBuffer.ByteBuffer.StaticSize = SxsWin32ExePath.Length + sizeof(SXS_POLICY_SUFFIX);
  3015. SxsWin32AssemblyDirectoryBuffer.ByteBuffer.StaticSize = SxsWin32ExePath.Length + sizeof(WCHAR); // Win32AssemblyDirectory overestimate
  3016. SxsNtManifestPathBuffer.ByteBuffer.StaticSize = SxsNtExePath.Length + sizeof(SXS_MANIFEST_SUFFIX);
  3017. SxsNtPolicyPathBuffer.ByteBuffer.StaticSize = SxsNtExePath.Length + sizeof(SXS_POLICY_SUFFIX);
  3018. //
  3019. // now add them up as BYTE sizes
  3020. //
  3021. SxsConglomeratedBufferSizeBytes = 0;
  3022. for (sxsi = 0 ; sxsi != RTL_NUMBER_OF(SxsStringBuffers) ; ++sxsi) {
  3023. SxsConglomeratedBufferSizeBytes += SxsStringBuffers[sxsi]->ByteBuffer.StaticSize;
  3024. }
  3025. #if DBG
  3026. DbgPrintEx(
  3027. DPFLTR_SXS_ID,
  3028. DPFLTR_INFO_LEVEL,
  3029. "SXS: SxsConglomeratedBufferSizeBytes:%Id\n",
  3030. SxsConglomeratedBufferSizeBytes
  3031. );
  3032. #endif
  3033. //
  3034. // one honking heap allocation
  3035. //
  3036. SxsConglomeratedByteBuffer = (PBYTE)RtlAllocateHeap(RtlProcessHeap(), 0, SxsConglomeratedBufferSizeBytes);
  3037. if (SxsConglomeratedByteBuffer == NULL) {
  3038. BaseSetLastNTError(STATUS_NO_MEMORY);
  3039. return FALSE;
  3040. }
  3041. //
  3042. // now dole out pieces, calling the proper initialization function
  3043. //
  3044. for (sxsi= 0 ; sxsi != RTL_NUMBER_OF(SxsStringBuffers) ; ++sxsi) {
  3045. RtlInitUnicodeStringBuffer(
  3046. SxsStringBuffers[sxsi],
  3047. (sxsi != 0) ? SxsStringBuffers[sxsi - 1]->ByteBuffer.Buffer + SxsStringBuffers[sxsi- 1]->ByteBuffer.StaticSize
  3048. : SxsConglomeratedByteBuffer,
  3049. SxsStringBuffers[sxsi]->ByteBuffer.StaticSize
  3050. );
  3051. }
  3052. SxsExeHandles.Process = ProcessHandle;
  3053. SxsExeHandles.File = FileHandle;
  3054. // The 1 bit here means something different than in the loader.
  3055. ASSERT((((ULONG_PTR)SectionHandle) & (ULONG_PTR)1) == 0);
  3056. SxsExeHandles.Section = SectionHandle;
  3057. // if we have an override stream, use it
  3058. if (NULL != pAppCompatSxsData) {
  3059. AppCompatSxsManifest.Name = SxsWin32ExePath; // unicode string
  3060. AppCompatSxsManifest.Address = pAppCompatSxsData; // pointer to unicode manifest
  3061. AppCompatSxsManifest.Size = cbAppCompatSxsData; // byte count
  3062. }
  3063. Status = BasepSxsCreateProcessCsrMessage(
  3064. (NULL != pAppCompatSxsData) ? &AppCompatSxsManifest : NULL, // override manifest (appcompat hook)
  3065. NULL, // override policy (appcompat hook)
  3066. &SxsManifestPathPair,
  3067. &SxsManifestFileHandles,
  3068. &SxsExePathPair,
  3069. &SxsExeHandles,
  3070. &SxsPolicyPathPair,
  3071. &SxsPolicyHandles,
  3072. &SxsWin32AssemblyDirectoryBuffer,
  3073. &a->Sxs
  3074. );
  3075. #if DBG
  3076. // verify the buffer size calculation
  3077. for (sxsi = 0 ; sxsi != RTL_NUMBER_OF(SxsStringBuffers) ; ++sxsi)
  3078. {
  3079. if (SxsStringBuffers[sxsi]->ByteBuffer.Buffer != SxsStringBuffers[sxsi]->ByteBuffer.StaticBuffer)
  3080. {
  3081. DbgPrintEx(
  3082. DPFLTR_SXS_ID,
  3083. DPFLTR_WARNING_LEVEL,
  3084. "SXS: SxsStringBuffers[%lu]'s StaticSize was computed too small (%Id, %Id)\n",
  3085. sxsi,
  3086. SxsStringBuffers[sxsi]->ByteBuffer.StaticSize,
  3087. SxsStringBuffers[sxsi]->ByteBuffer.Size
  3088. );
  3089. }
  3090. }
  3091. #endif
  3092. if ( !NT_SUCCESS( Status ) ) {
  3093. BaseSetLastNTError(Status);
  3094. return FALSE;
  3095. }
  3096. //
  3097. // Determine the location of the
  3098. // processes PEB.
  3099. //
  3100. Status = NtQueryInformationProcess(
  3101. ProcessHandle,
  3102. ProcessBasicInformation,
  3103. &ProcessInfo,
  3104. sizeof( ProcessInfo ),
  3105. NULL
  3106. );
  3107. if ( !NT_SUCCESS( Status ) ) {
  3108. BaseSetLastNTError(Status);
  3109. return FALSE;
  3110. }
  3111. Peb = ProcessInfo.PebBaseAddress;
  3112. //
  3113. // Push the parameters into the address space of the new process
  3114. //
  3115. if ( ARGUMENT_PRESENT(lpCurrentDirectory) ) {
  3116. CurdirBuffer = RtlAllocateHeap( RtlProcessHeap(),
  3117. MAKE_TAG( TMP_TAG ),
  3118. (MAX_PATH + 1) * sizeof( WCHAR ) );
  3119. if ( !CurdirBuffer ) {
  3120. BaseSetLastNTError(STATUS_NO_MEMORY);
  3121. return FALSE;
  3122. }
  3123. CurdirLength2 = GetFullPathNameW(
  3124. lpCurrentDirectory,
  3125. MAX_PATH,
  3126. CurdirBuffer,
  3127. &CurdirFilePart
  3128. );
  3129. if ( CurdirLength2 > MAX_PATH ) {
  3130. SetLastError(ERROR_DIRECTORY);
  3131. return FALSE;
  3132. }
  3133. //
  3134. // now make sure the directory exists
  3135. //
  3136. CurdirLength = GetFileAttributesW(CurdirBuffer);
  3137. if ( (CurdirLength == 0xffffffff) ||
  3138. !(CurdirLength & FILE_ATTRIBUTE_DIRECTORY) ) {
  3139. SetLastError(ERROR_DIRECTORY);
  3140. return FALSE;
  3141. }
  3142. }
  3143. if ( QuoteInsert || QuoteCmdLine) {
  3144. QuotedBuffer = RtlAllocateHeap(RtlProcessHeap(),0,wcslen(lpCommandLine)*2+6);
  3145. if ( QuotedBuffer ) {
  3146. wcscpy(QuotedBuffer,L"\"");
  3147. if ( QuoteInsert ) {
  3148. TempChar = *TempNull;
  3149. *TempNull = UNICODE_NULL;
  3150. }
  3151. wcscat(QuotedBuffer,lpCommandLine);
  3152. wcscat(QuotedBuffer,L"\"");
  3153. if ( QuoteInsert ) {
  3154. *TempNull = TempChar;
  3155. wcscat(QuotedBuffer,TempNull);
  3156. }
  3157. }
  3158. else {
  3159. if ( QuoteInsert ) {
  3160. QuoteInsert = FALSE;
  3161. }
  3162. if ( QuoteCmdLine ) {
  3163. QuoteCmdLine = FALSE;
  3164. }
  3165. }
  3166. }
  3167. // If we found a manifest, we want to push that fact to the new process.
  3168. if (a->Sxs.Flags & BASE_MSG_SXS_MANIFEST_PRESENT)
  3169. dwBasePushProcessParametersFlags |= BASE_PUSH_PROCESS_PARAMETERS_FLAG_APP_MANIFEST_PRESENT;
  3170. if (!BasePushProcessParameters(
  3171. dwBasePushProcessParametersFlags,
  3172. ProcessHandle,
  3173. Peb,
  3174. lpApplicationName,
  3175. CurdirBuffer,
  3176. QuoteInsert || QuoteCmdLine ? QuotedBuffer : lpCommandLine,
  3177. lpEnvironment,
  3178. &StartupInfo,
  3179. dwCreationFlags | dwNoWindow,
  3180. bInheritHandles,
  3181. IsWowBinary ? IMAGE_SUBSYSTEM_WINDOWS_GUI : 0,
  3182. pAppCompatDataTemp,
  3183. cbAppCompatData
  3184. ) ) {
  3185. return FALSE;
  3186. }
  3187. RtlFreeUnicodeString(&VdmNameString);
  3188. VdmNameString.Buffer = NULL;
  3189. //
  3190. // Stuff in the standard handles if needed
  3191. //
  3192. if (!VdmBinaryType &&
  3193. !bInheritHandles &&
  3194. !(StartupInfo.dwFlags & STARTF_USESTDHANDLES) &&
  3195. !(dwCreationFlags & (DETACHED_PROCESS | CREATE_NEW_CONSOLE | CREATE_NO_WINDOW)) &&
  3196. ImageInformation.SubSystemType == IMAGE_SUBSYSTEM_WINDOWS_CUI
  3197. ) {
  3198. PRTL_USER_PROCESS_PARAMETERS ParametersInNewProcess;
  3199. Status = NtReadVirtualMemory( ProcessHandle,
  3200. &Peb->ProcessParameters,
  3201. &ParametersInNewProcess,
  3202. sizeof( ParametersInNewProcess ),
  3203. NULL
  3204. );
  3205. if (NT_SUCCESS( Status )) {
  3206. if (!CONSOLE_HANDLE( NtCurrentPeb()->ProcessParameters->StandardInput )) {
  3207. StuffStdHandle( ProcessHandle,
  3208. NtCurrentPeb()->ProcessParameters->StandardInput,
  3209. &ParametersInNewProcess->StandardInput
  3210. );
  3211. }
  3212. if (!CONSOLE_HANDLE( NtCurrentPeb()->ProcessParameters->StandardOutput )) {
  3213. StuffStdHandle( ProcessHandle,
  3214. NtCurrentPeb()->ProcessParameters->StandardOutput,
  3215. &ParametersInNewProcess->StandardOutput
  3216. );
  3217. }
  3218. if (!CONSOLE_HANDLE( NtCurrentPeb()->ProcessParameters->StandardError )) {
  3219. StuffStdHandle( ProcessHandle,
  3220. NtCurrentPeb()->ProcessParameters->StandardError,
  3221. &ParametersInNewProcess->StandardError
  3222. );
  3223. }
  3224. }
  3225. }
  3226. //
  3227. // Create the thread...
  3228. //
  3229. //
  3230. // Allocate a stack for this thread in the address space of the target
  3231. // process.
  3232. //
  3233. StackStatus = BaseCreateStack(
  3234. ProcessHandle,
  3235. ImageInformation.CommittedStackSize,
  3236. (ImageInformation.MaximumStackSize < 256*1024) ? 256*1024 : ImageInformation.MaximumStackSize,
  3237. &InitialTeb
  3238. );
  3239. if ( !NT_SUCCESS(StackStatus) ) {
  3240. BaseSetLastNTError(StackStatus);
  3241. return FALSE;
  3242. }
  3243. //
  3244. // Create an initial context for the new thread.
  3245. //
  3246. BaseInitializeContext(
  3247. &ThreadContext,
  3248. Peb,
  3249. ImageInformation.TransferAddress,
  3250. InitialTeb.StackBase,
  3251. BaseContextTypeProcess
  3252. );
  3253. //
  3254. // Create the actual thread object
  3255. //
  3256. pObja = BaseFormatObjectAttributes(&Obja,lpThreadAttributes,NULL);
  3257. Status = NtCreateThread(
  3258. &ThreadHandle,
  3259. THREAD_ALL_ACCESS,
  3260. pObja,
  3261. ProcessHandle,
  3262. &ClientId,
  3263. &ThreadContext,
  3264. &InitialTeb,
  3265. TRUE
  3266. );
  3267. if (!NT_SUCCESS(Status) ) {
  3268. BaseSetLastNTError(Status);
  3269. return FALSE;
  3270. }
  3271. a->Peb = (ULONGLONG) Peb;
  3272. //
  3273. // From here on out, do not modify the address space of the
  3274. // new process. WOW64's implementation of NtCreateThread()
  3275. // reshuffles the new process' address space if the current
  3276. // process is 32-bit and the new process is 64-bit.
  3277. //
  3278. #if DBG
  3279. Peb = NULL;
  3280. #endif
  3281. #if defined(WX86)
  3282. //
  3283. // if this is a Wx86 Process, setup for a Wx86 emulated Thread
  3284. //
  3285. if (Wx86Info) {
  3286. //
  3287. // create a WX86Tib and initialize it's Teb->Vdm.
  3288. //
  3289. Status = BaseCreateWx86Tib(ProcessHandle,
  3290. ThreadHandle,
  3291. (ULONG)((ULONG_PTR)ImageInformation.TransferAddress),
  3292. (ULONG)ImageInformation.CommittedStackSize,
  3293. (ULONG)ImageInformation.MaximumStackSize,
  3294. TRUE
  3295. );
  3296. if (!NT_SUCCESS(Status)) {
  3297. BaseSetLastNTError(Status);
  3298. return( FALSE );
  3299. }
  3300. //
  3301. // Mark Process as WX86
  3302. //
  3303. Status = NtSetInformationProcess (ProcessHandle,
  3304. ProcessWx86Information,
  3305. &Wx86Info,
  3306. sizeof(Wx86Info)
  3307. );
  3308. if (!NT_SUCCESS(Status)) {
  3309. BaseSetLastNTError(Status);
  3310. return( FALSE );
  3311. }
  3312. }
  3313. #endif
  3314. //
  3315. // Call the Windows server to let it know about the
  3316. // process.
  3317. //
  3318. a->ProcessHandle = ProcessHandle;
  3319. a->ThreadHandle = ThreadHandle;
  3320. a->ClientId = ClientId;
  3321. switch (ImageInformation.Machine) {
  3322. case IMAGE_FILE_MACHINE_I386:
  3323. #if defined(_WIN64) || defined(BUILD_WOW6432)
  3324. a->ProcessorArchitecture = PROCESSOR_ARCHITECTURE_IA32_ON_WIN64;
  3325. #else
  3326. a->ProcessorArchitecture = PROCESSOR_ARCHITECTURE_INTEL;
  3327. #endif
  3328. break;
  3329. case IMAGE_FILE_MACHINE_IA64:
  3330. a->ProcessorArchitecture = PROCESSOR_ARCHITECTURE_IA64;
  3331. break;
  3332. case IMAGE_FILE_MACHINE_AMD64:
  3333. a->ProcessorArchitecture = PROCESSOR_ARCHITECTURE_AMD64;
  3334. break;
  3335. default:
  3336. DbgPrint("kernel32: No mapping for ImageInformation.Machine == %04x\n", ImageInformation.Machine);
  3337. a->ProcessorArchitecture = PROCESSOR_ARCHITECTURE_UNKNOWN;
  3338. break;
  3339. }
  3340. //
  3341. // remove debug flags now its not being done by CSR
  3342. //
  3343. a->CreationFlags = dwCreationFlags & ~ (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS);
  3344. a->DebuggerClientId.UniqueProcess = NULL;
  3345. a->DebuggerClientId.UniqueThread = NULL;
  3346. //
  3347. // Set the 2 bit if a gui app is starting. The window manager needs to
  3348. // know this so it can synchronize the startup of this app
  3349. // (WaitForInputIdle api). This info is passed using the process
  3350. // handle tag bits. The 1 bit asks the window manager to turn on
  3351. // or turn off the application start cursor (hourglass/pointer).
  3352. //
  3353. // When starting a WOW process, lie and tell UserSrv NTVDM.EXE is a GUI
  3354. // process. We also turn on bit 0x8 so that UserSrv can ignore the
  3355. // UserNotifyConsoleApplication call made by the console during startup.
  3356. //
  3357. if ( ImageInformation.SubSystemType == IMAGE_SUBSYSTEM_WINDOWS_GUI ||
  3358. IsWowBinary ) {
  3359. a->ProcessHandle = (HANDLE)((ULONG_PTR)a->ProcessHandle | 2);
  3360. //
  3361. // If the creating process is a GUI app, turn on the app. start cursor
  3362. // by default. This can be overridden by STARTF_FORCEOFFFEEDBACK.
  3363. //
  3364. NtHeaders = RtlImageNtHeader((PVOID)GetModuleHandle(NULL));
  3365. if ( NtHeaders
  3366. && (NtHeaders->OptionalHeader.Subsystem
  3367. == IMAGE_SUBSYSTEM_WINDOWS_GUI ) ) {
  3368. a->ProcessHandle = (HANDLE)((ULONG_PTR)a->ProcessHandle | 1);
  3369. }
  3370. }
  3371. //
  3372. // If feedback is forced on, turn it on. If forced off, turn it off.
  3373. // Off overrides on.
  3374. //
  3375. if (StartupInfo.dwFlags & STARTF_FORCEONFEEDBACK)
  3376. a->ProcessHandle = (HANDLE)((ULONG_PTR)a->ProcessHandle | 1);
  3377. if (StartupInfo.dwFlags & STARTF_FORCEOFFFEEDBACK)
  3378. a->ProcessHandle = (HANDLE)((ULONG_PTR)a->ProcessHandle & ~1);
  3379. a->VdmBinaryType = VdmBinaryType; // just tell server the truth
  3380. if (VdmBinaryType){
  3381. a->hVDM = iTask ? 0 : NtCurrentPeb()->ProcessParameters->ConsoleHandle;
  3382. a->VdmTask = iTask;
  3383. }
  3384. #if defined(BUILD_WOW6432)
  3385. m.ReturnValue = CsrBasepCreateProcess(a);
  3386. #else
  3387. m.u.CreateProcess = *a;
  3388. if (m.u.CreateProcess.Sxs.Flags != 0)
  3389. {
  3390. const PUNICODE_STRING StringsToCapture[] =
  3391. {
  3392. &m.u.CreateProcess.Sxs.Manifest.Path,
  3393. &m.u.CreateProcess.Sxs.Policy.Path,
  3394. &m.u.CreateProcess.Sxs.AssemblyDirectory
  3395. };
  3396. Status =
  3397. CsrCaptureMessageMultiUnicodeStringsInPlace(
  3398. &CaptureBuffer,
  3399. RTL_NUMBER_OF(StringsToCapture),
  3400. StringsToCapture
  3401. );
  3402. if (!NT_SUCCESS(Status)) {
  3403. BaseSetLastNTError(Status);
  3404. return FALSE;
  3405. }
  3406. }
  3407. CsrClientCallServer( (PCSR_API_MSG)&m,
  3408. CaptureBuffer,
  3409. CSR_MAKE_API_NUMBER( BASESRV_SERVERDLL_INDEX,
  3410. BasepCreateProcess
  3411. ),
  3412. sizeof( *a )
  3413. );
  3414. if ( CaptureBuffer ) {
  3415. CsrFreeCaptureBuffer( CaptureBuffer );
  3416. CaptureBuffer = NULL;
  3417. }
  3418. #endif
  3419. if (!NT_SUCCESS((NTSTATUS)m.ReturnValue)) {
  3420. BaseSetLastNTError((NTSTATUS)m.ReturnValue);
  3421. NtTerminateProcess(ProcessHandle, (NTSTATUS)m.ReturnValue);
  3422. return FALSE;
  3423. }
  3424. //
  3425. // If the WinSafer sandboxing policy indicates that the
  3426. // process needs to be run with a restricted token or placed
  3427. // into a restricted job object, then do those actions now.
  3428. // Do not replace the token if the restricted token was created
  3429. // from a caller supplied token i.e. the CreateProcessAsUser case.
  3430. //
  3431. if ((hSaferRestrictedToken != NULL) && (hUserToken == NULL)) {
  3432. Status = BasepReplaceProcessThreadTokens(
  3433. hSaferRestrictedToken,
  3434. ProcessHandle,
  3435. ThreadHandle);
  3436. if (!NT_SUCCESS(Status)) {
  3437. // kill and cleanup.
  3438. NtTerminateProcess(ProcessHandle, Status);
  3439. BaseSetLastNTError(Status);
  3440. return FALSE;
  3441. }
  3442. }
  3443. if (hSaferAssignmentJob != NULL) {
  3444. Status = NtAssignProcessToJobObject(
  3445. hSaferAssignmentJob, ProcessHandle);
  3446. if (!NT_SUCCESS(Status)) {
  3447. // kill and cleanup.
  3448. NtTerminateProcess(ProcessHandle, STATUS_ACCESS_DENIED);
  3449. BaseSetLastNTError(Status);
  3450. return FALSE;
  3451. }
  3452. }
  3453. //
  3454. // Make the thread start execution if we are allowed to.
  3455. //
  3456. if (!( dwCreationFlags & CREATE_SUSPENDED) ) {
  3457. NtResumeThread(ThreadHandle,&i);
  3458. }
  3459. VdmExists:
  3460. bStatus = TRUE;
  3461. if (VDMCreationState)
  3462. VDMCreationState |= VDM_CREATION_SUCCESSFUL;
  3463. try {
  3464. if (VdmWaitHandle) {
  3465. //
  3466. // tag Shared WOW VDM handles so that wait for input idle has a
  3467. // chance to work. Shared WOW VDM "process" handles are actually
  3468. // event handles, Separate WOW VDM handles are real process
  3469. // handles. Also mark DOS handles with 0x1 so WaitForInputIdle
  3470. // has a way to distinguish DOS apps and not block forever.
  3471. //
  3472. if (VdmBinaryType == BINARY_TYPE_WIN16) {
  3473. lpProcessInformation->hProcess =
  3474. (HANDLE)((ULONG_PTR)VdmWaitHandle | 0x2);
  3475. //
  3476. // Shared WOW doesn't always start a process, so
  3477. // we don't have a process ID or thread ID to
  3478. // return if the VDM already existed.
  3479. //
  3480. // Separate WOW doesn't hit this codepath
  3481. // (no VdmWaitHandle).
  3482. //
  3483. if (VDMCreationState & VDM_BEING_REUSED) {
  3484. ClientId.UniqueProcess = 0;
  3485. ClientId.UniqueThread = 0;
  3486. }
  3487. }
  3488. else {
  3489. lpProcessInformation->hProcess =
  3490. (HANDLE)((ULONG_PTR)VdmWaitHandle | 0x1);
  3491. }
  3492. //
  3493. // Close the ProcessHandle, since we are returning the
  3494. // VdmProcessHandle instead.
  3495. //
  3496. if (ProcessHandle != NULL)
  3497. NtClose(ProcessHandle);
  3498. }
  3499. else{
  3500. lpProcessInformation->hProcess = ProcessHandle;
  3501. }
  3502. lpProcessInformation->hThread = ThreadHandle;
  3503. lpProcessInformation->dwProcessId = HandleToUlong(ClientId.UniqueProcess);
  3504. lpProcessInformation->dwThreadId = HandleToUlong(ClientId.UniqueThread);
  3505. ProcessHandle = NULL;
  3506. ThreadHandle = NULL;
  3507. }
  3508. __except ( EXCEPTION_EXECUTE_HANDLER ) {
  3509. NtClose( ProcessHandle );
  3510. NtClose( ThreadHandle );
  3511. ProcessHandle = NULL;
  3512. ThreadHandle = NULL;
  3513. if (VDMCreationState)
  3514. VDMCreationState &= ~VDM_CREATION_SUCCESSFUL;
  3515. }
  3516. }
  3517. __finally {
  3518. if (ExePathFullBuffer != NULL) {
  3519. SxsWin32ExePath.Buffer = NULL;
  3520. SxsWin32ExePath.Length = 0;
  3521. SxsWin32ExePath.MaximumLength = 0;
  3522. RtlFreeHeap(RtlProcessHeap(), 0, ExePathFullBuffer);
  3523. ExePathFullBuffer = NULL;
  3524. }
  3525. if (!VdmBinaryType) {
  3526. NTSTATUS Status1;
  3527. BasepSxsCloseHandles(&SxsManifestFileHandles);
  3528. BasepSxsCloseHandles(&SxsPolicyHandles);
  3529. //
  3530. // don't close SxsExeHandles, they are
  3531. // aliases of other variables that are either closed
  3532. // or returned to the caller
  3533. //
  3534. //
  3535. // This loop only really frees any memory if our computation
  3536. // of the overall buffer size was too low, which it is not supposed to be.
  3537. //
  3538. if (SxsConglomeratedByteBuffer != NULL) {
  3539. for (sxsi= 0 ; sxsi != RTL_NUMBER_OF(SxsStringBuffers) ; ++sxsi) {
  3540. RtlFreeUnicodeStringBuffer(SxsStringBuffers[sxsi]);
  3541. }
  3542. RtlFreeHeap(RtlProcessHeap(), 0,SxsConglomeratedByteBuffer);
  3543. }
  3544. }
  3545. if (lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT) ) {
  3546. RtlDestroyEnvironment(lpEnvironment);
  3547. lpEnvironment = NULL;
  3548. }
  3549. RtlFreeHeap(RtlProcessHeap(), 0,QuotedBuffer);
  3550. RtlFreeHeap(RtlProcessHeap(), 0,NameBuffer);
  3551. RtlFreeHeap(RtlProcessHeap(), 0,CurdirBuffer);
  3552. RtlFreeHeap(RtlProcessHeap(), 0,FreeBuffer);
  3553. if ( FileHandle ) {
  3554. NtClose(FileHandle);
  3555. }
  3556. if ( SectionHandle ) {
  3557. NtClose(SectionHandle);
  3558. }
  3559. if ( ThreadHandle ) {
  3560. NtTerminateProcess(ProcessHandle,STATUS_SUCCESS);
  3561. NtClose(ThreadHandle);
  3562. }
  3563. if ( ProcessHandle ) {
  3564. NtClose(ProcessHandle);
  3565. }
  3566. if ( hSaferAssignmentJob ) {
  3567. NtClose(hSaferAssignmentJob);
  3568. }
  3569. if ( hSaferRestrictedToken ) {
  3570. if (hUserToken == NULL) {
  3571. // CreateProcess case
  3572. NtClose(hSaferRestrictedToken);
  3573. }
  3574. else{
  3575. // CreateProcessAsUser case
  3576. *hRestrictedUserToken = hSaferRestrictedToken;
  3577. }
  3578. }
  3579. if (NULL != pAppCompatData) {
  3580. RtlFreeHeap(RtlProcessHeap(), 0, pAppCompatData);
  3581. }
  3582. if (NULL != pAppCompatSxsData) {
  3583. RtlFreeHeap(RtlProcessHeap(), 0, pAppCompatSxsData);
  3584. }
  3585. RtlFreeUnicodeString(&VdmNameString);
  3586. RtlFreeUnicodeString(&SubSysCommandLine);
  3587. if (AnsiStringVDMEnv.Buffer || UnicodeStringVDMEnv.Buffer)
  3588. BaseDestroyVDMEnvironment(&AnsiStringVDMEnv, &UnicodeStringVDMEnv);
  3589. if (VDMCreationState && !(VDMCreationState & VDM_CREATION_SUCCESSFUL)){
  3590. BaseUpdateVDMEntry (
  3591. UPDATE_VDM_UNDO_CREATION,
  3592. (HANDLE *)&iTask,
  3593. VDMCreationState,
  3594. VdmBinaryType
  3595. );
  3596. if(VdmWaitHandle) {
  3597. NtClose(VdmWaitHandle);
  3598. }
  3599. }
  3600. }
  3601. if (lpEnvironment && !(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT) ) {
  3602. RtlDestroyEnvironment(lpEnvironment);
  3603. }
  3604. return bStatus;
  3605. }
  3606. BOOL
  3607. WINAPI
  3608. CreateProcessW(
  3609. LPCWSTR lpApplicationName,
  3610. LPWSTR lpCommandLine,
  3611. LPSECURITY_ATTRIBUTES lpProcessAttributes,
  3612. LPSECURITY_ATTRIBUTES lpThreadAttributes,
  3613. BOOL bInheritHandles,
  3614. DWORD dwCreationFlags,
  3615. LPVOID lpEnvironment,
  3616. LPCWSTR lpCurrentDirectory,
  3617. LPSTARTUPINFOW lpStartupInfo,
  3618. LPPROCESS_INFORMATION lpProcessInformation
  3619. )
  3620. /*++
  3621. Routine Description:
  3622. A process and thread object are created and a handle opened to each
  3623. object using CreateProcess. Note that WinExec and LoadModule are
  3624. still supported, but are implemented as a call to CreateProcess.
  3625. Arguments:
  3626. lpApplicationName - Supplies an optional pointer to a null terminated
  3627. character string that contains the name of the image file to
  3628. execute. This is a fully qualified DOS path name. If not
  3629. specified, then the image file name is the first whitespace
  3630. delimited token on the command line.
  3631. lpCommandLine - Supplies a null terminated character string that
  3632. contains the command line for the application to be executed.
  3633. The entire command line is made available to the new process
  3634. using GetCommandLine. If the lpApplicationName parameter was
  3635. not specified, then the first token of the command line
  3636. specifies file name of the application (note that this token
  3637. begins at the beginning of the command line and ends at the
  3638. first "white space" character). If the file name does not
  3639. contain an extension (the presence of a "."), then .EXE is
  3640. assumed. If the file name does not contain a directory path,
  3641. Windows will search for the executable file in:
  3642. - The current directory
  3643. - The windows directory
  3644. - The windows system directory
  3645. - The directories listed in the path environment variable
  3646. This parameter is optional onlu if the lpApplicationName
  3647. parameter is specified. In this case the command line the
  3648. application receives will be the application name.
  3649. lpProcessAttributes - An optional parameter that may be used to
  3650. specify the attributes of the new process. If the parameter is
  3651. not specified, then the process is created without a security
  3652. descriptor, and the resulting handle is not inherited on process
  3653. creation:
  3654. SECURITY_ATTRIBUTES Structure:
  3655. DWORD nLength - Specifies the length of this structure. Must be
  3656. set to sizeof( SECURITY_ATTRUBUTES ).
  3657. LPVOID lpSecurityDescriptor - Points to a security descriptor for
  3658. the object (must be NULL for Win32, used on NT/Win32). The
  3659. security descriptor controls the sharing of an object.
  3660. BOOL bInheritHandle - Supplies a flag that indicates whether
  3661. or not the returned handle is to be inherited by a new
  3662. process during process creation. A value of TRUE
  3663. indicates that the new process will inherit the handle.
  3664. lpThreadAttributes - An optional parameter that may be used to specify
  3665. the attributes of the new thread. If the parameter is not
  3666. specified, then the thread is created without a security
  3667. descriptor, and the resulting handle is not inherited on
  3668. process creation.
  3669. dwCreationFlags - Supplies additional flags that control the creation
  3670. of the process.
  3671. dwCreationFlags Flags:
  3672. DEBUG_PROCESS - If this flag bit is set, then the creating
  3673. process is treated as a debugger, and the process being
  3674. created is created as a debugee. All debug events occuring
  3675. in the debugee are reported to the debugger. If this bit is
  3676. clear, but the calling process is a debugee, then the
  3677. process becomes a debugee of the calling processes debugger.
  3678. If this bit is clear and the calling processes is not a
  3679. debugee then no debug related actions occur.
  3680. DEBUG_ONLY_THIS_PROCESS - If this flag is set, then the
  3681. DEBUG_PROCESS flag bit must also be set. The calling
  3682. process is is treated as a debugger, and the new process is
  3683. created as its debuggee. If the new process creates
  3684. additional processes, no debug related activities (with
  3685. respect to the debugger) occur.
  3686. CREATE_SUSPENDED - The process is created, but the initial thread
  3687. of the process remains suspended. The creator can resume this
  3688. thread using ResumeThread. Until this is done, code in the
  3689. process will not execute.
  3690. CREATE_UNICODE_ENVIRONMENT - If set, the environment pointer
  3691. points to a Unicode environment block. Otherwise, the
  3692. block is ANSI (actually OEM.)
  3693. bInheritHandles - Supplies a flag that specifies whether or not the
  3694. new process is to inherit handles to objects visible to the
  3695. calling process. A value of TRUE causes handles to be inherited
  3696. by the new process. If TRUE was specified, then for each handle
  3697. visible to the calling process, if the handle was created with
  3698. the inherit handle option, the handle is inherited to the new
  3699. process. The handle has the same granted access in the new
  3700. process as it has in the calling process, and the value of the
  3701. handle is the same.
  3702. lpEnvironment - An optional parameter, that if specified, supplies a
  3703. pointer to an environment block. If the parameter is not
  3704. specified, the environment block of the current process is used.
  3705. This environment block is made available to the new process
  3706. using GetEnvironmentStrings.
  3707. lpCurrentDirectory - An optional parameter, that if specified,
  3708. supplies a string representing the current drive and directory
  3709. for the new process. The string must be a fully qualified
  3710. pathname that includes a drive letter. If the parameter is not
  3711. specified, then the new process is created with the same current
  3712. drive and directory as the calling process. This option is
  3713. provided primarily for shells that want to start an application
  3714. and specify its initial drive and working directory.
  3715. lpStartupInfo - Supplies information that specified how the
  3716. applications window is to be shown. This structure is described
  3717. in the Win32 User Interface API Book.
  3718. lpProcessInformation - Returns identification information about the
  3719. new process.
  3720. PROCESS_INFORMATION Structure:
  3721. HANDLE hProcess - Returns a handle to the newly created process.
  3722. Through the handle, all operations on process objects are
  3723. allowed.
  3724. HANDLE hThread - Returns a handle to the newly created thread.
  3725. Through the handle, all operations on thread objects are
  3726. allowed.
  3727. DWORD dwProcessId - Returns a global process id that may be used
  3728. to identify a process. The value is valid from the time the
  3729. process is created until the time the process is terminated.
  3730. DWORD dwThreadId - Returns a global thread id that may be used
  3731. to identify a thread. The value is valid from the time the
  3732. thread is created until the time the thread is terminated.
  3733. Return Value:
  3734. TRUE - The operation was successful
  3735. FALSE/NULL - The operation failed. Extended error status is available
  3736. using GetLastError.
  3737. --*/
  3738. {
  3739. return CreateProcessInternalW(
  3740. NULL, // Create new process with the token on the creator process
  3741. lpApplicationName,
  3742. lpCommandLine,
  3743. lpProcessAttributes,
  3744. lpThreadAttributes,
  3745. bInheritHandles,
  3746. dwCreationFlags,
  3747. lpEnvironment,
  3748. lpCurrentDirectory,
  3749. lpStartupInfo,
  3750. lpProcessInformation,
  3751. NULL // Do not return the restricted token
  3752. );
  3753. }
  3754. HANDLE
  3755. WINAPI
  3756. OpenProcess(
  3757. DWORD dwDesiredAccess,
  3758. BOOL bInheritHandle,
  3759. DWORD dwProcessId
  3760. )
  3761. /*++
  3762. Routine Description:
  3763. A handle to a process object may be created using OpenProcess.
  3764. Opening a process creates a handle to the specified process.
  3765. Associated with the process handle is a set of access rights that
  3766. may be performed using the process handle. The caller specifies the
  3767. desired access to the process using the DesiredAccess parameter.
  3768. Arguments:
  3769. mDesiredAccess - Supplies the desired access to the process object.
  3770. For NT/Win32, this access is checked against any security
  3771. descriptor on the target process. The following object type
  3772. specific access flags can be specified in addition to the
  3773. STANDARD_RIGHTS_REQUIRED access flags.
  3774. DesiredAccess Flags:
  3775. PROCESS_DUP_HANDLE - Duplicate object access to the process is
  3776. desired. This access is required in order to duplicate an
  3777. object handle into or out of a process.
  3778. PROCESS_QUERY_INFORMATION - This access is required to read
  3779. certain information from the process object.
  3780. PROCESS_VM_READ - This access is required to read the memory of
  3781. another process.
  3782. PROCESS_VM_WRITE - This access is required to write the memory
  3783. of another process.
  3784. SYNCHRONIZE - This access is required to wait on a process object.
  3785. PROCESS_ALL_ACCESS - This set of access flags specifies all of the
  3786. possible access flags for a process object.
  3787. bInheritHandle - Supplies a flag that indicates whether or not the
  3788. returned handle is to be inherited by a new process during
  3789. process creation. A value of TRUE indicates that the new
  3790. process will inherit the handle.
  3791. dwProcessId - Supplies the process id of the process to open.
  3792. Return Value:
  3793. NON-NULL - Returns an open handle to the specified process. The
  3794. handle may be used by the calling process in any API that
  3795. requires a handle to a process. If the open is successful, the
  3796. handle is granted access to the process object only to the
  3797. extent that it requested access through the DesiredAccess
  3798. parameter.
  3799. NULL - The operation failed. Extended error status is available
  3800. using GetLastError.
  3801. --*/
  3802. {
  3803. NTSTATUS Status;
  3804. OBJECT_ATTRIBUTES Obja;
  3805. HANDLE Handle;
  3806. CLIENT_ID ClientId;
  3807. ClientId.UniqueThread = NULL;
  3808. ClientId.UniqueProcess = LongToHandle(dwProcessId);
  3809. InitializeObjectAttributes(
  3810. &Obja,
  3811. NULL,
  3812. (bInheritHandle ? OBJ_INHERIT : 0),
  3813. NULL,
  3814. NULL
  3815. );
  3816. Status = NtOpenProcess(
  3817. &Handle,
  3818. (ACCESS_MASK)dwDesiredAccess,
  3819. &Obja,
  3820. &ClientId
  3821. );
  3822. if ( NT_SUCCESS(Status) ) {
  3823. return Handle;
  3824. }
  3825. else {
  3826. BaseSetLastNTError(Status);
  3827. return NULL;
  3828. }
  3829. }
  3830. VOID
  3831. WINAPI
  3832. #if defined(_X86_)
  3833. _ExitProcess(
  3834. #else
  3835. ExitProcess(
  3836. #endif
  3837. UINT uExitCode
  3838. )
  3839. /*++
  3840. Routine Description:
  3841. The current process can exit using ExitProcess.
  3842. ExitProcess is the prefered method of exiting an application. This
  3843. API provides a clean application shutdown. This includes calling
  3844. all attached DLLs at their instance termination entrypoint. If an
  3845. application terminates by any other method:
  3846. - TerminateProcess
  3847. - TerminateThread of last thread in the process
  3848. - ExitThread of last thread in the process
  3849. The DLLs that the process is attached to will not be notified of the
  3850. process termination.
  3851. After notifying all DLLs of the process termination, this API
  3852. terminates the current process as if a call to
  3853. TerminateProcess(GetCurrentProcess()) were made.
  3854. Arguments:
  3855. uExitCode - Supplies the termination status for each thread
  3856. in the process.
  3857. Return Value:
  3858. None.
  3859. --*/
  3860. {
  3861. NTSTATUS Status;
  3862. BASE_API_MSG m;
  3863. PBASE_EXITPROCESS_MSG a = &m.u.ExitProcess;
  3864. if ( BaseRunningInServerProcess ) {
  3865. ASSERT(!BaseRunningInServerProcess);
  3866. }
  3867. else {
  3868. RtlAcquirePebLock();
  3869. try {
  3870. Status = NtTerminateProcess(NULL,(NTSTATUS)uExitCode);
  3871. LdrShutdownProcess();
  3872. #if defined(BUILD_WOW6432)
  3873. CsrBasepExitProcess(uExitCode);
  3874. #else
  3875. a->uExitCode = uExitCode;
  3876. CsrClientCallServer( (PCSR_API_MSG)&m,
  3877. NULL,
  3878. CSR_MAKE_API_NUMBER( BASESRV_SERVERDLL_INDEX,
  3879. BasepExitProcess
  3880. ),
  3881. sizeof( *a )
  3882. );
  3883. #endif
  3884. NtTerminateProcess(NtCurrentProcess(),(NTSTATUS)uExitCode);
  3885. }
  3886. finally {
  3887. RtlReleasePebLock();
  3888. }
  3889. }
  3890. }
  3891. #if defined(_X86_)
  3892. // Appcompat: There's code that depends on the old EH frame setup/teardown. Simulate it here
  3893. // then call the real function. ExitProcess is a no-return function so don't bother cleaning up.
  3894. __declspec(naked) VOID WINAPI ExitProcess( UINT uExitCode )
  3895. {
  3896. __asm {
  3897. push ebp
  3898. mov ebp,esp
  3899. push -1
  3900. push 0x77e8f3b0
  3901. push uExitCode
  3902. call _ExitProcess
  3903. }
  3904. }
  3905. #endif
  3906. BOOL
  3907. WINAPI
  3908. TerminateProcess(
  3909. HANDLE hProcess,
  3910. UINT uExitCode
  3911. )
  3912. /*++
  3913. Routine Description:
  3914. A process and all of its threads may be terminated using
  3915. TerminateProcess.
  3916. TerminateProcess is used to cause all of the threads within a
  3917. process to terminate.
  3918. While TerminateProcess will cause all threads within a process to
  3919. terminate, and will cause an application to exit, it does not notify
  3920. DLLs that the process is attached to that the process is
  3921. terminating. TerminateProcess is used to unconditionally cause a
  3922. process to exit. It should only be used in extreme circumstances.
  3923. The state of global data maintained by DLLs may be comprimised if
  3924. TerminateProcess is used rather that ExitProcess.
  3925. Once all of the threads have terminated, the process attains a state
  3926. of signaled satisfying any waits on the process. The process's
  3927. termination status is updated from its initial value of
  3928. STATUS_PENDING to the termination status of the last thread in the
  3929. process to terminate (usually this is the same value as the
  3930. TerminationStatus parameter). Terminating a process does not remove
  3931. a process from the system. It simply causes all of the threads in
  3932. the process to terminate their execution, and causes all of the
  3933. object handles opened by the process to be closed. The process is
  3934. not removed from the system until the last handle to the process is
  3935. closed.
  3936. Arguments:
  3937. hProcess - Supplies a handle to the process to terminate. The handle
  3938. must have been created with PROCESS_TERMINATE access.
  3939. uExitCode - Supplies the termination status for each thread
  3940. in the process.
  3941. Return Value:
  3942. TRUE - The operation was successful
  3943. FALSE/NULL - The operation failed. Extended error status is available
  3944. using GetLastError.
  3945. --*/
  3946. {
  3947. NTSTATUS Status;
  3948. if ( hProcess == NULL ) {
  3949. SetLastError(ERROR_INVALID_HANDLE);
  3950. return FALSE;
  3951. }
  3952. Status = NtTerminateProcess(hProcess,(NTSTATUS)uExitCode);
  3953. if ( NT_SUCCESS(Status) ) {
  3954. return TRUE;
  3955. }
  3956. else {
  3957. BaseSetLastNTError(Status);
  3958. return FALSE;
  3959. }
  3960. }
  3961. BOOL
  3962. WINAPI
  3963. GetExitCodeProcess(
  3964. HANDLE hProcess,
  3965. LPDWORD lpExitCode
  3966. )
  3967. /*++
  3968. Routine Description:
  3969. The termination status of a process can be read using
  3970. GetExitCodeProcess.
  3971. If a process is in the signaled state, calling this function returns
  3972. the termination status of the process.
  3973. If the process is not yet signaled, the termination
  3974. status returned is STILL_ACTIVE.
  3975. Arguments:
  3976. hProcess - Supplies a handle to the process whose termination status
  3977. is to be read. The handle must have been created with
  3978. PROCESS_QUERY_INFORMATION access.
  3979. lpExitCode - Returns the current termination status of the process.
  3980. Return Value:
  3981. TRUE - The operation was successful
  3982. FALSE/NULL - The operation failed. Extended error status is available
  3983. using GetLastError.
  3984. --*/
  3985. {
  3986. NTSTATUS Status;
  3987. PROCESS_BASIC_INFORMATION BasicInformation;
  3988. if (BaseCheckForVDM (hProcess,lpExitCode) == TRUE)
  3989. return TRUE;
  3990. Status = NtQueryInformationProcess(
  3991. hProcess,
  3992. ProcessBasicInformation,
  3993. &BasicInformation,
  3994. sizeof(BasicInformation),
  3995. NULL
  3996. );
  3997. if ( NT_SUCCESS(Status) ) {
  3998. *lpExitCode = BasicInformation.ExitStatus;
  3999. return TRUE;
  4000. }
  4001. else {
  4002. BaseSetLastNTError(Status);
  4003. return FALSE;
  4004. }
  4005. }
  4006. VOID
  4007. WINAPI
  4008. GetStartupInfoW(
  4009. LPSTARTUPINFOW lpStartupInfo
  4010. )
  4011. /*++
  4012. Routine Description:
  4013. The startup information for the current process is available using this
  4014. API.
  4015. Arguments:
  4016. lpStartupInfo - a pointer to a STARTUPINFO structure that will be filed
  4017. in by the API. The pointer fields of the structure will point
  4018. to static strings.
  4019. Return Value:
  4020. None.
  4021. --*/
  4022. {
  4023. PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
  4024. ProcessParameters = NtCurrentPeb()->ProcessParameters;
  4025. lpStartupInfo->cb = sizeof( *lpStartupInfo );
  4026. lpStartupInfo->lpReserved = (LPWSTR)ProcessParameters->ShellInfo.Buffer;
  4027. lpStartupInfo->lpDesktop = (LPWSTR)ProcessParameters->DesktopInfo.Buffer;
  4028. lpStartupInfo->lpTitle = (LPWSTR)ProcessParameters->WindowTitle.Buffer;
  4029. lpStartupInfo->dwX = ProcessParameters->StartingX;
  4030. lpStartupInfo->dwY = ProcessParameters->StartingY;
  4031. lpStartupInfo->dwXSize = ProcessParameters->CountX;
  4032. lpStartupInfo->dwYSize = ProcessParameters->CountY;
  4033. lpStartupInfo->dwXCountChars = ProcessParameters->CountCharsX;
  4034. lpStartupInfo->dwYCountChars = ProcessParameters->CountCharsY;
  4035. lpStartupInfo->dwFillAttribute = ProcessParameters->FillAttribute;
  4036. lpStartupInfo->dwFlags = ProcessParameters->WindowFlags;
  4037. lpStartupInfo->wShowWindow = (WORD)ProcessParameters->ShowWindowFlags;
  4038. lpStartupInfo->cbReserved2 = ProcessParameters->RuntimeData.Length;
  4039. lpStartupInfo->lpReserved2 = (LPBYTE)ProcessParameters->RuntimeData.Buffer;
  4040. if (lpStartupInfo->dwFlags & (STARTF_USESTDHANDLES | STARTF_USEHOTKEY | STARTF_HASSHELLDATA)) {
  4041. lpStartupInfo->hStdInput = ProcessParameters->StandardInput;
  4042. lpStartupInfo->hStdOutput = ProcessParameters->StandardOutput;
  4043. lpStartupInfo->hStdError = ProcessParameters->StandardError;
  4044. }
  4045. return;
  4046. }
  4047. VOID
  4048. WINAPI
  4049. GetStartupInfoA(
  4050. LPSTARTUPINFOA lpStartupInfo
  4051. )
  4052. /*++
  4053. Routine Description:
  4054. The startup information for the current process is available using this
  4055. API.
  4056. Arguments:
  4057. lpStartupInfo - a pointer to a STARTUPINFO structure that will be filed
  4058. in by the API. The pointer fields of the structure will point
  4059. to static strings.
  4060. Return Value:
  4061. None.
  4062. --*/
  4063. {
  4064. PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
  4065. NTSTATUS Status;
  4066. ANSI_STRING AnsiString;
  4067. ProcessParameters = NtCurrentPeb()->ProcessParameters;
  4068. RtlAcquirePebLock();
  4069. try {
  4070. if ( !BaseAnsiStartupInfo ) {
  4071. BaseAnsiStartupInfo = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), sizeof(*BaseAnsiStartupInfo));
  4072. if (!BaseAnsiStartupInfo) {
  4073. RtlRaiseStatus(STATUS_NO_MEMORY);
  4074. }
  4075. BaseAnsiStartupInfo->cb = sizeof( *BaseAnsiStartupInfo );
  4076. BaseAnsiStartupInfo->dwX = ProcessParameters->StartingX;
  4077. BaseAnsiStartupInfo->dwY = ProcessParameters->StartingY;
  4078. BaseAnsiStartupInfo->dwXSize = ProcessParameters->CountX;
  4079. BaseAnsiStartupInfo->dwYSize = ProcessParameters->CountY;
  4080. BaseAnsiStartupInfo->dwXCountChars = ProcessParameters->CountCharsX;
  4081. BaseAnsiStartupInfo->dwYCountChars = ProcessParameters->CountCharsY;
  4082. BaseAnsiStartupInfo->dwFillAttribute = ProcessParameters->FillAttribute;
  4083. BaseAnsiStartupInfo->dwFlags = ProcessParameters->WindowFlags;
  4084. BaseAnsiStartupInfo->wShowWindow = (WORD)ProcessParameters->ShowWindowFlags;
  4085. BaseAnsiStartupInfo->cbReserved2 = ProcessParameters->RuntimeData.Length;
  4086. BaseAnsiStartupInfo->lpReserved2 = (LPBYTE)ProcessParameters->RuntimeData.Buffer;
  4087. BaseAnsiStartupInfo->hStdInput = ProcessParameters->StandardInput;
  4088. BaseAnsiStartupInfo->hStdOutput = ProcessParameters->StandardOutput;
  4089. BaseAnsiStartupInfo->hStdError = ProcessParameters->StandardError;
  4090. BaseAnsiStartupInfo->lpReserved = NULL;
  4091. BaseAnsiStartupInfo->lpDesktop = NULL;
  4092. BaseAnsiStartupInfo->lpTitle = NULL;
  4093. Status = RtlUnicodeStringToAnsiString(&AnsiString,&ProcessParameters->ShellInfo,TRUE);
  4094. if ( !NT_SUCCESS(Status) ) {
  4095. RtlRaiseStatus(Status);
  4096. }
  4097. else {
  4098. BaseAnsiStartupInfo->lpReserved = AnsiString.Buffer;
  4099. }
  4100. Status = RtlUnicodeStringToAnsiString(&AnsiString,&ProcessParameters->DesktopInfo,TRUE);
  4101. if ( !NT_SUCCESS(Status) ) {
  4102. RtlRaiseStatus(Status);
  4103. }
  4104. else {
  4105. BaseAnsiStartupInfo->lpDesktop = AnsiString.Buffer;
  4106. }
  4107. Status = RtlUnicodeStringToAnsiString(&AnsiString,&ProcessParameters->WindowTitle,TRUE);
  4108. if ( !NT_SUCCESS(Status) ) {
  4109. RtlRaiseStatus(Status);
  4110. }
  4111. else {
  4112. BaseAnsiStartupInfo->lpTitle = AnsiString.Buffer;
  4113. }
  4114. }
  4115. }
  4116. finally {
  4117. RtlReleasePebLock();
  4118. }
  4119. lpStartupInfo->cb = BaseAnsiStartupInfo->cb ;
  4120. lpStartupInfo->lpReserved = BaseAnsiStartupInfo->lpReserved ;
  4121. lpStartupInfo->lpDesktop = BaseAnsiStartupInfo->lpDesktop ;
  4122. lpStartupInfo->lpTitle = BaseAnsiStartupInfo->lpTitle ;
  4123. lpStartupInfo->dwX = BaseAnsiStartupInfo->dwX ;
  4124. lpStartupInfo->dwY = BaseAnsiStartupInfo->dwY ;
  4125. lpStartupInfo->dwXSize = BaseAnsiStartupInfo->dwXSize ;
  4126. lpStartupInfo->dwYSize = BaseAnsiStartupInfo->dwYSize ;
  4127. lpStartupInfo->dwXCountChars = BaseAnsiStartupInfo->dwXCountChars;
  4128. lpStartupInfo->dwYCountChars = BaseAnsiStartupInfo->dwYCountChars;
  4129. lpStartupInfo->dwFillAttribute = BaseAnsiStartupInfo->dwFillAttribute;
  4130. lpStartupInfo->dwFlags = BaseAnsiStartupInfo->dwFlags ;
  4131. lpStartupInfo->wShowWindow = BaseAnsiStartupInfo->wShowWindow;
  4132. lpStartupInfo->cbReserved2 = BaseAnsiStartupInfo->cbReserved2;
  4133. lpStartupInfo->lpReserved2 = BaseAnsiStartupInfo->lpReserved2;
  4134. if (lpStartupInfo->dwFlags & (STARTF_USESTDHANDLES | STARTF_USEHOTKEY | STARTF_HASSHELLDATA)) {
  4135. lpStartupInfo->hStdInput = BaseAnsiStartupInfo->hStdInput;
  4136. lpStartupInfo->hStdOutput = BaseAnsiStartupInfo->hStdOutput;
  4137. lpStartupInfo->hStdError = BaseAnsiStartupInfo->hStdError;
  4138. }
  4139. else {
  4140. lpStartupInfo->hStdInput = INVALID_HANDLE_VALUE;
  4141. lpStartupInfo->hStdOutput = INVALID_HANDLE_VALUE;
  4142. lpStartupInfo->hStdError = INVALID_HANDLE_VALUE;
  4143. }
  4144. return;
  4145. }
  4146. LPSTR
  4147. WINAPI
  4148. GetCommandLineA(
  4149. VOID
  4150. )
  4151. /*++
  4152. Routine Description:
  4153. The command line of the current process is available using this
  4154. API.
  4155. Arguments:
  4156. None.
  4157. Return Value:
  4158. The address of the current processes command line is returned. The
  4159. return value is a pointer to null terminate string.
  4160. --*/
  4161. {
  4162. return (LPSTR)BaseAnsiCommandLine.Buffer;
  4163. }
  4164. LPWSTR
  4165. WINAPI
  4166. GetCommandLineW(
  4167. VOID
  4168. )
  4169. /*++
  4170. Routine Description:
  4171. The command line of the current process is available using this
  4172. API.
  4173. Arguments:
  4174. None.
  4175. Return Value:
  4176. The address of the current processes command line is returned. The
  4177. return value is a pointer to null terminate string.
  4178. --*/
  4179. {
  4180. return BaseUnicodeCommandLine.Buffer;
  4181. }
  4182. BOOL
  4183. WINAPI
  4184. FreeEnvironmentStringsW(
  4185. LPWSTR penv
  4186. )
  4187. /*++
  4188. Routine Description:
  4189. This API is intended to be called after the environment block
  4190. pointer returned by GetEnvironmentStringsW is no longer needed.
  4191. Arguments:
  4192. None.
  4193. Return Value:
  4194. TRUE, since the process environment block is never freed until
  4195. the process terminates.
  4196. --*/
  4197. {
  4198. UNREFERENCED_PARAMETER(penv);
  4199. return TRUE;
  4200. }
  4201. BOOL
  4202. WINAPI
  4203. FreeEnvironmentStringsA(
  4204. LPSTR penv
  4205. )
  4206. /*++
  4207. Routine Description:
  4208. This API is intended to be called after the environment block
  4209. pointer returned by GetEnvironmentStringsA is no longer needed.
  4210. Arguments:
  4211. None.
  4212. Return Value:
  4213. The return code from RtlFreeHeap.
  4214. --*/
  4215. {
  4216. return RtlFreeHeap(RtlProcessHeap(), 0, penv );
  4217. }
  4218. LPWSTR
  4219. WINAPI
  4220. GetEnvironmentStringsW(
  4221. VOID
  4222. )
  4223. /*++
  4224. Routine Description:
  4225. The environment strings of the current process are available using
  4226. this API.
  4227. Arguments:
  4228. None.
  4229. Return Value:
  4230. The address of the current processes environment block is returned.
  4231. The block is opaque and must only be interpreted via the environment
  4232. variable access functions.
  4233. --*/
  4234. {
  4235. return (LPWSTR)NtCurrentPeb()->ProcessParameters->Environment;
  4236. }
  4237. LPSTR
  4238. WINAPI
  4239. GetEnvironmentStrings(
  4240. VOID
  4241. )
  4242. /*++
  4243. Routine Description:
  4244. The environment strings of the current process are available using
  4245. this API.
  4246. Arguments:
  4247. None.
  4248. Return Value:
  4249. The address of the current processes environment block is returned.
  4250. The block is opaque and must only be interpreted via the environment
  4251. variable access functions.
  4252. --*/
  4253. {
  4254. NTSTATUS Status;
  4255. LPWSTR pUnicode;
  4256. USHORT cch = 0;
  4257. UNICODE_STRING Unicode;
  4258. OEM_STRING Buffer;
  4259. pUnicode = (LPWSTR)NtCurrentPeb()->ProcessParameters->Environment;
  4260. Unicode.Buffer = pUnicode;
  4261. while ( (*pUnicode) || (*(pUnicode+1))) {
  4262. cch++;
  4263. pUnicode++;
  4264. }
  4265. // Go for worst case
  4266. Buffer.Buffer = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( ENV_TAG ), (cch+2)*sizeof(WCHAR));
  4267. if (Buffer.Buffer == NULL) {
  4268. BaseSetLastNTError( STATUS_NO_MEMORY );
  4269. return NULL;
  4270. }
  4271. Buffer.Length = Buffer.MaximumLength = (cch + 2) * sizeof(WCHAR);
  4272. Unicode.Length = Unicode.MaximumLength = (cch + 2) * sizeof(WCHAR);
  4273. Status = RtlUnicodeStringToOemString(&Buffer, &Unicode, FALSE);
  4274. if (!NT_SUCCESS( Status )) {
  4275. BaseSetLastNTError( Status );
  4276. RtlFreeHeap( RtlProcessHeap(), 0, Buffer.Buffer );
  4277. }
  4278. return Buffer.Buffer;
  4279. }
  4280. DWORD
  4281. WINAPI
  4282. GetEnvironmentVariableA(
  4283. LPCSTR lpName,
  4284. LPSTR lpBuffer,
  4285. DWORD nSize
  4286. )
  4287. /*++
  4288. Routine Description:
  4289. The value of an environment variable of the current process is available
  4290. using this API.
  4291. Arguments:
  4292. lpName - Pointer to a null terminate string that is the name of the
  4293. environment variable whose value is being requested.
  4294. lpBuffer - Pointer to a buffer that is to contain the value of the
  4295. specified variable name.
  4296. nSize - Specifies the maximum number of bytes that can be stored in
  4297. the buffer pointed to by lpBuffer, including the null terminator.
  4298. Return Value:
  4299. The actual number of bytes stored in the memory pointed to by the
  4300. lpBuffer parameter. The return value is zero if the environment
  4301. variable name was not found in the current process's environment.
  4302. On successful return (returned value < nSize) the returned value
  4303. does not include the null terminator byte. On buffer overflow failure
  4304. (returned value > nSize), the returned value does include the null
  4305. terminator byte.
  4306. --*/
  4307. {
  4308. NTSTATUS Status;
  4309. NTSTATUS Status2;
  4310. STRING Value, Name;
  4311. UNICODE_STRING UnicodeName;
  4312. UNICODE_STRING UnicodeValue;
  4313. DWORD iSize;
  4314. RtlInitString( &Name, lpName );
  4315. Status = RtlAnsiStringToUnicodeString( &UnicodeName, &Name, TRUE );
  4316. if (!NT_SUCCESS( Status )) {
  4317. BaseSetLastNTError( Status );
  4318. return ( 0 );
  4319. }
  4320. if ( nSize > (MAXUSHORT >> 1)-2 ) {
  4321. iSize = (MAXUSHORT >> 1)-2;
  4322. }
  4323. else {
  4324. iSize = nSize;
  4325. }
  4326. UnicodeValue.MaximumLength = (USHORT)(iSize ? iSize - 1 : iSize)*sizeof(WCHAR);
  4327. UnicodeValue.Buffer = (PWCHAR)
  4328. RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( TMP_TAG ), UnicodeValue.MaximumLength );
  4329. if (UnicodeValue.Buffer == NULL) {
  4330. BaseSetLastNTError( STATUS_NO_MEMORY );
  4331. return ( 0 );
  4332. }
  4333. Status = RtlQueryEnvironmentVariable_U( NULL,
  4334. &UnicodeName,
  4335. &UnicodeValue
  4336. );
  4337. if (NT_SUCCESS( Status ) && (nSize == 0)) {
  4338. Status = STATUS_BUFFER_OVERFLOW; // No room for terminator
  4339. }
  4340. if( Status != STATUS_BUFFER_TOO_SMALL ) RtlFreeUnicodeString( &UnicodeName );
  4341. if (NT_SUCCESS( Status )) {
  4342. if ( nSize > MAXUSHORT-2 ) {
  4343. iSize = MAXUSHORT-2;
  4344. }
  4345. else {
  4346. iSize = nSize;
  4347. }
  4348. Value.Buffer = lpBuffer;
  4349. Value.MaximumLength = (USHORT)iSize;
  4350. Status2 = RtlUnicodeStringToAnsiString( &Value, &UnicodeValue, FALSE );
  4351. RtlFreeHeap( RtlProcessHeap(), 0, UnicodeValue.Buffer );
  4352. if (!NT_SUCCESS( Status2 )) {
  4353. BaseSetLastNTError( Status2 );
  4354. return ( 0 );
  4355. }
  4356. lpBuffer[ Value.Length ] = '\0';
  4357. return( Value.Length );
  4358. }
  4359. else {
  4360. RtlFreeHeap( RtlProcessHeap(), 0, UnicodeValue.Buffer );
  4361. if ( Status == STATUS_BUFFER_TOO_SMALL ) {
  4362. DWORD dwAnsiStringSize = 0;
  4363. UnicodeValue.MaximumLength = UnicodeValue.Length + sizeof(WCHAR); // for NULL
  4364. UnicodeValue.Buffer = (PWCHAR)
  4365. RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( TMP_TAG ), UnicodeValue.MaximumLength );
  4366. if (UnicodeValue.Buffer == NULL) {
  4367. BaseSetLastNTError( STATUS_NO_MEMORY );
  4368. return ( 0 );
  4369. }
  4370. Status = RtlQueryEnvironmentVariable_U( NULL ,
  4371. &UnicodeName ,
  4372. &UnicodeValue
  4373. );
  4374. RtlFreeUnicodeString( &UnicodeName );
  4375. if( NT_SUCCESS( Status ) ) {
  4376. dwAnsiStringSize = RtlUnicodeStringToAnsiSize( &UnicodeValue );
  4377. }
  4378. RtlFreeHeap( RtlProcessHeap(), 0, UnicodeValue.Buffer );
  4379. // dwAnsiStringSize alreay keeps the size including NULL character.
  4380. return dwAnsiStringSize;
  4381. }
  4382. else {
  4383. BaseSetLastNTError( Status );
  4384. return( 0 );
  4385. }
  4386. }
  4387. }
  4388. BOOL
  4389. WINAPI
  4390. SetEnvironmentVariableA(
  4391. LPCSTR lpName,
  4392. LPCSTR lpValue
  4393. )
  4394. /*++
  4395. Routine Description:
  4396. The value of an environment variable of the current process is available
  4397. using this API.
  4398. Arguments:
  4399. lpName - Pointer to a null terminate string that is the name of the
  4400. environment variable whose value is being requested.
  4401. lpValue - An optional pointer to a null terminated string that is to be
  4402. the new value of the specified variable name. If this parameter
  4403. is NULL, then the variable will be deleted from the current
  4404. process's environment.
  4405. Return Value:
  4406. TRUE - The operation was successful
  4407. FALSE/NULL - The operation failed. Extended error status is available
  4408. using GetLastError.
  4409. --*/
  4410. {
  4411. NTSTATUS Status;
  4412. STRING Name;
  4413. STRING Value;
  4414. UNICODE_STRING UnicodeName;
  4415. UNICODE_STRING UnicodeValue;
  4416. RtlInitString( &Name, lpName );
  4417. Status = RtlAnsiStringToUnicodeString(&UnicodeName, &Name, TRUE);
  4418. if ( !NT_SUCCESS(Status) ) {
  4419. BaseSetLastNTError( Status );
  4420. return FALSE;
  4421. }
  4422. if (ARGUMENT_PRESENT( lpValue )) {
  4423. RtlInitString( &Value, lpValue );
  4424. Status = RtlAnsiStringToUnicodeString(&UnicodeValue, &Value, TRUE);
  4425. if ( !NT_SUCCESS(Status) ) {
  4426. BaseSetLastNTError( Status );
  4427. RtlFreeUnicodeString(&UnicodeName);
  4428. return FALSE;
  4429. }
  4430. Status = RtlSetEnvironmentVariable( NULL, &UnicodeName, &UnicodeValue);
  4431. RtlFreeUnicodeString(&UnicodeValue);
  4432. }
  4433. else {
  4434. Status = RtlSetEnvironmentVariable( NULL, &UnicodeName, NULL);
  4435. }
  4436. RtlFreeUnicodeString(&UnicodeName);
  4437. if (NT_SUCCESS( Status )) {
  4438. return( TRUE );
  4439. }
  4440. else {
  4441. BaseSetLastNTError( Status );
  4442. return( FALSE );
  4443. }
  4444. }
  4445. DWORD
  4446. WINAPI
  4447. GetEnvironmentVariableW(
  4448. LPCWSTR lpName,
  4449. LPWSTR lpBuffer,
  4450. DWORD nSize
  4451. )
  4452. {
  4453. NTSTATUS Status;
  4454. UNICODE_STRING Name;
  4455. UNICODE_STRING Value;
  4456. DWORD iSize;
  4457. if (nSize > UNICODE_STRING_MAX_CHARS - 1) {
  4458. iSize = UNICODE_STRING_MAX_BYTES - sizeof (WCHAR);
  4459. } else {
  4460. if (nSize > 0) {
  4461. iSize = (nSize - 1) * sizeof (WCHAR);
  4462. } else {
  4463. iSize = 0;
  4464. }
  4465. }
  4466. Status = RtlInitUnicodeStringEx (&Name, lpName);
  4467. if (!NT_SUCCESS (Status)) {
  4468. BaseSetLastNTError (Status);
  4469. return( 0 );
  4470. }
  4471. Value.Buffer = lpBuffer;
  4472. Value.Length = 0;
  4473. Value.MaximumLength = (USHORT)iSize;
  4474. Status = RtlQueryEnvironmentVariable_U (NULL,
  4475. &Name,
  4476. &Value);
  4477. if (NT_SUCCESS (Status) && (nSize == 0)) {
  4478. Status = STATUS_BUFFER_OVERFLOW; // No room for terminator
  4479. }
  4480. if (NT_SUCCESS (Status)) {
  4481. lpBuffer[Value.Length / sizeof(WCHAR)] = L'\0';
  4482. return (Value.Length / sizeof(WCHAR));
  4483. } else {
  4484. if (Status == STATUS_BUFFER_TOO_SMALL) {
  4485. return Value.Length / sizeof(WCHAR) + 1;
  4486. } else {
  4487. BaseSetLastNTError (Status);
  4488. return (0);
  4489. }
  4490. }
  4491. }
  4492. BOOL
  4493. WINAPI
  4494. SetEnvironmentVariableW(
  4495. LPCWSTR lpName,
  4496. LPCWSTR lpValue
  4497. )
  4498. {
  4499. NTSTATUS Status;
  4500. UNICODE_STRING Name, Value;
  4501. Status = RtlInitUnicodeStringEx (&Name, lpName);
  4502. if (!NT_SUCCESS (Status)) {
  4503. BaseSetLastNTError (Status);
  4504. return (FALSE);
  4505. }
  4506. if (ARGUMENT_PRESENT (lpValue)) {
  4507. Status = RtlInitUnicodeStringEx (&Value, lpValue);
  4508. if (!NT_SUCCESS (Status)) {
  4509. BaseSetLastNTError (Status);
  4510. return (FALSE);
  4511. }
  4512. Status = RtlSetEnvironmentVariable (NULL, &Name, &Value);
  4513. } else {
  4514. Status = RtlSetEnvironmentVariable (NULL, &Name, NULL);
  4515. }
  4516. if (NT_SUCCESS (Status)) {
  4517. return (TRUE);
  4518. } else {
  4519. BaseSetLastNTError (Status);
  4520. return (FALSE);
  4521. }
  4522. }
  4523. DWORD
  4524. WINAPI
  4525. ExpandEnvironmentStringsA(
  4526. LPCSTR lpSrc,
  4527. LPSTR lpDst,
  4528. DWORD nSize
  4529. )
  4530. {
  4531. NTSTATUS Status;
  4532. ANSI_STRING Source, Destination;
  4533. ULONG Length;
  4534. UNICODE_STRING UnicodeSource;
  4535. UNICODE_STRING UnicodeDest;
  4536. DWORD iSize;
  4537. if ( nSize > (MAXUSHORT >> 1)-2 ) {
  4538. iSize = (MAXUSHORT >> 1)-2;
  4539. }
  4540. else {
  4541. iSize = nSize;
  4542. }
  4543. if( lpDst != NULL )
  4544. *lpDst = '\0';
  4545. RtlInitString( &Source, lpSrc );
  4546. Status = RtlAnsiStringToUnicodeString( &UnicodeSource, &Source, TRUE );
  4547. if (!NT_SUCCESS( Status )) {
  4548. BaseSetLastNTError( Status );
  4549. return 0;
  4550. }
  4551. UnicodeDest.MaximumLength = (USHORT)(iSize ? iSize - 1 : iSize)*sizeof(WCHAR);
  4552. UnicodeDest.Buffer = (PWCHAR)
  4553. RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( TMP_TAG ), UnicodeDest.MaximumLength );
  4554. if (UnicodeDest.Buffer == NULL) {
  4555. BaseSetLastNTError( STATUS_NO_MEMORY );
  4556. return 0;
  4557. }
  4558. Length = 0;
  4559. Status = RtlExpandEnvironmentStrings_U( NULL,
  4560. (PUNICODE_STRING)&UnicodeSource,
  4561. (PUNICODE_STRING)&UnicodeDest,
  4562. &Length
  4563. );
  4564. if (NT_SUCCESS( Status )) {
  4565. if ( nSize > MAXUSHORT-2 ) {
  4566. iSize = MAXUSHORT-2;
  4567. }
  4568. else {
  4569. iSize = nSize;
  4570. }
  4571. Destination.MaximumLength = (USHORT)iSize;
  4572. Destination.Buffer = lpDst;
  4573. Status = RtlUnicodeStringToAnsiString(&Destination,&UnicodeDest,FALSE);
  4574. RtlFreeHeap(RtlProcessHeap(), 0, UnicodeDest.Buffer);
  4575. RtlFreeUnicodeString(&UnicodeSource);
  4576. if (!NT_SUCCESS( Status )) {
  4577. *lpDst = '\0';
  4578. BaseSetLastNTError( Status );
  4579. return 0;
  4580. }
  4581. return( Length / sizeof( WCHAR ) );
  4582. }
  4583. else if (Status == STATUS_BUFFER_TOO_SMALL) {
  4584. RtlFreeHeap(RtlProcessHeap(), 0, UnicodeDest.Buffer);
  4585. RtlFreeUnicodeString(&UnicodeSource);
  4586. return( (Length / sizeof( WCHAR )) + 1 );
  4587. }
  4588. else {
  4589. RtlFreeHeap(RtlProcessHeap(), 0, UnicodeDest.Buffer);
  4590. RtlFreeUnicodeString(&UnicodeSource);
  4591. BaseSetLastNTError( Status );
  4592. return 0;
  4593. }
  4594. }
  4595. DWORD
  4596. WINAPI
  4597. ExpandEnvironmentStringsW(
  4598. LPCWSTR lpSrc,
  4599. LPWSTR lpDst,
  4600. DWORD nSize
  4601. )
  4602. {
  4603. NTSTATUS Status;
  4604. UNICODE_STRING Source, Destination;
  4605. ULONG Length;
  4606. DWORD iSize;
  4607. if ( nSize > (MAXUSHORT >> 1)-2 ) {
  4608. iSize = (MAXUSHORT >> 1)-2;
  4609. }
  4610. else {
  4611. iSize = nSize;
  4612. }
  4613. RtlInitUnicodeString( &Source, lpSrc );
  4614. Destination.Buffer = lpDst;
  4615. Destination.Length = 0;
  4616. Destination.MaximumLength = (USHORT)(iSize * sizeof( WCHAR ));
  4617. Length = 0;
  4618. Status = RtlExpandEnvironmentStrings_U( NULL,
  4619. &Source,
  4620. &Destination,
  4621. &Length
  4622. );
  4623. if (NT_SUCCESS( Status ) || Status == STATUS_BUFFER_TOO_SMALL) {
  4624. return( Length / sizeof( WCHAR ) );
  4625. }
  4626. else {
  4627. BaseSetLastNTError( Status );
  4628. return( 0 );
  4629. }
  4630. }
  4631. UINT
  4632. WINAPI
  4633. WinExec(
  4634. LPCSTR lpCmdLine,
  4635. UINT uCmdShow
  4636. )
  4637. /*++
  4638. Routine Description:
  4639. This function executes the Windows or non-Windows application
  4640. identified by the lpCmdLine parameter. The uCmdShow parameter
  4641. specifies the initial state of the application's main window when it
  4642. is created.
  4643. The WinExec function is obsolete. CreateProcess is the prefered
  4644. mechanism for creating a process to run an application. The Win32
  4645. implementation of WinExec is layered on top of CreateProcess. For
  4646. each parameter to CreateProcess, the following section describes how
  4647. the parameter is formed, and its meaning with respect to WinExec.
  4648. lpApplicationName - NULL
  4649. lpCommandLine - The value of lpCmdLine is passed.
  4650. lpProcessAttributes - A value of NULL is used.
  4651. lpThreadAttributes - A value of NULL is used.
  4652. bInheritHandles - A value of FALSE is used.
  4653. dwCreationFlags - A value of 0 is used
  4654. lpEnvironment - The value of NULL is used.
  4655. lpCurrentDirectory - A value of NULL is used.
  4656. lpStartupInfo - The structure is initialized to NULL. The cb
  4657. field is initialized, and the wShowWindow field is set to
  4658. the value of uCmdShow.
  4659. lpProcessInformation.hProcess - The handle is immediately closed.
  4660. lpProcessInformation.hThread - The handle is immediately closed.
  4661. Arguments:
  4662. lpCmdLine - Points to a null-terminated character string that
  4663. contains the command line (filename plus optional parameters)
  4664. for the application to be executed. If the lpCmdLine string
  4665. does not contain a directory path, Windows will search for the
  4666. executable file in this order:
  4667. 1. The current directory
  4668. 2. The Windows directory (the directory containing WIN.COM);
  4669. the GetWindowsDirectory function obtains the pathname of
  4670. this directory
  4671. 3. The Windows system directory (the directory containing such
  4672. system files as KERNEL.EXE); the GetSystemDirectory function
  4673. obtains the pathname of this directory
  4674. 4. The directories listed in the PATH environment variable
  4675. uCmdShow - Specifies how a Windows application window is to be
  4676. shown. See the description of the ShowWindow function for a
  4677. list of the acceptable values for the uCmdShow parameter. For a
  4678. non-Windows application, the PIF file, if any, for the
  4679. application determines the window state.
  4680. Return Value:
  4681. 33 - The operation was successful
  4682. 2 - File not found.
  4683. 3 - Path not found.
  4684. 11 - Invalid .EXE file (non-Win32 .EXE or error in .EXE image).
  4685. 0 - Out of memory or system resources.
  4686. --*/
  4687. {
  4688. STARTUPINFOA StartupInfo;
  4689. PROCESS_INFORMATION ProcessInformation;
  4690. BOOL CreateProcessStatus;
  4691. DWORD ErrorCode;
  4692. retry:
  4693. RtlZeroMemory(&StartupInfo,sizeof(StartupInfo));
  4694. StartupInfo.cb = sizeof(StartupInfo);
  4695. StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
  4696. StartupInfo.wShowWindow = (WORD)uCmdShow;
  4697. CreateProcessStatus = CreateProcess(
  4698. NULL,
  4699. (LPSTR)lpCmdLine,
  4700. NULL,
  4701. NULL,
  4702. FALSE,
  4703. 0,
  4704. NULL,
  4705. NULL,
  4706. &StartupInfo,
  4707. &ProcessInformation
  4708. );
  4709. if ( CreateProcessStatus ) {
  4710. //
  4711. // Wait for the started process to go idle. If it doesn't go idle in
  4712. // 10 seconds, return anyway.
  4713. //
  4714. if (UserWaitForInputIdleRoutine != NULL)
  4715. (*UserWaitForInputIdleRoutine)(ProcessInformation.hProcess,
  4716. DEFAULT_WAIT_FOR_INPUT_IDLE_TIMEOUT);
  4717. NtClose(ProcessInformation.hProcess);
  4718. NtClose(ProcessInformation.hThread);
  4719. return 33;
  4720. }
  4721. else {
  4722. //
  4723. // If CreateProcess failed, then look at GetLastError to determine
  4724. // appropriate return code.
  4725. //
  4726. //
  4727. // Take a closer look at CreateProcess errors. For instance,
  4728. // Claris Works 5.0 launches hyperterm.exe as hyperterm.exe"<null>
  4729. // the trailing " is causing problems so nuke it and then retry.
  4730. //
  4731. if ( !lstrcmpiA(lpCmdLine,"hypertrm.exe\"") ) {
  4732. lpCmdLine = "hypertrm.exe";
  4733. goto retry;
  4734. }
  4735. ErrorCode = GetLastError();
  4736. switch ( ErrorCode ) {
  4737. case ERROR_FILE_NOT_FOUND:
  4738. return 2;
  4739. case ERROR_PATH_NOT_FOUND:
  4740. return 3;
  4741. case ERROR_BAD_EXE_FORMAT:
  4742. return 11;
  4743. default:
  4744. return 0;
  4745. }
  4746. }
  4747. }
  4748. DWORD
  4749. WINAPI
  4750. LoadModule(
  4751. LPCSTR lpModuleName,
  4752. LPVOID lpParameterBlock
  4753. )
  4754. /*++
  4755. Routine Description:
  4756. This function loads and executes a Windows program. This function
  4757. is designed to layer directly on top of CreateProcess.
  4758. The LoadModule function is obsolete. CreateProcess is the prefered
  4759. mechanism for creating a process to run an application. The Win32
  4760. implementation of LoadModule is layered on top of CreateProcess.
  4761. For each parameter to CreateProcess, the following section describes
  4762. how the parameter is formed, and its meaning with respect to
  4763. LoadModule.
  4764. lpApplicationName - The value of lpModuleName
  4765. lpCommandLine - The value of lpParameterBlock->lpCmdLine.
  4766. lpProcessAttributes - A value of NULL is used.
  4767. lpThreadAttributes - A value of NULL is used.
  4768. bInheritHandles - A value of FALSE is used.
  4769. dwCreationFlags - A value of 0 is used
  4770. lpEnvironment - The value of lpEnvAddress from the parameter
  4771. block is used.
  4772. lpCurrentDirectory - A value of NULL is used.
  4773. lpStartupInfo - The structure is initialized to NULL. The cb
  4774. field is initialized, and the wShowWindow field is set to
  4775. the value of second word of the lpCmdShow field of the
  4776. parameter block is used.
  4777. lpProcessInformation.hProcess - The handle is immediately closed.
  4778. lpProcessInformation.hThread - The handle is immediately closed.
  4779. Arguments:
  4780. lpModuleName - Points to a null-terminated string that contains the
  4781. filename of the application to be run. If the lpModuleName
  4782. string does not contain a directory path, Windows will search
  4783. for the executable file in this order:
  4784. 1. The current directory
  4785. 2. The Windows directory. the GetWindowsDirectory function
  4786. obtains the pathname of this directory
  4787. 3. The Windows system directory (the directory containing such
  4788. system files as KERNEL.EXE); the GetSystemDirectory function
  4789. obtains the pathname of this directory
  4790. 4. The directories listed in the PATH environment variable
  4791. lpParameterBlock - Points to a data structure consisting of four
  4792. fields that defines a parameter block. This data structure
  4793. consists of the following fields:
  4794. lpEnvAddress - Points to an array of NULL terminated strings
  4795. that supply the environment strings for the new process.
  4796. The array has a value of NULL as its last entry. A value of
  4797. NULL for this parameter causes the new process to start with
  4798. the same environment as the calling process.
  4799. lpCmdLine - Points to a null-terminated string that contains a
  4800. correctly formed command line.
  4801. lpCmdShow - Points to a structure containing two WORD values.
  4802. The first value must always be set to two. The second value
  4803. specifies how the application window is to be shown and is used
  4804. to supply the dwShowWindow parameter to CreateProcess. See
  4805. the description of the <uCmdShow> paramter of the ShowWindow
  4806. function for a list of the acceptable values.
  4807. dwReserved - Is reserved and must be NULL.
  4808. All unused fields should be set to NULL, except for lpCmdLine,
  4809. which must point to a null string if it is not used.
  4810. Return Value:
  4811. 33 - The operation was successful
  4812. 2 - File not found.
  4813. 3 - Path not found.
  4814. 11 - Invalid .EXE file (non-Win32 .EXE or error in .EXE image).
  4815. 0 - Out of memory or system resources.
  4816. --*/
  4817. {
  4818. STARTUPINFOA StartupInfo;
  4819. PROCESS_INFORMATION ProcessInformation;
  4820. BOOL CreateProcessStatus;
  4821. PLOAD_MODULE_PARAMS LoadModuleParams;
  4822. LPSTR NameBuffer;
  4823. LPSTR CommandLineBuffer;
  4824. DWORD Length;
  4825. DWORD CreateFlag;
  4826. CreateFlag = 0;
  4827. LoadModuleParams = (PLOAD_MODULE_PARAMS)lpParameterBlock;
  4828. if ( LoadModuleParams->dwReserved ||
  4829. LoadModuleParams->lpCmdShow->wMustBe2 != 2 ) {
  4830. BaseSetLastNTError(STATUS_INVALID_PARAMETER);
  4831. return 0;
  4832. }
  4833. CommandLineBuffer = NULL;
  4834. NameBuffer = NULL;
  4835. try {
  4836. //
  4837. // Locate the image
  4838. //
  4839. NameBuffer = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), MAX_PATH);
  4840. Length = SearchPath(
  4841. NULL,
  4842. lpModuleName,
  4843. ".exe",
  4844. MAX_PATH,
  4845. NameBuffer,
  4846. NULL
  4847. );
  4848. if ( !Length || Length >= MAX_PATH ) {
  4849. //
  4850. // If we search pathed, then return file not found.
  4851. // otherwise, try to be more specific.
  4852. //
  4853. RTL_PATH_TYPE PathType;
  4854. HANDLE hFile;
  4855. UNICODE_STRING u;
  4856. ANSI_STRING a;
  4857. RtlInitAnsiString(&a,lpModuleName);
  4858. if ( !NT_SUCCESS(RtlAnsiStringToUnicodeString(&u,&a,TRUE)) ) {
  4859. if ( NameBuffer ) {
  4860. RtlFreeHeap(RtlProcessHeap(), 0,NameBuffer);
  4861. }
  4862. return 2;
  4863. }
  4864. PathType = RtlDetermineDosPathNameType_U(u.Buffer);
  4865. RtlFreeUnicodeString(&u);
  4866. if ( PathType != RtlPathTypeRelative ) {
  4867. //
  4868. // The failed open should set get last error properly.
  4869. //
  4870. hFile = CreateFile(
  4871. lpModuleName,
  4872. GENERIC_READ,
  4873. FILE_SHARE_READ | FILE_SHARE_WRITE,
  4874. NULL,
  4875. OPEN_EXISTING,
  4876. FILE_ATTRIBUTE_NORMAL,
  4877. NULL
  4878. );
  4879. RtlFreeHeap(RtlProcessHeap(), 0,NameBuffer);
  4880. if ( hFile != INVALID_HANDLE_VALUE ) {
  4881. CloseHandle(hFile);
  4882. return 2;
  4883. }
  4884. return GetLastError();
  4885. }
  4886. else {
  4887. RtlFreeHeap(RtlProcessHeap(), 0,NameBuffer);
  4888. return 2;
  4889. }
  4890. }
  4891. RtlZeroMemory(&StartupInfo,sizeof(StartupInfo));
  4892. StartupInfo.cb = sizeof(StartupInfo);
  4893. StartupInfo.dwFlags = STARTF_USESHOWWINDOW;
  4894. StartupInfo.wShowWindow =
  4895. LoadModuleParams->lpCmdShow->wShowWindowValue;
  4896. CommandLineBuffer = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( TMP_TAG ), (ULONG)LoadModuleParams->lpCmdLine[0]+1+Length+1);
  4897. RtlMoveMemory(CommandLineBuffer,NameBuffer,Length);
  4898. CommandLineBuffer[Length] = ' ';
  4899. RtlMoveMemory(&CommandLineBuffer[Length+1],&LoadModuleParams->lpCmdLine[1],(ULONG)LoadModuleParams->lpCmdLine[0]);
  4900. CommandLineBuffer[Length+1+LoadModuleParams->lpCmdLine[0]] = '\0';
  4901. CreateProcessStatus = CreateProcess(
  4902. NameBuffer,
  4903. CommandLineBuffer,
  4904. NULL,
  4905. NULL,
  4906. FALSE,
  4907. CreateFlag,
  4908. LoadModuleParams->lpEnvAddress,
  4909. NULL,
  4910. &StartupInfo,
  4911. &ProcessInformation
  4912. );
  4913. RtlFreeHeap(RtlProcessHeap(), 0,NameBuffer);
  4914. NameBuffer = NULL;
  4915. RtlFreeHeap(RtlProcessHeap(), 0,CommandLineBuffer);
  4916. CommandLineBuffer = NULL;
  4917. }
  4918. except (EXCEPTION_EXECUTE_HANDLER) {
  4919. RtlFreeHeap(RtlProcessHeap(), 0,NameBuffer);
  4920. RtlFreeHeap(RtlProcessHeap(), 0,CommandLineBuffer);
  4921. BaseSetLastNTError(GetExceptionCode());
  4922. return 0;
  4923. }
  4924. if ( CreateProcessStatus ) {
  4925. //
  4926. // Wait for the started process to go idle. If it doesn't go idle in
  4927. // 10 seconds, return anyway.
  4928. //
  4929. if (UserWaitForInputIdleRoutine != NULL)
  4930. (*UserWaitForInputIdleRoutine)(ProcessInformation.hProcess,
  4931. DEFAULT_WAIT_FOR_INPUT_IDLE_TIMEOUT);
  4932. NtClose(ProcessInformation.hProcess);
  4933. NtClose(ProcessInformation.hThread);
  4934. return 33;
  4935. }
  4936. else {
  4937. //
  4938. // If CreateProcess failed, then look at GetLastError to determine
  4939. // appropriate return code.
  4940. //
  4941. Length = GetLastError();
  4942. switch ( Length ) {
  4943. case ERROR_FILE_NOT_FOUND:
  4944. return 2;
  4945. case ERROR_PATH_NOT_FOUND:
  4946. return 3;
  4947. case ERROR_BAD_EXE_FORMAT:
  4948. return 11;
  4949. default:
  4950. return 0;
  4951. }
  4952. }
  4953. }
  4954. HANDLE
  4955. WINAPI
  4956. GetCurrentProcess(
  4957. VOID
  4958. )
  4959. /*++
  4960. Routine Description:
  4961. A pseudo handle to the current process may be retrieved using
  4962. GetCurrentProcess.
  4963. A special constant is exported by Win32 that is interpreted as a
  4964. handle to the current process. This handle may be used to specify
  4965. the current process whenever a process handle is required. On
  4966. Win32, this handle has PROCESS_ALL_ACCESS to the current process.
  4967. On NT/Win32, this handle has the maximum access allowed by any
  4968. security descriptor placed on the current process.
  4969. Arguments:
  4970. None.
  4971. Return Value:
  4972. Returns the pseudo handle of the current process.
  4973. --*/
  4974. {
  4975. return NtCurrentProcess();
  4976. }
  4977. DWORD
  4978. WINAPI
  4979. GetCurrentProcessId(
  4980. VOID
  4981. )
  4982. /*++
  4983. Routine Description:
  4984. The process ID of the current process may be retrieved using
  4985. GetCurrentProcessId.
  4986. Arguments:
  4987. None.
  4988. Return Value:
  4989. Returns a unique value representing the process ID of the currently
  4990. executing process. The return value may be used to open a handle to
  4991. a process.
  4992. --*/
  4993. {
  4994. return HandleToUlong(NtCurrentTeb()->ClientId.UniqueProcess);
  4995. }
  4996. DWORD
  4997. APIENTRY
  4998. GetProcessId(
  4999. HANDLE Process
  5000. )
  5001. /*++
  5002. Routine Description:
  5003. Gets the process ID of the process open via the specified handle
  5004. Arguments:
  5005. Process - Handle of the process to do the query on
  5006. Return Value:
  5007. Returns a unique value representing the process ID of the
  5008. executing process. The return value may be used to identify a process
  5009. in the system. If the function fails the return value is zero.
  5010. --*/
  5011. {
  5012. NTSTATUS Status;
  5013. PROCESS_BASIC_INFORMATION pbi;
  5014. Status = NtQueryInformationProcess (Process,
  5015. ProcessBasicInformation,
  5016. &pbi,
  5017. sizeof (pbi),
  5018. NULL);
  5019. if (!NT_SUCCESS (Status)) {
  5020. BaseSetLastNTError (Status);
  5021. return 0;
  5022. }
  5023. return (DWORD) pbi.UniqueProcessId;
  5024. }
  5025. BOOL
  5026. WINAPI
  5027. ReadProcessMemory(
  5028. HANDLE hProcess,
  5029. LPCVOID lpBaseAddress,
  5030. LPVOID lpBuffer,
  5031. SIZE_T nSize,
  5032. SIZE_T *lpNumberOfBytesRead
  5033. )
  5034. /*++
  5035. Routine Description:
  5036. Memory within a specified process can be read using
  5037. ReadProcessMemory.
  5038. This function copies the data in the specified address range from
  5039. the specified process into the specified buffer of the current
  5040. process. The specified process does not have to be being debugged
  5041. in order for this API to operate. The caller must simply have a
  5042. handle to the process that was created with PROCESS_VM_READ access.
  5043. Arguments:
  5044. hProcess - Supplies an open handle to a process whose memory is to
  5045. be read. The handle must have been created with PROCESS_VM_READ
  5046. access to the process.
  5047. lpBaseAddress - Supplies the base address in the specified process
  5048. to be read. Before any data transfer occurs, the system
  5049. verifies that all data within the base address and the specified
  5050. size is accessible for read access. If this is the case, then
  5051. the API proceeds. Otherwise the API fail.
  5052. lpBuffer - Supplies the address of a buffer which receives the
  5053. contents from the specified process address space.
  5054. nSize - Supplies the requested number of bytes to read from the
  5055. specified process.
  5056. lpNumberOfBytesRead - An optional parameter, that if supplied
  5057. receives the actual number of bytes transferred into the
  5058. specified buffer. This can be different than the value of nSize
  5059. if the requested read crosses into an area of the process that
  5060. is inaccessible (and that was made inaccessible during the data
  5061. transfer). If this occurs a value of FALSE is returned and
  5062. GetLastError returns a "short read" error indicator.
  5063. Return Value:
  5064. TRUE - The operation was successful.
  5065. FALSE/NULL - The operation failed. Extended error status is available
  5066. using GetLastError.
  5067. --*/
  5068. {
  5069. NTSTATUS Status;
  5070. SIZE_T NtNumberOfBytesRead;
  5071. Status = NtReadVirtualMemory(
  5072. hProcess,
  5073. (PVOID)lpBaseAddress,
  5074. lpBuffer,
  5075. nSize,
  5076. &NtNumberOfBytesRead
  5077. );
  5078. if ( lpNumberOfBytesRead != NULL ) {
  5079. *lpNumberOfBytesRead = NtNumberOfBytesRead;
  5080. }
  5081. if ( !NT_SUCCESS(Status) ) {
  5082. BaseSetLastNTError(Status);
  5083. return FALSE;
  5084. }
  5085. else {
  5086. return TRUE;
  5087. }
  5088. }
  5089. BOOL
  5090. WINAPI
  5091. WriteProcessMemory(
  5092. HANDLE hProcess,
  5093. LPVOID lpBaseAddress,
  5094. LPCVOID lpBuffer,
  5095. SIZE_T nSize,
  5096. SIZE_T *lpNumberOfBytesWritten
  5097. )
  5098. /*++
  5099. Routine Description:
  5100. Memory within a specified process can be written using
  5101. WriteProcessMemory.
  5102. This function copies the from the specified buffer in the current
  5103. process to the address range of the specified process. The
  5104. specified process does not have to be being debugged in order for
  5105. this API to operate. The caller must simply have a handle to the
  5106. process that was created with PROCESS_VM_WRITE access.
  5107. Arguments:
  5108. hProcess - Supplies an open handle to a process whose memory is to
  5109. be written. The handle must have been created with PROCESS_VM_WRITE
  5110. access to the process.
  5111. lpBaseAddress - Supplies the base address in the specified process
  5112. to be written. Before any data transfer occurs, the system
  5113. verifies that all data within the base address and the specified
  5114. size is accessible for write access. If this is the case, then
  5115. the API proceeds. Otherwise the API fail.
  5116. lpBuffer - Supplies the address of a buffer which supplies the data
  5117. to be written into the specified process address space.
  5118. nSize - Supplies the requested number of bytes to write into the
  5119. specified process.
  5120. lpNumberOfBytesWritten - An optional parameter, that if supplied
  5121. receives the actual number of bytes transferred into the
  5122. specified process. This can be different than the value of
  5123. nSize if the requested write crosses into an area of the process
  5124. that is inaccessible (and that was made inaccessible during the
  5125. data transfer). . If this occurs a value of FALSE is returned
  5126. and GetLastError returns a "short write" error indicator.
  5127. Return Value:
  5128. TRUE - The operation was successful.
  5129. FALSE/NULL - The operation failed. Extended error status is available
  5130. using GetLastError.
  5131. --*/
  5132. {
  5133. NTSTATUS Status, xStatus;
  5134. ULONG OldProtect;
  5135. SIZE_T RegionSize;
  5136. PVOID Base;
  5137. SIZE_T NtNumberOfBytesWritten;
  5138. //
  5139. // Set the protection to allow writes
  5140. //
  5141. RegionSize = nSize;
  5142. Base = lpBaseAddress;
  5143. Status = NtProtectVirtualMemory(
  5144. hProcess,
  5145. &Base,
  5146. &RegionSize,
  5147. PAGE_READWRITE,
  5148. &OldProtect
  5149. );
  5150. if ( NT_SUCCESS(Status) ) {
  5151. //
  5152. // See if previous protection was writable. If so,
  5153. // then reset protection and do the write.
  5154. // Otherwise, see if previous protection was read-only or
  5155. // no access. In this case, don't do the write, just fail
  5156. //
  5157. if ( (OldProtect & PAGE_READWRITE) == PAGE_READWRITE ||
  5158. (OldProtect & PAGE_WRITECOPY) == PAGE_WRITECOPY ||
  5159. (OldProtect & PAGE_EXECUTE_READWRITE) == PAGE_EXECUTE_READWRITE ||
  5160. (OldProtect & PAGE_EXECUTE_WRITECOPY) == PAGE_EXECUTE_WRITECOPY ) {
  5161. Status = NtProtectVirtualMemory(
  5162. hProcess,
  5163. &Base,
  5164. &RegionSize,
  5165. OldProtect,
  5166. &OldProtect
  5167. );
  5168. Status = NtWriteVirtualMemory(
  5169. hProcess,
  5170. lpBaseAddress,
  5171. lpBuffer,
  5172. nSize,
  5173. &NtNumberOfBytesWritten
  5174. );
  5175. if ( lpNumberOfBytesWritten != NULL ) {
  5176. *lpNumberOfBytesWritten = NtNumberOfBytesWritten;
  5177. }
  5178. if ( !NT_SUCCESS(Status) ) {
  5179. BaseSetLastNTError(Status);
  5180. return FALSE;
  5181. }
  5182. NtFlushInstructionCache(hProcess,lpBaseAddress,nSize);
  5183. return TRUE;
  5184. }
  5185. else {
  5186. //
  5187. // See if the previous protection was read only or no access. If
  5188. // this is the case, restore the previous protection and return
  5189. // an access violation error.
  5190. //
  5191. if ( (OldProtect & PAGE_NOACCESS) == PAGE_NOACCESS ||
  5192. (OldProtect & PAGE_READONLY) == PAGE_READONLY ) {
  5193. Status = NtProtectVirtualMemory(
  5194. hProcess,
  5195. &Base,
  5196. &RegionSize,
  5197. OldProtect,
  5198. &OldProtect
  5199. );
  5200. BaseSetLastNTError(STATUS_ACCESS_VIOLATION);
  5201. return FALSE;
  5202. }
  5203. else {
  5204. //
  5205. // The previous protection must have been code and the caller
  5206. // is trying to set a breakpoint or edit the code. Do the write
  5207. // and then restore the previous protection.
  5208. //
  5209. Status = NtWriteVirtualMemory(
  5210. hProcess,
  5211. lpBaseAddress,
  5212. lpBuffer,
  5213. nSize,
  5214. &NtNumberOfBytesWritten
  5215. );
  5216. if ( lpNumberOfBytesWritten != NULL ) {
  5217. *lpNumberOfBytesWritten = NtNumberOfBytesWritten;
  5218. }
  5219. xStatus = NtProtectVirtualMemory(
  5220. hProcess,
  5221. &Base,
  5222. &RegionSize,
  5223. OldProtect,
  5224. &OldProtect
  5225. );
  5226. if ( !NT_SUCCESS(Status) ) {
  5227. BaseSetLastNTError(STATUS_ACCESS_VIOLATION);
  5228. return STATUS_ACCESS_VIOLATION;
  5229. }
  5230. NtFlushInstructionCache(hProcess,lpBaseAddress,nSize);
  5231. return TRUE;
  5232. }
  5233. }
  5234. }
  5235. else {
  5236. BaseSetLastNTError(Status);
  5237. return FALSE;
  5238. }
  5239. }
  5240. VOID
  5241. WINAPI
  5242. FatalAppExitW(
  5243. UINT uAction,
  5244. LPCWSTR lpMessageText
  5245. )
  5246. {
  5247. NTSTATUS Status;
  5248. UNICODE_STRING UnicodeString;
  5249. ULONG Response;
  5250. ULONG_PTR ErrorParameters[1];
  5251. RtlInitUnicodeString(&UnicodeString,lpMessageText);
  5252. ErrorParameters[0] = (ULONG_PTR)&UnicodeString;
  5253. Status =NtRaiseHardError( STATUS_FATAL_APP_EXIT | HARDERROR_OVERRIDE_ERRORMODE,
  5254. 1,
  5255. 1,
  5256. ErrorParameters,
  5257. #if DBG
  5258. OptionOkCancel,
  5259. #else
  5260. OptionOk,
  5261. #endif
  5262. &Response
  5263. );
  5264. if ( NT_SUCCESS(Status) && Response == ResponseCancel ) {
  5265. return;
  5266. }
  5267. else {
  5268. ExitProcess(0);
  5269. }
  5270. }
  5271. VOID
  5272. WINAPI
  5273. FatalAppExitA(
  5274. UINT uAction,
  5275. LPCSTR lpMessageText
  5276. )
  5277. {
  5278. PUNICODE_STRING Unicode;
  5279. ANSI_STRING AnsiString;
  5280. NTSTATUS Status;
  5281. Unicode = &NtCurrentTeb()->StaticUnicodeString;
  5282. RtlInitAnsiString(
  5283. &AnsiString,
  5284. lpMessageText
  5285. );
  5286. Status = RtlAnsiStringToUnicodeString(Unicode,&AnsiString,FALSE);
  5287. if ( !NT_SUCCESS(Status) ) {
  5288. ExitProcess(0);
  5289. }
  5290. FatalAppExitW(uAction,Unicode->Buffer);
  5291. }
  5292. VOID
  5293. WINAPI
  5294. FatalExit(
  5295. int ExitCode
  5296. )
  5297. {
  5298. #if DBG
  5299. char Response[ 2 ];
  5300. DbgPrint("FatalExit...\n");
  5301. DbgPrint("\n");
  5302. while (TRUE) {
  5303. DbgPrompt( "A (Abort), B (Break), I (Ignore)? ",
  5304. Response,
  5305. sizeof( Response )
  5306. );
  5307. switch (Response[0]) {
  5308. case 'B':
  5309. case 'b':
  5310. DbgBreakPoint();
  5311. break;
  5312. case 'I':
  5313. case 'i':
  5314. return;
  5315. case 'A':
  5316. case 'a':
  5317. ExitProcess(ExitCode);
  5318. break;
  5319. }
  5320. }
  5321. #endif
  5322. ExitProcess(ExitCode);
  5323. }
  5324. BOOL
  5325. WINAPI
  5326. IsProcessorFeaturePresent(
  5327. DWORD ProcessorFeature
  5328. )
  5329. {
  5330. BOOL rv;
  5331. if ( ProcessorFeature < PROCESSOR_FEATURE_MAX ) {
  5332. rv = (BOOL)(USER_SHARED_DATA->ProcessorFeatures[ProcessorFeature]);
  5333. }
  5334. else {
  5335. rv = FALSE;
  5336. }
  5337. return rv;
  5338. }
  5339. VOID
  5340. GetSystemInfoInternal(
  5341. IN PSYSTEM_BASIC_INFORMATION BasicInfo,
  5342. IN PSYSTEM_PROCESSOR_INFORMATION ProcessorInfo,
  5343. OUT LPSYSTEM_INFO lpSystemInfo
  5344. )
  5345. /*++
  5346. Routine Description:
  5347. The GetSystemInfo function is used to return information about the
  5348. current system. This includes the processor type, page size, oem
  5349. id, and other interesting pieces of information.
  5350. Arguments:
  5351. BasicInfo - Pointer to an initialized SYSTEM_BASIC_INFORMATION structure.
  5352. ProcessorInfo - Pointer to an initialized SYSTEM_PROCESSOR_INFORMATION structure.
  5353. lpSystemInfo - Returns information about the current system.
  5354. Return Value:
  5355. None.
  5356. --*/
  5357. {
  5358. RtlZeroMemory(lpSystemInfo,sizeof(*lpSystemInfo));
  5359. lpSystemInfo->wProcessorArchitecture = ProcessorInfo->ProcessorArchitecture;
  5360. lpSystemInfo->wReserved = 0;
  5361. lpSystemInfo->dwPageSize = BasicInfo->PageSize;
  5362. lpSystemInfo->lpMinimumApplicationAddress = (LPVOID)BasicInfo->MinimumUserModeAddress;
  5363. lpSystemInfo->lpMaximumApplicationAddress = (LPVOID)BasicInfo->MaximumUserModeAddress;
  5364. lpSystemInfo->dwActiveProcessorMask = BasicInfo->ActiveProcessorsAffinityMask;
  5365. lpSystemInfo->dwNumberOfProcessors = BasicInfo->NumberOfProcessors;
  5366. lpSystemInfo->wProcessorLevel = ProcessorInfo->ProcessorLevel;
  5367. lpSystemInfo->wProcessorRevision = ProcessorInfo->ProcessorRevision;
  5368. if (ProcessorInfo->ProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL) {
  5369. if (ProcessorInfo->ProcessorLevel == 3) {
  5370. lpSystemInfo->dwProcessorType = PROCESSOR_INTEL_386;
  5371. }
  5372. else
  5373. if (ProcessorInfo->ProcessorLevel == 4) {
  5374. lpSystemInfo->dwProcessorType = PROCESSOR_INTEL_486;
  5375. }
  5376. else {
  5377. lpSystemInfo->dwProcessorType = PROCESSOR_INTEL_PENTIUM;
  5378. }
  5379. }
  5380. else
  5381. if (ProcessorInfo->ProcessorArchitecture == PROCESSOR_ARCHITECTURE_MIPS) {
  5382. lpSystemInfo->dwProcessorType = PROCESSOR_MIPS_R4000;
  5383. }
  5384. else
  5385. if (ProcessorInfo->ProcessorArchitecture == PROCESSOR_ARCHITECTURE_ALPHA) {
  5386. lpSystemInfo->dwProcessorType = PROCESSOR_ALPHA_21064;
  5387. }
  5388. else
  5389. if (ProcessorInfo->ProcessorArchitecture == PROCESSOR_ARCHITECTURE_PPC) {
  5390. lpSystemInfo->dwProcessorType = 604; // backward compatibility
  5391. }
  5392. else
  5393. if (ProcessorInfo->ProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64) {
  5394. lpSystemInfo->dwProcessorType = PROCESSOR_INTEL_IA64;
  5395. }
  5396. else {
  5397. lpSystemInfo->dwProcessorType = 0;
  5398. }
  5399. lpSystemInfo->dwAllocationGranularity = BasicInfo->AllocationGranularity;
  5400. //
  5401. // for apps less than 3.51, then return 0 in dwReserved. This allows borlands
  5402. // debugger to continue to run since it mistakenly used dwReserved
  5403. // as AllocationGranularity
  5404. //
  5405. if ( GetProcessVersion(0) < 0x30033 ) {
  5406. lpSystemInfo->wProcessorLevel = 0;
  5407. lpSystemInfo->wProcessorRevision = 0;
  5408. }
  5409. return;
  5410. }
  5411. VOID
  5412. WINAPI
  5413. GetSystemInfo(
  5414. LPSYSTEM_INFO lpSystemInfo
  5415. )
  5416. /*++
  5417. Routine Description:
  5418. The GetSystemInfo function is used to return information about the
  5419. current system. This includes the processor type, page size, oem
  5420. id, and other interesting pieces of information.
  5421. Arguments:
  5422. lpSystemInfo - Returns information about the current system.
  5423. SYSTEM_INFO Structure:
  5424. WORD wProcessorArchitecture - returns the architecture of the
  5425. processors in the system: e.g. Intel, Mips, Alpha or PowerPC
  5426. DWORD dwPageSize - Returns the page size. This is specifies the
  5427. granularity of page protection and commitment.
  5428. LPVOID lpMinimumApplicationAddress - Returns the lowest memory
  5429. address accessible to applications and DLLs.
  5430. LPVOID lpMaximumApplicationAddress - Returns the highest memory
  5431. address accessible to applications and DLLs.
  5432. DWORD dwActiveProcessorMask - Returns a mask representing the
  5433. set of processors configured into the system. Bit 0 is
  5434. processor 0, bit 31 is processor 31.
  5435. DWORD dwNumberOfProcessors - Returns the number of processors in
  5436. the system.
  5437. WORD wProcessorLevel - Returns the level of the processors in the
  5438. system. All processors are assumed to be of the same level,
  5439. stepping, and are configured with the same options.
  5440. WORD wProcessorRevision - Returns the revision or stepping of the
  5441. processors in the system. All processors are assumed to be
  5442. of the same level, stepping, and are configured with the
  5443. same options.
  5444. Return Value:
  5445. None.
  5446. --*/
  5447. {
  5448. NTSTATUS Status;
  5449. SYSTEM_BASIC_INFORMATION BasicInfo;
  5450. SYSTEM_PROCESSOR_INFORMATION ProcessorInfo;
  5451. Status = NtQuerySystemInformation(
  5452. SystemBasicInformation,
  5453. &BasicInfo,
  5454. sizeof(BasicInfo),
  5455. NULL
  5456. );
  5457. if ( !NT_SUCCESS(Status) ) {
  5458. return;
  5459. }
  5460. Status = NtQuerySystemInformation(
  5461. SystemProcessorInformation,
  5462. &ProcessorInfo,
  5463. sizeof(ProcessorInfo),
  5464. NULL
  5465. );
  5466. if ( !NT_SUCCESS(Status) ) {
  5467. return;
  5468. }
  5469. GetSystemInfoInternal(
  5470. &BasicInfo,
  5471. &ProcessorInfo,
  5472. lpSystemInfo);
  5473. return;
  5474. }
  5475. VOID
  5476. WINAPI
  5477. GetNativeSystemInfo(
  5478. LPSYSTEM_INFO lpSystemInfo
  5479. )
  5480. /*++
  5481. Routine Description:
  5482. The GetSystemInfo function is used to return information about the
  5483. native current system. The function returns the native system information
  5484. ragarding the processor type, page size, oem id, and other interesting pieces of information
  5485. when running inside a Wow64 process. If this function is called from a non-Wow64
  5486. process, then the results would be the same as of GetSystemInfo.
  5487. Arguments:
  5488. lpSystemInfo - Returns information about the current system.
  5489. SYSTEM_INFO Structure:
  5490. WORD wProcessorArchitecture - returns the architecture of the
  5491. processors in the system: e.g. Intel, Mips, Alpha or PowerPC
  5492. DWORD dwPageSize - Returns the page size. This is specifies the
  5493. granularity of page protection and commitment.
  5494. LPVOID lpMinimumApplicationAddress - Returns the lowest memory
  5495. address accessible to applications and DLLs.
  5496. LPVOID lpMaximumApplicationAddress - Returns the highest memory
  5497. address accessible to applications and DLLs.
  5498. DWORD dwActiveProcessorMask - Returns a mask representing the
  5499. set of processors configured into the system. Bit 0 is
  5500. processor 0, bit 31 is processor 31.
  5501. DWORD dwNumberOfProcessors - Returns the number of processors in
  5502. the system.
  5503. WORD wProcessorLevel - Returns the level of the processors in the
  5504. system. All processors are assumed to be of the same level,
  5505. stepping, and are configured with the same options.
  5506. WORD wProcessorRevision - Returns the revision or stepping of the
  5507. processors in the system. All processors are assumed to be
  5508. of the same level, stepping, and are configured with the
  5509. same options.
  5510. Return Value:
  5511. None.
  5512. --*/
  5513. {
  5514. NTSTATUS Status;
  5515. SYSTEM_BASIC_INFORMATION BasicInfo;
  5516. SYSTEM_PROCESSOR_INFORMATION ProcessorInfo;
  5517. Status = RtlGetNativeSystemInformation(
  5518. SystemBasicInformation,
  5519. &BasicInfo,
  5520. sizeof(BasicInfo),
  5521. NULL
  5522. );
  5523. if ( !NT_SUCCESS(Status) ) {
  5524. return;
  5525. }
  5526. Status = RtlGetNativeSystemInformation(
  5527. SystemProcessorInformation,
  5528. &ProcessorInfo,
  5529. sizeof(ProcessorInfo),
  5530. NULL
  5531. );
  5532. if ( !NT_SUCCESS(Status) ) {
  5533. return;
  5534. }
  5535. GetSystemInfoInternal(
  5536. &BasicInfo,
  5537. &ProcessorInfo,
  5538. lpSystemInfo);
  5539. return;
  5540. }
  5541. #if defined(REMOTE_BOOT)
  5542. BOOL
  5543. WINAPI
  5544. GetSystemInfoExA(
  5545. IN SYSTEMINFOCLASS dwSystemInfoClass,
  5546. OUT LPVOID lpSystemInfoBuffer,
  5547. IN OUT LPDWORD nSize
  5548. )
  5549. /*++
  5550. ANSI thunk to GetSystemInfoExW
  5551. --*/
  5552. {
  5553. DWORD requiredSize;
  5554. BOOL isRemoteBoot;
  5555. UNICODE_STRING unicodeString;
  5556. ANSI_STRING ansiString;
  5557. isRemoteBoot = (BOOL)((USER_SHARED_DATA->SystemFlags & SYSTEM_FLAG_REMOTE_BOOT_CLIENT) != 0);
  5558. //
  5559. // Determine the required buffer size.
  5560. //
  5561. switch ( dwSystemInfoClass ) {
  5562. case SystemInfoRemoteBoot:
  5563. requiredSize = sizeof(BOOL);
  5564. break;
  5565. case SystemInfoRemoteBootServerPath:
  5566. if ( isRemoteBoot ) {
  5567. RtlInitUnicodeString( &unicodeString, USER_SHARED_DATA->RemoteBootServerPath );
  5568. requiredSize = RtlUnicodeStringToAnsiSize( &unicodeString );
  5569. } else {
  5570. //
  5571. // This is not a remote boot client. Return success with a
  5572. // zero-length buffer.
  5573. //
  5574. *nSize = 0;
  5575. return TRUE;
  5576. }
  5577. break;
  5578. default:
  5579. //
  5580. // Unrecognized information class.
  5581. //
  5582. SetLastError(ERROR_INVALID_PARAMETER);
  5583. return FALSE;
  5584. }
  5585. //
  5586. // If the buffer isn't big enough, tell the caller how big the buffer
  5587. // needs to be and return an error.
  5588. //
  5589. if ( *nSize < requiredSize ) {
  5590. *nSize = requiredSize;
  5591. SetLastError(ERROR_BUFFER_OVERFLOW);
  5592. return FALSE;
  5593. }
  5594. *nSize = requiredSize;
  5595. //
  5596. // The buffer is big enough. Return the requested information.
  5597. //
  5598. switch ( dwSystemInfoClass ) {
  5599. case SystemInfoRemoteBoot:
  5600. *(LPBOOL)lpSystemInfoBuffer = isRemoteBoot;
  5601. break;
  5602. case SystemInfoRemoteBootServerPath:
  5603. ansiString.Buffer = lpSystemInfoBuffer;
  5604. ansiString.MaximumLength = (USHORT)*nSize;
  5605. RtlUnicodeStringToAnsiString( &ansiString, &unicodeString, FALSE );
  5606. break;
  5607. }
  5608. return TRUE;
  5609. }
  5610. BOOL
  5611. WINAPI
  5612. GetSystemInfoExW(
  5613. IN SYSTEMINFOCLASS dwSystemInfoClass,
  5614. OUT LPVOID lpSystemInfoBuffer,
  5615. IN OUT LPDWORD nSize
  5616. )
  5617. /*++
  5618. Routine Description:
  5619. The GetSystemInfoEx function is used to return information about the
  5620. current system. It returns different information depending on the
  5621. requested class.
  5622. Arguments:
  5623. dwSystemInfoClass - Specifies the class of information to return.
  5624. lpSystemInfoBuffer - Supplies a pointer to a buffer in which the
  5625. requested information is returned. The structure of this buffer
  5626. varies based on dwSystemInfoClass.
  5627. nSize - On input, supplies the length, in bytes, of the buffer. On output,
  5628. return the length of the data written to the buffer, or, if the
  5629. buffer was too small, the required buffer size.
  5630. Return Value:
  5631. TRUE - The operation was successful
  5632. FALSE/NULL - The operation failed. Extended error status is available
  5633. using GetLastError.
  5634. If the return value is FALSE and GetLastError returns
  5635. ERROR_BUFFER_OVERFLOW, then the supplied buffer was too small
  5636. too contain all of the information, and nSize returns the
  5637. required buffer size.
  5638. --*/
  5639. {
  5640. DWORD requiredSize;
  5641. BOOL isRemoteBoot;
  5642. isRemoteBoot = (BOOL)((USER_SHARED_DATA->SystemFlags & SYSTEM_FLAG_REMOTE_BOOT_CLIENT) != 0);
  5643. //
  5644. // Determine the required buffer size.
  5645. //
  5646. switch ( dwSystemInfoClass ) {
  5647. case SystemInfoRemoteBoot:
  5648. requiredSize = sizeof(BOOL);
  5649. break;
  5650. case SystemInfoRemoteBootServerPath:
  5651. if ( isRemoteBoot ) {
  5652. requiredSize = (wcslen(USER_SHARED_DATA->RemoteBootServerPath) + 1) * sizeof(WCHAR);
  5653. } else {
  5654. //
  5655. // This is not a remote boot client. Return success with a
  5656. // zero-length buffer.
  5657. //
  5658. *nSize = 0;
  5659. return TRUE;
  5660. }
  5661. break;
  5662. default:
  5663. //
  5664. // Unrecognized information class.
  5665. //
  5666. SetLastError(ERROR_INVALID_PARAMETER);
  5667. return FALSE;
  5668. }
  5669. //
  5670. // If the buffer isn't big enough, tell the caller how big the buffer
  5671. // needs to be and return an error.
  5672. //
  5673. if ( *nSize < requiredSize ) {
  5674. *nSize = requiredSize;
  5675. SetLastError(ERROR_BUFFER_OVERFLOW);
  5676. return FALSE;
  5677. }
  5678. *nSize = requiredSize;
  5679. //
  5680. // The buffer is big enough. Return the requested information.
  5681. //
  5682. switch ( dwSystemInfoClass ) {
  5683. case SystemInfoRemoteBoot:
  5684. *(LPBOOL)lpSystemInfoBuffer = isRemoteBoot;
  5685. break;
  5686. case SystemInfoRemoteBootServerPath:
  5687. wcscpy( lpSystemInfoBuffer, USER_SHARED_DATA->RemoteBootServerPath );
  5688. break;
  5689. }
  5690. return TRUE;
  5691. }
  5692. #endif // defined(REMOTE_BOOT)
  5693. BOOL
  5694. BuildSubSysCommandLine(
  5695. LPWSTR lpSubSysName,
  5696. LPCWSTR lpApplicationName,
  5697. LPCWSTR lpCommandLine,
  5698. PUNICODE_STRING SubSysCommandLine
  5699. )
  5700. {
  5701. UNICODE_STRING Args;
  5702. UNICODE_STRING Command;
  5703. BOOLEAN ReturnStatus = TRUE;
  5704. //
  5705. // build the command line as follows:
  5706. // [OS2 | POSIX] /P <full path> /C <original CommandLine>
  5707. //
  5708. // Get application name length
  5709. RtlInitUnicodeString(&Command, lpApplicationName);
  5710. // get lpCommandLine length
  5711. RtlInitUnicodeString(&Args, lpCommandLine);
  5712. SubSysCommandLine->Length = 0;
  5713. SubSysCommandLine->MaximumLength = Command.MaximumLength
  5714. + Args.MaximumLength
  5715. + (USHORT)32;
  5716. SubSysCommandLine->Buffer = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( VDM_TAG ),
  5717. SubSysCommandLine->MaximumLength
  5718. );
  5719. if ( SubSysCommandLine->Buffer ) {
  5720. // New command line begins with either L"OS2 /P " or L"POSIX /P "
  5721. RtlAppendUnicodeToString(SubSysCommandLine, lpSubSysName);
  5722. // append full path name
  5723. RtlAppendUnicodeStringToString(SubSysCommandLine, &Command);
  5724. RtlAppendUnicodeToString(SubSysCommandLine, L" /C ");
  5725. // and append to new command line
  5726. RtlAppendUnicodeStringToString(SubSysCommandLine, &Args);
  5727. } else {
  5728. BaseSetLastNTError(STATUS_NO_MEMORY);
  5729. ReturnStatus = FALSE;
  5730. }
  5731. return ReturnStatus;
  5732. }
  5733. BOOL
  5734. WINAPI
  5735. SetPriorityClass(
  5736. HANDLE hProcess,
  5737. DWORD dwPriorityClass
  5738. )
  5739. /*++
  5740. Routine Description:
  5741. This API is used to set the priority class of the specified process.
  5742. PROCESS_SET_INFORMATION and PROCESS_QUERY_INFORMATION access is
  5743. required to the process in order to call this API. Using this API
  5744. has a dramatic impact on the scheduling characteristics of the
  5745. effected process. Applications should use this API carefully and
  5746. understand the impact of making a process run in either the Idle or
  5747. High priority classes.
  5748. Arguments:
  5749. hProcess - Supplies an open handle to the process whose priority is
  5750. to change.
  5751. dwPriorityClass - Supplies the new priority class for the process.
  5752. The priority class constants are described above. If more than
  5753. one priority class is specified, the lowest specified priority
  5754. class is used.
  5755. Return Value:
  5756. TRUE - The operation was was successful.
  5757. FALSE - The operation failed. Extended error status is available
  5758. using GetLastError.
  5759. --*/
  5760. {
  5761. NTSTATUS Status;
  5762. UCHAR PriorityClass;
  5763. BOOL ReturnValue;
  5764. // NOTE: The following construct is used to ensure the PriClass struct
  5765. // is allocated on a dword boundary. w/o it, the compiler may choose
  5766. // to put it on a word boundary and the NtxxxInformationProces call will
  5767. // fail with a datatype misalignment fault.
  5768. union {
  5769. PROCESS_PRIORITY_CLASS PriClass;
  5770. ULONG x;
  5771. }x;
  5772. PVOID State = NULL;
  5773. ReturnValue = TRUE;
  5774. if (dwPriorityClass & IDLE_PRIORITY_CLASS ) {
  5775. PriorityClass = PROCESS_PRIORITY_CLASS_IDLE;
  5776. }
  5777. else if (dwPriorityClass & BELOW_NORMAL_PRIORITY_CLASS ) {
  5778. PriorityClass = PROCESS_PRIORITY_CLASS_BELOW_NORMAL;
  5779. }
  5780. else if (dwPriorityClass & NORMAL_PRIORITY_CLASS ) {
  5781. PriorityClass = PROCESS_PRIORITY_CLASS_NORMAL;
  5782. }
  5783. else if (dwPriorityClass & ABOVE_NORMAL_PRIORITY_CLASS ) {
  5784. PriorityClass = PROCESS_PRIORITY_CLASS_ABOVE_NORMAL;
  5785. }
  5786. else if (dwPriorityClass & HIGH_PRIORITY_CLASS ) {
  5787. PriorityClass = PROCESS_PRIORITY_CLASS_HIGH;
  5788. }
  5789. else if (dwPriorityClass & REALTIME_PRIORITY_CLASS ) {
  5790. if ( State = BasepIsRealtimeAllowed(TRUE) ) {
  5791. PriorityClass = PROCESS_PRIORITY_CLASS_REALTIME;
  5792. }
  5793. else {
  5794. PriorityClass = PROCESS_PRIORITY_CLASS_HIGH;
  5795. }
  5796. }
  5797. else {
  5798. SetLastError(ERROR_INVALID_PARAMETER);
  5799. return FALSE;
  5800. }
  5801. x.PriClass.PriorityClass = PriorityClass;
  5802. x.PriClass.Foreground = FALSE;
  5803. Status = NtSetInformationProcess(
  5804. hProcess,
  5805. ProcessPriorityClass,
  5806. (PVOID)&x.PriClass,
  5807. sizeof(x.PriClass)
  5808. );
  5809. if ( State ) {
  5810. BasepReleasePrivilege( State );
  5811. }
  5812. if ( !NT_SUCCESS(Status) ) {
  5813. BaseSetLastNTError(Status);
  5814. ReturnValue = FALSE;
  5815. }
  5816. return ReturnValue;
  5817. }
  5818. DWORD
  5819. WINAPI
  5820. GetPriorityClass(
  5821. HANDLE hProcess
  5822. )
  5823. /*++
  5824. Routine Description:
  5825. This API is used to get the priority class of the specified process.
  5826. PROCESS_QUERY_INFORMATION access is required to the process in order
  5827. to call this API.
  5828. Arguments:
  5829. hProcess - Supplies an open handle to the process whose priority is
  5830. to be returned.
  5831. Return Value:
  5832. Non-Zero - Returns the priority class of the specified process.
  5833. 0 - The operation failed. Extended error status is available
  5834. using GetLastError.
  5835. --*/
  5836. {
  5837. NTSTATUS Status;
  5838. ULONG PriorityClass;
  5839. // NOTE: The following construct is used to ensure the PriClass struct
  5840. // is allocated on a dword boundary. w/o it, the compiler may choose
  5841. // to put it on a word boundary and the NtxxxInformationProces call will
  5842. // fail with a datatype misalignment fault.
  5843. union _x {
  5844. PROCESS_PRIORITY_CLASS PriClass;
  5845. ULONG x;
  5846. }x;
  5847. PriorityClass = 0;
  5848. Status = NtQueryInformationProcess(
  5849. hProcess,
  5850. ProcessPriorityClass,
  5851. &x.PriClass,
  5852. sizeof(x.PriClass),
  5853. NULL
  5854. );
  5855. if ( !NT_SUCCESS(Status) ) {
  5856. BaseSetLastNTError(Status);
  5857. return 0;
  5858. }
  5859. switch ( x.PriClass.PriorityClass ) {
  5860. case PROCESS_PRIORITY_CLASS_IDLE:
  5861. PriorityClass = IDLE_PRIORITY_CLASS;
  5862. break;
  5863. case PROCESS_PRIORITY_CLASS_HIGH:
  5864. PriorityClass = HIGH_PRIORITY_CLASS;
  5865. break;
  5866. case PROCESS_PRIORITY_CLASS_REALTIME:
  5867. PriorityClass = REALTIME_PRIORITY_CLASS;
  5868. break;
  5869. case PROCESS_PRIORITY_CLASS_BELOW_NORMAL:
  5870. PriorityClass = BELOW_NORMAL_PRIORITY_CLASS;
  5871. break;
  5872. case PROCESS_PRIORITY_CLASS_ABOVE_NORMAL:
  5873. PriorityClass = ABOVE_NORMAL_PRIORITY_CLASS;
  5874. break;
  5875. case PROCESS_PRIORITY_CLASS_NORMAL:
  5876. default:
  5877. PriorityClass = NORMAL_PRIORITY_CLASS;
  5878. break;
  5879. }
  5880. return PriorityClass;
  5881. }
  5882. BOOL
  5883. WINAPI
  5884. IsBadReadPtr(
  5885. CONST VOID *lp,
  5886. UINT_PTR cb
  5887. )
  5888. /*++
  5889. Routine Description:
  5890. This function verifies that the range of memory specified by the
  5891. input parameters can be read by the calling process.
  5892. If the entire range of memory is accessible, then a value of FALSE
  5893. is returned; otherwise, a value of TRUE is returned.
  5894. Note that since Win32 is a pre-emptive multi-tasking environment,
  5895. the results of this test are only meaningful if the other threads in
  5896. the process do not manipulate the range of memory being tested by
  5897. this call. Even after a pointer validation, an application should
  5898. use the structured exception handling capabilities present in the
  5899. system to gaurd access through pointers that it does not control.
  5900. Arguments:
  5901. lp - Supplies the base address of the memory that is to be checked
  5902. for read access.
  5903. cb - Supplies the length in bytes to be checked.
  5904. Return Value:
  5905. TRUE - Some portion of the specified range of memory is not accessible
  5906. for read access.
  5907. FALSE - All pages within the specified range have been successfully
  5908. read.
  5909. --*/
  5910. {
  5911. PSZ EndAddress;
  5912. PSZ StartAddress;
  5913. ULONG PageSize;
  5914. PageSize = BASE_SYSINFO.PageSize;
  5915. //
  5916. // If the structure has zero length, then do not probe the structure for
  5917. // read accessibility or alignment.
  5918. //
  5919. if (cb != 0) {
  5920. //
  5921. // If it is a NULL pointer just return TRUE, they are always bad
  5922. //
  5923. if (lp == NULL) {
  5924. return TRUE;
  5925. }
  5926. StartAddress = (PSZ)lp;
  5927. //
  5928. // Compute the ending address of the structure and probe for
  5929. // read accessibility.
  5930. //
  5931. EndAddress = StartAddress + cb - 1;
  5932. if ( EndAddress < StartAddress ) {
  5933. return TRUE;
  5934. }
  5935. else {
  5936. try {
  5937. *(volatile CHAR *)StartAddress;
  5938. StartAddress = (PCHAR)((ULONG_PTR)StartAddress & (~((LONG)PageSize - 1)));
  5939. EndAddress = (PCHAR)((ULONG_PTR)EndAddress & (~((LONG)PageSize - 1)));
  5940. while (StartAddress != EndAddress) {
  5941. StartAddress = StartAddress + PageSize;
  5942. *(volatile CHAR *)StartAddress;
  5943. }
  5944. }
  5945. except(EXCEPTION_EXECUTE_HANDLER) {
  5946. return TRUE;
  5947. }
  5948. }
  5949. }
  5950. return FALSE;
  5951. }
  5952. BOOL
  5953. WINAPI
  5954. IsBadHugeReadPtr(
  5955. CONST VOID *lp,
  5956. UINT_PTR cb
  5957. )
  5958. /*++
  5959. Same as IsBadReadPtr
  5960. --*/
  5961. {
  5962. return IsBadReadPtr(lp,cb);
  5963. }
  5964. BOOL
  5965. WINAPI
  5966. IsBadWritePtr(
  5967. LPVOID lp,
  5968. UINT_PTR cb
  5969. )
  5970. /*++
  5971. Routine Description:
  5972. This function verifies that the range of memory specified by the
  5973. input parameters can be written by the calling process.
  5974. If the entire range of memory is accessible, then a value of FALSE
  5975. is returned; otherwise, a value of TRUE is returned.
  5976. Note that since Win32 is a pre-emptive multi-tasking environment,
  5977. the results of this test are only meaningful if the other threads in
  5978. the process do not manipulate the range of memory being tested by
  5979. this call. Even after a pointer validation, an application should
  5980. use the structured exception handling capabilities present in the
  5981. system to gaurd access through pointers that it does not control.
  5982. Also not that implementations are free to do a write test by reading
  5983. a value and then writing it back.
  5984. Arguments:
  5985. lp - Supplies the base address of the memory that is to be checked
  5986. for write access.
  5987. cb - Supplies the length in bytes to be checked.
  5988. Return Value:
  5989. TRUE - Some portion of the specified range of memory is not accessible
  5990. for write access.
  5991. FALSE - All pages within the specified range have been successfully
  5992. written.
  5993. --*/
  5994. {
  5995. PSZ EndAddress;
  5996. PSZ StartAddress;
  5997. ULONG PageSize;
  5998. PageSize = BASE_SYSINFO.PageSize;
  5999. //
  6000. // If the structure has zero length, then do not probe the structure for
  6001. // write accessibility.
  6002. //
  6003. if (cb != 0) {
  6004. //
  6005. // If it is a NULL pointer just return TRUE, they are always bad
  6006. //
  6007. if (lp == NULL) {
  6008. return TRUE;
  6009. }
  6010. StartAddress = (PCHAR)lp;
  6011. //
  6012. // Compute the ending address of the structure and probe for
  6013. // write accessibility.
  6014. //
  6015. EndAddress = StartAddress + cb - 1;
  6016. if ( EndAddress < StartAddress ) {
  6017. return TRUE;
  6018. }
  6019. else {
  6020. try {
  6021. *(volatile CHAR *)StartAddress = *(volatile CHAR *)StartAddress;
  6022. StartAddress = (PCHAR)((ULONG_PTR)StartAddress & (~((LONG)PageSize - 1)));
  6023. EndAddress = (PCHAR)((ULONG_PTR)EndAddress & (~((LONG)PageSize - 1)));
  6024. while (StartAddress != EndAddress) {
  6025. StartAddress = StartAddress + PageSize;
  6026. *(volatile CHAR *)StartAddress = *(volatile CHAR *)StartAddress;
  6027. }
  6028. }
  6029. except(EXCEPTION_EXECUTE_HANDLER) {
  6030. return TRUE;
  6031. }
  6032. }
  6033. }
  6034. return FALSE;
  6035. }
  6036. BOOL
  6037. WINAPI
  6038. IsBadHugeWritePtr(
  6039. LPVOID lp,
  6040. UINT_PTR cb
  6041. )
  6042. /*++
  6043. Same as IsBadWritePtr
  6044. --*/
  6045. {
  6046. return IsBadWritePtr(lp,cb);
  6047. }
  6048. BOOL
  6049. WINAPI
  6050. IsBadCodePtr(
  6051. FARPROC lpfn
  6052. )
  6053. /*++
  6054. Same as IsBadReadPtr with a length of 1
  6055. --*/
  6056. {
  6057. return IsBadReadPtr((LPVOID)lpfn,1);
  6058. }
  6059. BOOL
  6060. WINAPI
  6061. IsBadStringPtrA(
  6062. LPCSTR lpsz,
  6063. UINT_PTR cchMax
  6064. )
  6065. /*++
  6066. Routine Description:
  6067. This function verifies that the range of memory specified by the
  6068. input parameters can be read by the calling process.
  6069. The range is the smaller of the number of bytes covered by the
  6070. specified NULL terminated ANSI string, or the number of bytes specified
  6071. by cchMax.
  6072. If the entire range of memory is accessible, then a value of FALSE
  6073. is returned; otherwise, a value of TRUE is returned.
  6074. Note that since Win32 is a pre-emptive multi-tasking environment,
  6075. the results of this test are only meaningful if the other threads in
  6076. the process do not manipulate the range of memory being tested by
  6077. this call. Even after a pointer validation, an application should
  6078. use the structured exception handling capabilities present in the
  6079. system to gaurd access through pointers that it does not control.
  6080. Arguments:
  6081. lpsz - Supplies the base address of the memory that is to be checked
  6082. for read access.
  6083. cchMax - Supplies the length in bytes to be checked.
  6084. Return Value:
  6085. TRUE - Some portion of the specified range of memory is not accessible
  6086. for read access.
  6087. FALSE - All pages within the specified range have been successfully
  6088. read.
  6089. --*/
  6090. {
  6091. PSZ EndAddress;
  6092. PSZ StartAddress;
  6093. CHAR c;
  6094. //
  6095. // If the structure has zero length, then do not probe the structure for
  6096. // read accessibility.
  6097. //
  6098. if (cchMax != 0) {
  6099. //
  6100. // If it is a NULL pointer just return TRUE, they are always bad
  6101. //
  6102. if (lpsz == NULL) {
  6103. return TRUE;
  6104. }
  6105. StartAddress = (PSZ)lpsz;
  6106. //
  6107. // Compute the ending address of the structure and probe for
  6108. // read accessibility.
  6109. //
  6110. EndAddress = StartAddress + cchMax - 1;
  6111. try {
  6112. c = *(volatile CHAR *)StartAddress;
  6113. while ( c && StartAddress != EndAddress ) {
  6114. StartAddress++;
  6115. c = *(volatile CHAR *)StartAddress;
  6116. }
  6117. }
  6118. except(EXCEPTION_EXECUTE_HANDLER) {
  6119. return TRUE;
  6120. }
  6121. }
  6122. return FALSE;
  6123. }
  6124. BOOL
  6125. WINAPI
  6126. IsBadStringPtrW(
  6127. LPCWSTR lpsz,
  6128. UINT_PTR cchMax
  6129. )
  6130. /*++
  6131. Routine Description:
  6132. This function verifies that the range of memory specified by the
  6133. input parameters can be read by the calling process.
  6134. The range is the smaller of the number of bytes covered by the
  6135. specified NULL terminated UNICODE string, or the number of bytes
  6136. specified by cchMax.
  6137. If the entire range of memory is accessible, then a value of FALSE
  6138. is returned; otherwise, a value of TRUE is returned.
  6139. Note that since Win32 is a pre-emptive multi-tasking environment,
  6140. the results of this test are only meaningful if the other threads in
  6141. the process do not manipulate the range of memory being tested by
  6142. this call. Even after a pointer validation, an application should
  6143. use the structured exception handling capabilities present in the
  6144. system to gaurd access through pointers that it does not control.
  6145. Arguments:
  6146. lpsz - Supplies the base address of the memory that is to be checked
  6147. for read access.
  6148. cchMax - Supplies the length in characters to be checked.
  6149. Return Value:
  6150. TRUE - Some portion of the specified range of memory is not accessible
  6151. for read access.
  6152. FALSE - All pages within the specified range have been successfully
  6153. read.
  6154. --*/
  6155. {
  6156. LPCWSTR EndAddress;
  6157. LPCWSTR StartAddress;
  6158. WCHAR c;
  6159. //
  6160. // If the structure has zero length, then do not probe the structure for
  6161. // read accessibility.
  6162. //
  6163. if (cchMax != 0) {
  6164. //
  6165. // If it is a NULL pointer just return TRUE, they are always bad
  6166. //
  6167. if (lpsz == NULL) {
  6168. return TRUE;
  6169. }
  6170. StartAddress = lpsz;
  6171. //
  6172. // Compute the ending address of the structure and probe for
  6173. // read accessibility.
  6174. //
  6175. EndAddress = (LPCWSTR)((PSZ)StartAddress + (cchMax*2) - 2);
  6176. try {
  6177. c = *(volatile WCHAR *)StartAddress;
  6178. while ( c && StartAddress != EndAddress ) {
  6179. StartAddress++;
  6180. c = *(volatile WCHAR *)StartAddress;
  6181. }
  6182. }
  6183. except(EXCEPTION_EXECUTE_HANDLER) {
  6184. return TRUE;
  6185. }
  6186. }
  6187. return FALSE;
  6188. }
  6189. BOOL
  6190. WINAPI
  6191. SetProcessShutdownParameters(
  6192. DWORD dwLevel,
  6193. DWORD dwFlags
  6194. )
  6195. /*++
  6196. Routine Description:
  6197. This function sets shutdown parameters for the currently calling
  6198. process. dwLevel is the field that defines this processes shutdown
  6199. order relative to the other processes in the system. Higher levels
  6200. shutdown first, lower levels shutdown last.
  6201. Arguments:
  6202. dwLevel - Specifies shutdown order relative to other processes in the
  6203. system. Higher levels shutdown first. System level shutdown orders
  6204. are pre-defined.
  6205. dwFlags - A flags parameter. The flags can be added together:
  6206. SHUTDOWN_NORETRY - If this process takes longer than the user
  6207. specified timeout to shutdown, do not put up a retry dialog
  6208. for the user.
  6209. Notes:
  6210. Applications running in the system security context do not get shut down
  6211. by the system. They will get notified of shutdown or logoff through the
  6212. callback installable via SetConsoleCtrlRoutine() (see that for more info).
  6213. They also will get notified in the order specified by the dwLevel
  6214. parameter.
  6215. Return Value
  6216. TRUE - Successful in setting the process shutdown parameters.
  6217. FALSE - Unsuccessful in setting the process shutdown parameters.
  6218. --*/
  6219. {
  6220. #if defined(BUILD_WOW6432)
  6221. NTSTATUS Status;
  6222. Status = CsrBasepSetProcessShutdownParam(dwLevel, dwFlags);
  6223. if (!NT_SUCCESS(Status)) {
  6224. BaseSetLastNTError(Status);
  6225. return FALSE;
  6226. }
  6227. return TRUE;
  6228. #else
  6229. BASE_API_MSG m;
  6230. PBASE_SHUTDOWNPARAM_MSG a = &m.u.ShutdownParam;
  6231. a->ShutdownLevel = dwLevel;
  6232. a->ShutdownFlags = dwFlags;
  6233. CsrClientCallServer((PCSR_API_MSG)&m, NULL,
  6234. CSR_MAKE_API_NUMBER(BASESRV_SERVERDLL_INDEX,
  6235. BasepSetProcessShutdownParam),
  6236. sizeof(*a));
  6237. if (!NT_SUCCESS((NTSTATUS)m.ReturnValue)) {
  6238. BaseSetLastNTError((NTSTATUS)m.ReturnValue);
  6239. return FALSE;
  6240. }
  6241. return TRUE;
  6242. #endif
  6243. }
  6244. BOOL
  6245. WINAPI
  6246. GetProcessShutdownParameters(
  6247. LPDWORD lpdwLevel,
  6248. LPDWORD lpdwFlags
  6249. )
  6250. /*++
  6251. Routine Description:
  6252. This function gets shutdown parameters for the currently calling
  6253. process. See SetProcessShutdownParameters() for the parameter
  6254. description.
  6255. Arguments:
  6256. lpdwLevel - Pointer to the DWORD where the shutdown level information
  6257. should be put.
  6258. lpdwFlags - Pointer to the DWORD where the shutdown flags information
  6259. should be put.
  6260. Return Value
  6261. TRUE - Successful in getting the process shutdown parameters.
  6262. FALSE - Unsuccessful in getting the process shutdown parameters.
  6263. --*/
  6264. {
  6265. #if defined(BUILD_WOW6432)
  6266. NTSTATUS Status;
  6267. Status = CsrBasepGetProcessShutdownParam(lpdwLevel, lpdwFlags);
  6268. if (!NT_SUCCESS(Status)) {
  6269. BaseSetLastNTError(Status);
  6270. return FALSE;
  6271. }
  6272. return TRUE;
  6273. #else
  6274. BASE_API_MSG m;
  6275. PBASE_SHUTDOWNPARAM_MSG a = &m.u.ShutdownParam;
  6276. CsrClientCallServer((PCSR_API_MSG)&m, NULL,
  6277. CSR_MAKE_API_NUMBER(BASESRV_SERVERDLL_INDEX,
  6278. BasepGetProcessShutdownParam),
  6279. sizeof(*a));
  6280. if (!NT_SUCCESS((NTSTATUS)m.ReturnValue)) {
  6281. BaseSetLastNTError((NTSTATUS)m.ReturnValue);
  6282. return FALSE;
  6283. }
  6284. *lpdwLevel = a->ShutdownLevel;
  6285. *lpdwFlags = a->ShutdownFlags;
  6286. return TRUE;
  6287. #endif
  6288. }
  6289. PVOID
  6290. BasepIsRealtimeAllowed(
  6291. BOOLEAN LeaveEnabled
  6292. )
  6293. {
  6294. PVOID State;
  6295. NTSTATUS Status;
  6296. Status = BasepAcquirePrivilegeEx( SE_INC_BASE_PRIORITY_PRIVILEGE, &State );
  6297. if (!NT_SUCCESS( Status )) {
  6298. return NULL;
  6299. }
  6300. if ( !LeaveEnabled ) {
  6301. BasepReleasePrivilege( State );
  6302. State = (PVOID)1;
  6303. }
  6304. return State;
  6305. }
  6306. BOOL
  6307. WINAPI
  6308. GetSystemTimes(
  6309. PFILETIME lpIdleTime,
  6310. PFILETIME lpKernelTime,
  6311. PFILETIME lpUserTime
  6312. )
  6313. /*++
  6314. Routine Description:
  6315. This function is used to return various timing information about
  6316. the system. On a multiprocessor system, these values are the sum
  6317. of the appropriate times across all processors.
  6318. Arguments:
  6319. lpIdleTime - Returns the amount of time that the system has been
  6320. idle.
  6321. lpKernelTime - Returns the amount of time that the system (all
  6322. threads in all processes) has executed in kernel-mode.
  6323. lpUserTime - Returns the amount of time that the system (all
  6324. threads in all processes) has executed in user-mode.
  6325. Return Value:
  6326. TRUE - The API was successful
  6327. FALSE - The operation failed. Extended error status is available
  6328. using GetLastError.
  6329. --*/
  6330. {
  6331. LONG Lupe;
  6332. PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION
  6333. ProcessorTimes;
  6334. ULONG ProcessorTimesCb;
  6335. NTSTATUS Status;
  6336. ULARGE_INTEGER Sum;
  6337. ULONG ReturnLength;
  6338. #if (!defined(BUILD_WOW6432) && !defined(_WIN64))
  6339. #define BASEP_GST_NPROCS BaseStaticServerData->SysInfo.NumberOfProcessors
  6340. #else
  6341. #define BASEP_GST_NPROCS SysInfo.NumberOfProcessors
  6342. #endif
  6343. ProcessorTimesCb = BASEP_GST_NPROCS * sizeof(*ProcessorTimes);
  6344. ProcessorTimes = ((PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)
  6345. RtlAllocateHeap(RtlProcessHeap(),
  6346. MAKE_TAG(TMP_TAG),
  6347. ProcessorTimesCb));
  6348. if (! ProcessorTimes) {
  6349. Status = STATUS_NO_MEMORY;
  6350. goto cleanup;
  6351. }
  6352. Status = NtQuerySystemInformation(SystemProcessorPerformanceInformation,
  6353. ProcessorTimes,
  6354. ProcessorTimesCb,
  6355. &ReturnLength);
  6356. if (! NT_SUCCESS(Status)) {
  6357. goto cleanup;
  6358. }
  6359. if (ReturnLength != ProcessorTimesCb) {
  6360. Status = STATUS_INTERNAL_ERROR;
  6361. goto cleanup;
  6362. }
  6363. #define BASEP_GST_SUM(DST, SRC) \
  6364. if ( DST ) { \
  6365. Sum.QuadPart = 0; \
  6366. for (Lupe = 0; \
  6367. Lupe < BASEP_GST_NPROCS; \
  6368. Lupe++) { \
  6369. Sum.QuadPart += ProcessorTimes[Lupe]. SRC .QuadPart ; \
  6370. } \
  6371. DST ->dwLowDateTime = Sum.LowPart; \
  6372. DST ->dwHighDateTime = Sum.HighPart; \
  6373. }
  6374. BASEP_GST_SUM(lpIdleTime, IdleTime);
  6375. BASEP_GST_SUM(lpKernelTime, KernelTime);
  6376. BASEP_GST_SUM(lpUserTime, UserTime);
  6377. #undef BASEP_GST_SUM
  6378. #undef BASEP_GST_NPROCS
  6379. Status = STATUS_SUCCESS;
  6380. cleanup:
  6381. if (ProcessorTimes) {
  6382. RtlFreeHeap(RtlProcessHeap(),
  6383. MAKE_TAG(TMP_TAG),
  6384. ProcessorTimes);
  6385. }
  6386. if (! NT_SUCCESS(Status)) {
  6387. BaseSetLastNTError(Status);
  6388. return FALSE;
  6389. }
  6390. return TRUE;
  6391. }
  6392. BOOL
  6393. WINAPI
  6394. GetProcessTimes(
  6395. HANDLE hProcess,
  6396. LPFILETIME lpCreationTime,
  6397. LPFILETIME lpExitTime,
  6398. LPFILETIME lpKernelTime,
  6399. LPFILETIME lpUserTime
  6400. )
  6401. /*++
  6402. Routine Description:
  6403. This function is used to return various timing information about the
  6404. process specified by hProcess.
  6405. All times are in units of 100ns increments. For lpCreationTime and lpExitTime,
  6406. the times are in terms of the SYSTEM time or GMT time.
  6407. Arguments:
  6408. hProcess - Supplies an open handle to the specified process. The
  6409. handle must have been created with PROCESS_QUERY_INFORMATION
  6410. access.
  6411. lpCreationTime - Returns a creation time of the process.
  6412. lpExitTime - Returns the exit time of a process. If the process has
  6413. not exited, this value is not defined.
  6414. lpKernelTime - Returns the amount of time that this process (all
  6415. it's threads), have executed in kernel-mode.
  6416. lpUserTime - Returns the amount of time that this process (all it's
  6417. threads), have executed in user-mode.
  6418. Return Value:
  6419. TRUE - The API was successful
  6420. FALSE - The operation failed. Extended error status is available
  6421. using GetLastError.
  6422. --*/
  6423. {
  6424. NTSTATUS Status;
  6425. KERNEL_USER_TIMES TimeInfo;
  6426. Status = NtQueryInformationProcess(
  6427. hProcess,
  6428. ProcessTimes,
  6429. (PVOID)&TimeInfo,
  6430. sizeof(TimeInfo),
  6431. NULL
  6432. );
  6433. if ( !NT_SUCCESS(Status) ) {
  6434. BaseSetLastNTError(Status);
  6435. return FALSE;
  6436. }
  6437. *lpCreationTime = *(LPFILETIME)&TimeInfo.CreateTime;
  6438. *lpExitTime = *(LPFILETIME)&TimeInfo.ExitTime;
  6439. *lpKernelTime = *(LPFILETIME)&TimeInfo.KernelTime;
  6440. *lpUserTime = *(LPFILETIME)&TimeInfo.UserTime;
  6441. return TRUE;
  6442. }
  6443. BOOL
  6444. WINAPI
  6445. GetProcessAffinityMask(
  6446. HANDLE hProcess,
  6447. PDWORD_PTR lpProcessAffinityMask,
  6448. PDWORD_PTR lpSystemAffinityMask
  6449. )
  6450. /*++
  6451. Routine Description:
  6452. This function is used to return the processor affinity mask for the
  6453. selected process and for the system. The process affinity mask is a
  6454. bit vector where each bit represents the processors that the process
  6455. is allowed to run on. The system affinity mask is a bit vector
  6456. where each bit represents the processors configured into the system
  6457. The process affinity mask is a proper subset of the system affinity mask.
  6458. Arguments:
  6459. hProcess - Supplies an open handle to the specified process. The
  6460. handle must have been created with PROCESS_QUERY_INFORMATION
  6461. access.
  6462. lpProcessAffinityMask - Supplies the address of a DWORD that returns the
  6463. specified process' affinity mask.
  6464. lpSystemAffinityMask - Supplies the address of a DWORD that returns the
  6465. system affinity mask.
  6466. Return Value:
  6467. TRUE - The API was successful
  6468. FALSE - The operation failed. Extended error status is available
  6469. using GetLastError.
  6470. --*/
  6471. {
  6472. PROCESS_BASIC_INFORMATION BasicInformation;
  6473. NTSTATUS Status;
  6474. BOOL rv;
  6475. Status = NtQueryInformationProcess(
  6476. hProcess,
  6477. ProcessBasicInformation,
  6478. &BasicInformation,
  6479. sizeof(BasicInformation),
  6480. NULL
  6481. );
  6482. if ( !NT_SUCCESS(Status) ) {
  6483. BaseSetLastNTError(Status);
  6484. rv = FALSE;
  6485. }
  6486. else {
  6487. *lpProcessAffinityMask = BasicInformation.AffinityMask;
  6488. *lpSystemAffinityMask = BASE_SYSINFO.ActiveProcessorsAffinityMask;
  6489. rv = TRUE;
  6490. }
  6491. return rv;
  6492. }
  6493. BOOL
  6494. WINAPI
  6495. GetProcessWorkingSetSize(
  6496. HANDLE hProcess,
  6497. PSIZE_T lpMinimumWorkingSetSize,
  6498. PSIZE_T lpMaximumWorkingSetSize
  6499. )
  6500. /*++
  6501. Routine Description:
  6502. This function allows the caller to determine the minimum and maximum working
  6503. set sizes of the specified process. The working set sizes effect the virtual
  6504. memory paging behavior for the process.
  6505. Arguments:
  6506. hProcess - Supplies an open handle to the specified process. The
  6507. handle must have been created with PROCESS_QUERY_INFORMATION
  6508. access.
  6509. lpMinimumWorkingSetSize - Supplies the address of the variable that
  6510. will receive the minimum working set size of the specified
  6511. process. The virtual memory manager will attempt to keep at
  6512. least this much memory resident in the process whenever the
  6513. process is active.
  6514. lpMaximumWorkingSetSize - Supplies the address of the variable that
  6515. will receive the maximum working set size of the specified
  6516. process. In tight memory situations, the virtual memory manager
  6517. will attempt to keep at no more than this much memory resident
  6518. in the process whenever the process is active.
  6519. Return Value:
  6520. TRUE - The API was successful
  6521. FALSE - The operation failed. Extended error status is available
  6522. using GetLastError.
  6523. --*/
  6524. {
  6525. QUOTA_LIMITS QuotaLimits;
  6526. NTSTATUS Status;
  6527. BOOL rv;
  6528. Status = NtQueryInformationProcess(
  6529. hProcess,
  6530. ProcessQuotaLimits,
  6531. &QuotaLimits,
  6532. sizeof(QuotaLimits),
  6533. NULL
  6534. );
  6535. if (NT_SUCCESS(Status)) {
  6536. *lpMinimumWorkingSetSize = QuotaLimits.MinimumWorkingSetSize;
  6537. *lpMaximumWorkingSetSize = QuotaLimits.MaximumWorkingSetSize;
  6538. rv = TRUE;
  6539. }
  6540. else {
  6541. rv = FALSE;
  6542. BaseSetLastNTError(Status);
  6543. }
  6544. return rv;
  6545. }
  6546. BOOL
  6547. WINAPI
  6548. SetProcessWorkingSetSize(
  6549. HANDLE hProcess,
  6550. SIZE_T dwMinimumWorkingSetSize,
  6551. SIZE_T dwMaximumWorkingSetSize
  6552. )
  6553. /*++
  6554. Routine Description:
  6555. This function allows the caller to set the minimum and maximum
  6556. working set sizes of the specified process. The working set sizes
  6557. effect the virtual memory paging behavior for the process. The
  6558. specified process's working set be emptied (essentially swapping out
  6559. the process) by specifying the distinguished values 0xffffffff for
  6560. both the minimum and maximum working set sizes.
  6561. If you are not trimming an address space, SE_INC_BASE_PRIORITY_PRIVILEGE
  6562. must be held by the process
  6563. Arguments:
  6564. hProcess - Supplies an open handle to the specified process. The
  6565. handle must have been created with PROCESS_SET_QUOTA
  6566. access.
  6567. dwMinimumWorkingSetSize - Supplies the minimum working set size for
  6568. the specified process. The virtual memory manager will attempt
  6569. to keep at least this much memory resident in the process
  6570. whenever the process is active. A value of (SIZE_T)-1 and the
  6571. same value in dwMaximumWorkingSetSize will temporarily trim the
  6572. working set of the specified process (essentially out swap the
  6573. process).
  6574. dwMaximumWorkingSetSize - Supplies the maximum working set size for
  6575. the specified process. In tight memory situations, the virtual
  6576. memory manager will attempt to keep at no more than this much
  6577. memory resident in the process whenever the process is active.
  6578. A value of (SIZE_T)-1 and the same value in
  6579. dwMinimumWorkingSetSize will temporarily trim the working set of
  6580. the specified process (essentially out swap the process).
  6581. Return Value:
  6582. TRUE - The API was successful
  6583. FALSE - The operation failed. Extended error status is available
  6584. using GetLastError.
  6585. --*/
  6586. {
  6587. QUOTA_LIMITS QuotaLimits;
  6588. NTSTATUS Status, PrivStatus;
  6589. BOOL rv;
  6590. PVOID State;
  6591. #ifdef _WIN64
  6592. ASSERT(dwMinimumWorkingSetSize != 0xffffffff && dwMaximumWorkingSetSize != 0xffffffff);
  6593. #endif
  6594. if ( dwMinimumWorkingSetSize == 0 || dwMaximumWorkingSetSize == 0 ) {
  6595. Status = STATUS_INVALID_PARAMETER;
  6596. rv = FALSE;
  6597. }
  6598. else {
  6599. QuotaLimits.MaximumWorkingSetSize = dwMaximumWorkingSetSize;
  6600. QuotaLimits.MinimumWorkingSetSize = dwMinimumWorkingSetSize;
  6601. //
  6602. // Attempt to acquire the appropriate privilege. If this
  6603. // fails, it's no big deal -- we'll attempt to make the
  6604. // NtSetInformationProcess call anyway, in case it turns out
  6605. // to be a decrease operation (which will succeed anyway).
  6606. //
  6607. PrivStatus = BasepAcquirePrivilegeEx( SE_INC_BASE_PRIORITY_PRIVILEGE, &State );
  6608. Status = NtSetInformationProcess (
  6609. hProcess,
  6610. ProcessQuotaLimits,
  6611. &QuotaLimits,
  6612. sizeof(QuotaLimits)
  6613. );
  6614. if ( !NT_SUCCESS(Status) ) {
  6615. rv = FALSE;
  6616. }
  6617. else {
  6618. rv = TRUE;
  6619. }
  6620. if ( NT_SUCCESS(PrivStatus) ) {
  6621. //
  6622. // We successfully acquired the privilege above; we need to relinquish it.
  6623. //
  6624. ASSERT( State != NULL );
  6625. BasepReleasePrivilege( State );
  6626. State = NULL;
  6627. }
  6628. }
  6629. if ( !rv ) {
  6630. BaseSetLastNTError(Status);
  6631. }
  6632. return rv;
  6633. }
  6634. DWORD
  6635. WINAPI
  6636. GetProcessVersion(
  6637. DWORD ProcessId
  6638. )
  6639. {
  6640. PIMAGE_NT_HEADERS NtHeader;
  6641. PPEB Peb;
  6642. HANDLE hProcess;
  6643. NTSTATUS Status;
  6644. PROCESS_BASIC_INFORMATION ProcessInfo;
  6645. BOOL b;
  6646. struct {
  6647. USHORT MajorSubsystemVersion;
  6648. USHORT MinorSubsystemVersion;
  6649. } SwappedVersion;
  6650. union {
  6651. struct {
  6652. USHORT MinorSubsystemVersion;
  6653. USHORT MajorSubsystemVersion;
  6654. };
  6655. DWORD SubsystemVersion;
  6656. } Version;
  6657. PVOID ImageBaseAddress;
  6658. LONG e_lfanew;
  6659. hProcess = NULL;
  6660. Version.SubsystemVersion = 0;
  6661. try {
  6662. if ( ProcessId == 0 || ProcessId == GetCurrentProcessId() ) {
  6663. Peb = NtCurrentPeb();
  6664. NtHeader = RtlImageNtHeader(Peb->ImageBaseAddress);
  6665. if (! NtHeader) {
  6666. BaseSetLastNTError(STATUS_INVALID_IMAGE_FORMAT);
  6667. goto finally_exit;
  6668. }
  6669. Version.MajorSubsystemVersion = NtHeader->OptionalHeader.MajorSubsystemVersion;
  6670. Version.MinorSubsystemVersion = NtHeader->OptionalHeader.MinorSubsystemVersion;
  6671. }
  6672. else {
  6673. hProcess = OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ,FALSE,ProcessId);
  6674. if ( !hProcess ) {
  6675. goto finally_exit;
  6676. }
  6677. //
  6678. // Get the Peb address
  6679. //
  6680. Status = NtQueryInformationProcess(
  6681. hProcess,
  6682. ProcessBasicInformation,
  6683. &ProcessInfo,
  6684. sizeof( ProcessInfo ),
  6685. NULL
  6686. );
  6687. if ( !NT_SUCCESS( Status ) ) {
  6688. BaseSetLastNTError(Status);
  6689. goto finally_exit;
  6690. }
  6691. Peb = ProcessInfo.PebBaseAddress;
  6692. //
  6693. // Read the image base address from the Peb
  6694. //
  6695. b = ReadProcessMemory(
  6696. hProcess,
  6697. &Peb->ImageBaseAddress,
  6698. &ImageBaseAddress,
  6699. sizeof(ImageBaseAddress),
  6700. NULL
  6701. );
  6702. if ( !b ) {
  6703. goto finally_exit;
  6704. }
  6705. //
  6706. // read e_lfanew from imageheader
  6707. //
  6708. b = ReadProcessMemory(
  6709. hProcess,
  6710. &((PIMAGE_DOS_HEADER)ImageBaseAddress)->e_lfanew,
  6711. &e_lfanew,
  6712. sizeof(e_lfanew),
  6713. NULL
  6714. );
  6715. if ( !b ) {
  6716. goto finally_exit;
  6717. }
  6718. NtHeader = (PIMAGE_NT_HEADERS)((PUCHAR)ImageBaseAddress + e_lfanew);
  6719. //
  6720. // Read subsystem version info
  6721. //
  6722. b = ReadProcessMemory(
  6723. hProcess,
  6724. &NtHeader->OptionalHeader.MajorSubsystemVersion,
  6725. &SwappedVersion,
  6726. sizeof(SwappedVersion),
  6727. NULL
  6728. );
  6729. if ( !b ) {
  6730. goto finally_exit;
  6731. }
  6732. Version.MajorSubsystemVersion = SwappedVersion.MajorSubsystemVersion;
  6733. Version.MinorSubsystemVersion = SwappedVersion.MinorSubsystemVersion;
  6734. }
  6735. finally_exit:;
  6736. }
  6737. finally {
  6738. if ( hProcess ) {
  6739. CloseHandle(hProcess);
  6740. }
  6741. }
  6742. return Version.SubsystemVersion;
  6743. }
  6744. BOOL
  6745. WINAPI
  6746. SetProcessAffinityMask(
  6747. HANDLE hProcess,
  6748. DWORD_PTR dwProcessAffinityMask
  6749. )
  6750. {
  6751. NTSTATUS Status;
  6752. Status = NtSetInformationProcess(
  6753. hProcess,
  6754. ProcessAffinityMask,
  6755. &dwProcessAffinityMask,
  6756. sizeof(dwProcessAffinityMask)
  6757. );
  6758. if ( !NT_SUCCESS(Status) ) {
  6759. BaseSetLastNTError(Status);
  6760. return FALSE;
  6761. }
  6762. return TRUE;
  6763. }
  6764. BOOL
  6765. WINAPI
  6766. SetProcessPriorityBoost(
  6767. HANDLE hProcess,
  6768. BOOL bDisablePriorityBoost
  6769. )
  6770. {
  6771. NTSTATUS Status;
  6772. ULONG DisableBoost;
  6773. DisableBoost = bDisablePriorityBoost ? 1 : 0;
  6774. Status = NtSetInformationProcess(
  6775. hProcess,
  6776. ProcessPriorityBoost,
  6777. &DisableBoost,
  6778. sizeof(DisableBoost)
  6779. );
  6780. if ( !NT_SUCCESS(Status) ) {
  6781. BaseSetLastNTError(Status);
  6782. return FALSE;
  6783. }
  6784. return TRUE;
  6785. }
  6786. BOOL
  6787. WINAPI
  6788. GetProcessPriorityBoost(
  6789. HANDLE hProcess,
  6790. PBOOL pDisablePriorityBoost
  6791. )
  6792. {
  6793. NTSTATUS Status;
  6794. DWORD DisableBoost;
  6795. Status = NtQueryInformationProcess(
  6796. hProcess,
  6797. ProcessPriorityBoost,
  6798. &DisableBoost,
  6799. sizeof(DisableBoost),
  6800. NULL
  6801. );
  6802. if ( !NT_SUCCESS(Status) ) {
  6803. BaseSetLastNTError(Status);
  6804. return FALSE;
  6805. }
  6806. *pDisablePriorityBoost = DisableBoost;
  6807. return TRUE;
  6808. }
  6809. BOOL
  6810. WINAPI
  6811. GetProcessIoCounters(
  6812. IN HANDLE hProcess,
  6813. OUT PIO_COUNTERS lpIoCounters
  6814. )
  6815. {
  6816. NTSTATUS Status;
  6817. Status = NtQueryInformationProcess(
  6818. hProcess,
  6819. ProcessIoCounters,
  6820. lpIoCounters,
  6821. sizeof(IO_COUNTERS),
  6822. NULL
  6823. );
  6824. if ( !NT_SUCCESS(Status) ) {
  6825. BaseSetLastNTError(Status);
  6826. return FALSE;
  6827. }
  6828. return TRUE;
  6829. }
  6830. BOOL
  6831. WINAPI
  6832. GetProcessHandleCount(
  6833. IN HANDLE hProcess,
  6834. OUT PDWORD pdwHandleCount
  6835. )
  6836. /*++
  6837. Routine Description:
  6838. This function returns the count of handles open by the specified process.
  6839. Arguments:
  6840. hProcess - Supplies an open handle to the specified process. The
  6841. handle must have been created with PROCESS_QUERY_INFORMATION
  6842. access.
  6843. pdwHandleCount - Supplies the location in which the process's
  6844. handle count should be written.
  6845. Return Value:
  6846. TRUE - The API was successful
  6847. FALSE - The operation failed. Extended error status is available
  6848. using GetLastError.
  6849. --*/
  6850. {
  6851. NTSTATUS Status;
  6852. ULONG HandleCount;
  6853. Status = NtQueryInformationProcess(
  6854. hProcess,
  6855. ProcessHandleCount,
  6856. &HandleCount,
  6857. sizeof(HandleCount),
  6858. NULL);
  6859. if (! NT_SUCCESS(Status)) {
  6860. BaseSetLastNTError(Status);
  6861. return FALSE;
  6862. }
  6863. *pdwHandleCount = HandleCount;
  6864. return TRUE;
  6865. }
  6866. BOOL
  6867. WINAPI
  6868. GetSystemRegistryQuota(
  6869. OUT PDWORD pdwQuotaAllowed,
  6870. OUT PDWORD pdwQuotaUsed
  6871. )
  6872. /*++
  6873. Routine Description:
  6874. This function returns the system registry's quota.
  6875. Arguments:
  6876. pdwQuotaAllowed - Supplies the location in which to write the
  6877. maximum size the registry may attain.
  6878. pdwQuotaUsed - Supplies the location in which to write the amount
  6879. of registry quota currently in use.
  6880. Return Value:
  6881. TRUE - The API was successful
  6882. FALSE - The operation failed. Extended error status is available
  6883. using GetLastError.
  6884. --*/
  6885. {
  6886. NTSTATUS Status;
  6887. SYSTEM_REGISTRY_QUOTA_INFORMATION QuotaInfo;
  6888. Status = NtQuerySystemInformation(
  6889. SystemRegistryQuotaInformation,
  6890. &QuotaInfo,
  6891. sizeof(QuotaInfo),
  6892. NULL);
  6893. if (! NT_SUCCESS(Status)) {
  6894. BaseSetLastNTError(Status);
  6895. return FALSE;
  6896. }
  6897. if (pdwQuotaAllowed) {
  6898. *pdwQuotaAllowed = QuotaInfo.RegistryQuotaAllowed;
  6899. }
  6900. if (pdwQuotaUsed) {
  6901. *pdwQuotaUsed = QuotaInfo.RegistryQuotaUsed;
  6902. }
  6903. return TRUE;
  6904. }
  6905. NTSTATUS
  6906. BasepConfigureAppCertDlls(
  6907. IN PWSTR ValueName,
  6908. IN ULONG ValueType,
  6909. IN PVOID ValueData,
  6910. IN ULONG ValueLength,
  6911. IN PVOID Context,
  6912. IN PVOID EntryContext
  6913. )
  6914. {
  6915. UNREFERENCED_PARAMETER( Context );
  6916. return (BasepSaveAppCertRegistryValue( (PLIST_ENTRY)EntryContext,
  6917. ValueName,
  6918. ValueData
  6919. )
  6920. );
  6921. }
  6922. NTSTATUS
  6923. BasepSaveAppCertRegistryValue(
  6924. IN OUT PLIST_ENTRY ListHead,
  6925. IN PWSTR Name,
  6926. IN PWSTR Value OPTIONAL
  6927. )
  6928. {
  6929. PLIST_ENTRY Next;
  6930. PBASEP_APPCERT_ENTRY p;
  6931. UNICODE_STRING UnicodeName;
  6932. RtlInitUnicodeString( &UnicodeName, Name );
  6933. Next = ListHead->Flink;
  6934. while ( Next != ListHead ) {
  6935. p = CONTAINING_RECORD( Next,
  6936. BASEP_APPCERT_ENTRY,
  6937. Entry
  6938. );
  6939. if (!RtlCompareUnicodeString( &p->Name, &UnicodeName, TRUE )) {
  6940. #if DBG
  6941. DbgPrint("BasepSaveRegistryValue: Entry already exists for Certification Component %ws\n",Name);
  6942. #endif
  6943. return( STATUS_SUCCESS );
  6944. }
  6945. Next = Next->Flink;
  6946. }
  6947. p = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( TMP_TAG ), sizeof( *p ) + UnicodeName.MaximumLength );
  6948. if (p == NULL) {
  6949. #if DBG
  6950. DbgPrint("BasepSaveRegistryValue: Failed to allocate memory\n");
  6951. #endif
  6952. return( STATUS_NO_MEMORY );
  6953. }
  6954. InitializeListHead( &p->Entry );
  6955. p->Name.Buffer = (PWSTR)(p+1);
  6956. p->Name.Length = UnicodeName.Length;
  6957. p->Name.MaximumLength = UnicodeName.MaximumLength;
  6958. RtlMoveMemory( p->Name.Buffer,
  6959. UnicodeName.Buffer,
  6960. UnicodeName.MaximumLength
  6961. );
  6962. InsertTailList( ListHead, &p->Entry );
  6963. if (ARGUMENT_PRESENT( Value )) {
  6964. //
  6965. // load certification DLL
  6966. //
  6967. HINSTANCE hDll = LoadLibraryW( Value );
  6968. if (hDll == NULL) {
  6969. //
  6970. // The library was not loaded, return.
  6971. //
  6972. RemoveEntryList( &p->Entry );
  6973. RtlFreeHeap( RtlProcessHeap(), 0, p );
  6974. #if DBG
  6975. DbgPrint("BasepSaveRegistryValue: Certification DLL %ws not found\n", Value);
  6976. #endif
  6977. return( STATUS_SUCCESS );
  6978. }
  6979. //
  6980. // get entry point
  6981. //
  6982. p->fPluginCertFunc = (NTSTATUS (WINAPI *)(LPCWSTR,ULONG))
  6983. GetProcAddress(hDll,
  6984. CERTAPP_ENTRYPOINT_NAME
  6985. );
  6986. if (p->fPluginCertFunc == NULL) {
  6987. //
  6988. // Unable to retrieve routine address, fail.
  6989. //
  6990. RemoveEntryList( &p->Entry );
  6991. RtlFreeHeap( RtlProcessHeap(), 0, p );
  6992. FreeLibrary(hDll);
  6993. #if DBG
  6994. DbgPrint("BasepSaveRegistryValue: DLL %ws does not have entry point %s\n", Value,CERTAPP_ENTRYPOINT_NAME);
  6995. #endif
  6996. return( STATUS_SUCCESS );
  6997. }
  6998. }
  6999. else {
  7000. RemoveEntryList( &p->Entry );
  7001. RtlFreeHeap( RtlProcessHeap(), 0, p );
  7002. #if DBG
  7003. DbgPrint("BasepSaveRegistryValue: Entry %ws is empty \n", Name);
  7004. #endif
  7005. return( STATUS_SUCCESS );
  7006. }
  7007. return( STATUS_SUCCESS );
  7008. }
  7009. BOOL
  7010. IsWow64Process(
  7011. HANDLE hProcess,
  7012. PBOOL Wow64Process
  7013. )
  7014. /*++
  7015. Routine Description:
  7016. Checks if a process is running inside Wow64 (emulation for 32-bit applications
  7017. on Win64).
  7018. Arguments:
  7019. hProcess - Process handle to check if it is running inside Wow64.
  7020. Wow64Process - Pointer to a boolean that receives the result if the function succeeds.
  7021. Return Value:
  7022. BOOL
  7023. --*/
  7024. {
  7025. NTSTATUS NtStatus;
  7026. BOOL bRet;
  7027. ULONG_PTR Peb32;
  7028. NtStatus = NtQueryInformationProcess (
  7029. hProcess,
  7030. ProcessWow64Information,
  7031. &Peb32,
  7032. sizeof (Peb32),
  7033. NULL
  7034. );
  7035. if (!NT_SUCCESS (NtStatus)) {
  7036. BaseSetLastNTError (NtStatus);
  7037. } else {
  7038. if (Peb32 == 0) {
  7039. *Wow64Process = FALSE;
  7040. } else {
  7041. *Wow64Process = TRUE;
  7042. }
  7043. }
  7044. return (NT_SUCCESS (NtStatus));
  7045. }
  7046. #if defined(_WIN64) || defined(BUILD_WOW6432)
  7047. BOOL
  7048. NtVdm64CreateProcess(
  7049. BOOL fPrefixMappedApplicationName,
  7050. LPCWSTR lpApplicationName,
  7051. LPCWSTR lpCommandLine,
  7052. LPSECURITY_ATTRIBUTES lpProcessAttributes,
  7053. LPSECURITY_ATTRIBUTES lpThreadAttributes,
  7054. BOOL bInheritHandles,
  7055. DWORD dwCreationFlags,
  7056. LPVOID lpEnvironment,
  7057. LPCWSTR lpCurrentDirectory,
  7058. LPSTARTUPINFOW lpStartupInfo,
  7059. LPPROCESS_INFORMATION lpProcessInformation
  7060. )
  7061. /*++
  7062. Routine Description:
  7063. Checks if there is a ported version of the Win16 lpApplicationName and
  7064. if so creates a process with the ported version.
  7065. Arguments:
  7066. fPrefixMappedApplicationName
  7067. - TRUE means that the original lpApplicationName was NULL.
  7068. The application name was stripped from the head of
  7069. lpCommandLine.
  7070. The mapped application name needs to be added to the
  7071. head of the mapped command line.
  7072. - FALSE means that the original lpApplicationName was non-NULL.
  7073. the lpCommandLine argument is identical to the original
  7074. lpCommandLine argument.
  7075. lpApplicationName - Win16 file name not optional
  7076. lpCommandLine - see comment for fPrefixMappedApplicationName.
  7077. other arguments are identical to CreateProcessW.
  7078. Return Value:
  7079. Same as CreateProcessW
  7080. --*/
  7081. {
  7082. typedef BOOL
  7083. (*LPNtVdm64CreateProcessFn)(
  7084. BOOL fPrefixMappedApplicationName,
  7085. LPCWSTR lpApplicationName,
  7086. LPCWSTR lpCommandLine,
  7087. LPSECURITY_ATTRIBUTES lpProcessAttributes,
  7088. LPSECURITY_ATTRIBUTES lpThreadAttributes,
  7089. BOOL bInheritHandles,
  7090. DWORD dwCreationFlags,
  7091. LPVOID lpEnvironment,
  7092. LPCWSTR lpCurrentDirectory,
  7093. LPSTARTUPINFOW lpStartupInfo,
  7094. LPPROCESS_INFORMATION lpProcessInformation
  7095. );
  7096. HINSTANCE hInstance;
  7097. LPNtVdm64CreateProcessFn lpfn;
  7098. BOOL result;
  7099. NTSTATUS Status;
  7100. WCHAR StaticUnicodeBuffer[STATIC_UNICODE_BUFFER_LENGTH];
  7101. hInstance = NULL;
  7102. Status = ERROR_BAD_EXE_FORMAT;
  7103. result = FALSE;
  7104. // so it turns out that there is a high probability that
  7105. // lpCommandLine sits in the StaticUnicodeBuffer in the Teb
  7106. // and also a high probability that LoadLibrary will trash that
  7107. // buffer in a bad way
  7108. if (lpCommandLine >= NtCurrentTeb()->StaticUnicodeBuffer &&
  7109. lpCommandLine < &NtCurrentTeb()->StaticUnicodeBuffer[STATIC_UNICODE_BUFFER_LENGTH]) {
  7110. wcscpy(StaticUnicodeBuffer, lpCommandLine);
  7111. lpCommandLine = StaticUnicodeBuffer;
  7112. }
  7113. hInstance = LoadLibraryW(L"NtVdm64.Dll");
  7114. if (hInstance == NULL) {
  7115. goto ErrorExit;
  7116. }
  7117. lpfn = (LPNtVdm64CreateProcessFn) GetProcAddress(hInstance, "NtVdm64CreateProcess");
  7118. if (lpfn == NULL) {
  7119. goto ErrorExit;
  7120. }
  7121. result = (*lpfn)(fPrefixMappedApplicationName,
  7122. lpApplicationName,
  7123. lpCommandLine,
  7124. lpProcessAttributes,
  7125. lpThreadAttributes,
  7126. bInheritHandles,
  7127. dwCreationFlags,
  7128. lpEnvironment,
  7129. lpCurrentDirectory,
  7130. lpStartupInfo,
  7131. lpProcessInformation
  7132. );
  7133. Status = GetLastError();
  7134. ErrorExit:
  7135. if (hInstance != NULL) {
  7136. FreeLibrary(hInstance);
  7137. }
  7138. SetLastError(Status);
  7139. return result;
  7140. }
  7141. #endif