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

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