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

2483 lines
66 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. support.c
  5. Abstract:
  6. This module implements various conversion routines
  7. that transform Win32 parameters into NT parameters.
  8. Author:
  9. Mark Lucovsky (markl) 20-Sep-1990
  10. Revision History:
  11. --*/
  12. #include "basedll.h"
  13. PCLDR_DATA_TABLE_ENTRY BasepExeLdrEntry = NULL;
  14. // N.B. These are the registry values we check for SafeDllSearchMode,
  15. // and MUST match the entries in BasepDllSearchPaths
  16. typedef enum {
  17. BasepCurrentDirUninitialized = -1,
  18. BasepCurrentDirAtStart = 0,
  19. BasepCurrentDirAfterSystem32 = 1,
  20. MaxBasepCurrentDir
  21. } BASEP_CURDIR_PLACEMENT;
  22. #define BASEP_DEFAULT_DLL_CURDIR_PLACEMENT (BasepCurrentDirAfterSystem32)
  23. #define BASEP_VALID_CURDIR_PLACEMENT_P(c) (BasepCurrentDirUninitialized < (c) \
  24. && (c) < MaxBasepCurrentDir)
  25. LONG BasepDllCurrentDirPlacement = BasepCurrentDirUninitialized;
  26. typedef enum {
  27. BasepSearchPathEnd, // end of path
  28. BasepSearchPathDlldir, // use the dll dir; fallback to nothing
  29. BasepSearchPathAppdir, // use the exe dir; fallback to base exe dir
  30. BasepSearchPathDefaultDirs, // use the default system dirs
  31. BasepSearchPathEnvPath, // use %PATH%
  32. BasepSearchPathCurdir, // use "."
  33. MaxBasepSearchPath
  34. } BASEP_SEARCH_PATH_ELEMENT;
  35. // N.B. The ordering of these must match the definitions for
  36. // BASEP_CURDIR_PLACEMENT.
  37. static const BASEP_SEARCH_PATH_ELEMENT BasepDllSearchPaths[MaxBasepCurrentDir][7] =
  38. {
  39. {
  40. // BasepCurrentDirAtStart
  41. BasepSearchPathAppdir,
  42. BasepSearchPathCurdir,
  43. BasepSearchPathDefaultDirs,
  44. BasepSearchPathEnvPath,
  45. BasepSearchPathEnd
  46. },
  47. {
  48. // BasepCurrentDirAfterSystem32
  49. BasepSearchPathAppdir,
  50. BasepSearchPathDefaultDirs,
  51. BasepSearchPathCurdir,
  52. BasepSearchPathEnvPath,
  53. BasepSearchPathEnd
  54. }
  55. };
  56. POBJECT_ATTRIBUTES
  57. BaseFormatObjectAttributes(
  58. OUT POBJECT_ATTRIBUTES ObjectAttributes,
  59. IN PSECURITY_ATTRIBUTES SecurityAttributes,
  60. IN PUNICODE_STRING ObjectName
  61. )
  62. /*++
  63. Routine Description:
  64. This function transforms a Win32 security attributes structure into
  65. an NT object attributes structure. It returns the address of the
  66. resulting structure (or NULL if SecurityAttributes was not
  67. specified).
  68. Arguments:
  69. ObjectAttributes - Returns an initialized NT object attributes
  70. structure that contains a superset of the information provided
  71. by the security attributes structure.
  72. SecurityAttributes - Supplies the address of a security attributes
  73. structure that needs to be transformed into an NT object
  74. attributes structure.
  75. ObjectName - Supplies a name for the object relative to the
  76. BaseNamedObjectDirectory object directory.
  77. Return Value:
  78. NULL - A value of null should be used to mimic the behavior of the
  79. specified SecurityAttributes structure.
  80. NON-NULL - Returns the ObjectAttributes value. The structure is
  81. properly initialized by this function.
  82. --*/
  83. {
  84. HANDLE RootDirectory;
  85. ULONG Attributes;
  86. PVOID SecurityDescriptor;
  87. if ( ARGUMENT_PRESENT(SecurityAttributes) ||
  88. ARGUMENT_PRESENT(ObjectName) ) {
  89. if ( ARGUMENT_PRESENT(ObjectName) ) {
  90. RootDirectory = BaseGetNamedObjectDirectory();
  91. }
  92. else {
  93. RootDirectory = NULL;
  94. }
  95. if ( SecurityAttributes ) {
  96. Attributes = (SecurityAttributes->bInheritHandle ? OBJ_INHERIT : 0);
  97. SecurityDescriptor = SecurityAttributes->lpSecurityDescriptor;
  98. }
  99. else {
  100. Attributes = 0;
  101. SecurityDescriptor = NULL;
  102. }
  103. if ( ARGUMENT_PRESENT(ObjectName) ) {
  104. Attributes |= OBJ_OPENIF;
  105. }
  106. InitializeObjectAttributes(
  107. ObjectAttributes,
  108. ObjectName,
  109. Attributes,
  110. RootDirectory,
  111. SecurityDescriptor
  112. );
  113. return ObjectAttributes;
  114. }
  115. else {
  116. return NULL;
  117. }
  118. }
  119. PLARGE_INTEGER
  120. BaseFormatTimeOut(
  121. OUT PLARGE_INTEGER TimeOut,
  122. IN DWORD Milliseconds
  123. )
  124. /*++
  125. Routine Description:
  126. This function translates a Win32 style timeout to an NT relative
  127. timeout value.
  128. Arguments:
  129. TimeOut - Returns an initialized NT timeout value that is equivalent
  130. to the Milliseconds parameter.
  131. Milliseconds - Supplies the timeout value in milliseconds. A value
  132. of -1 indicates indefinite timeout.
  133. Return Value:
  134. NULL - A value of null should be used to mimic the behavior of the
  135. specified Milliseconds parameter.
  136. NON-NULL - Returns the TimeOut value. The structure is properly
  137. initialized by this function.
  138. --*/
  139. {
  140. if ( (LONG) Milliseconds == -1 ) {
  141. return( NULL );
  142. }
  143. TimeOut->QuadPart = UInt32x32To64( Milliseconds, 10000 );
  144. TimeOut->QuadPart *= -1;
  145. return TimeOut;
  146. }
  147. NTSTATUS
  148. BaseCreateStack(
  149. IN HANDLE Process,
  150. IN SIZE_T StackSize,
  151. IN SIZE_T MaximumStackSize,
  152. OUT PINITIAL_TEB InitialTeb
  153. )
  154. /*++
  155. Routine Description:
  156. This function creates a stack for the specified process.
  157. Arguments:
  158. Process - Supplies a handle to the process that the stack will
  159. be allocated within.
  160. StackSize - An optional parameter, that if specified, supplies
  161. the initial commit size for the stack.
  162. MaximumStackSize - Supplies the maximum size for the new threads stack.
  163. If this parameter is not specified, then the reserve size of the
  164. current images stack descriptor is used.
  165. InitialTeb - Returns a populated InitialTeb that contains
  166. the stack size and limits.
  167. Return Value:
  168. TRUE - A stack was successfully created.
  169. FALSE - The stack counld not be created.
  170. --*/
  171. {
  172. NTSTATUS Status;
  173. PCH Stack;
  174. BOOLEAN GuardPage;
  175. SIZE_T RegionSize;
  176. ULONG OldProtect;
  177. SIZE_T ImageStackSize, ImageStackCommit;
  178. PIMAGE_NT_HEADERS NtHeaders;
  179. PPEB Peb;
  180. ULONG PageSize;
  181. Peb = NtCurrentPeb();
  182. BaseStaticServerData = BASE_SHARED_SERVER_DATA;
  183. PageSize = BASE_SYSINFO.PageSize;
  184. //
  185. // If the stack size was not supplied, then use the sizes from the
  186. // image header.
  187. //
  188. NtHeaders = RtlImageNtHeader(Peb->ImageBaseAddress);
  189. if (!NtHeaders) {
  190. return STATUS_INVALID_IMAGE_FORMAT;
  191. }
  192. ImageStackSize = NtHeaders->OptionalHeader.SizeOfStackReserve;
  193. ImageStackCommit = NtHeaders->OptionalHeader.SizeOfStackCommit;
  194. if ( !MaximumStackSize ) {
  195. MaximumStackSize = ImageStackSize;
  196. }
  197. if (!StackSize) {
  198. StackSize = ImageStackCommit;
  199. }
  200. else {
  201. //
  202. // Now Compute how much additional stack space is to be
  203. // reserved. This is done by... If the StackSize is <=
  204. // Reserved size in the image, then reserve whatever the image
  205. // specifies. Otherwise, round up to 1Mb.
  206. //
  207. if ( StackSize >= MaximumStackSize ) {
  208. MaximumStackSize = ROUND_UP(StackSize, (1024*1024));
  209. }
  210. }
  211. //
  212. // Align the stack size to a page boundry and the reserved size
  213. // to an allocation granularity boundry.
  214. //
  215. StackSize = ROUND_UP( StackSize, PageSize );
  216. MaximumStackSize = ROUND_UP(
  217. MaximumStackSize,
  218. BASE_SYSINFO.AllocationGranularity
  219. );
  220. //
  221. // Enforce a minimal stack commit if there is a PEB setting
  222. // for this.
  223. //
  224. {
  225. SIZE_T MinimumStackCommit;
  226. MinimumStackCommit = NtCurrentPeb()->MinimumStackCommit;
  227. if (MinimumStackCommit != 0 && StackSize < MinimumStackCommit) {
  228. StackSize = MinimumStackCommit;
  229. }
  230. //
  231. // Recheck and realign reserve size
  232. //
  233. if ( StackSize >= MaximumStackSize ) {
  234. MaximumStackSize = ROUND_UP (StackSize, (1024*1024));
  235. }
  236. StackSize = ROUND_UP (StackSize, PageSize);
  237. MaximumStackSize = ROUND_UP (MaximumStackSize, BASE_SYSINFO.AllocationGranularity);
  238. }
  239. #if !defined (_IA64_)
  240. //
  241. // Reserve address space for the stack
  242. //
  243. Stack = NULL;
  244. Status = NtAllocateVirtualMemory(
  245. Process,
  246. (PVOID *)&Stack,
  247. 0,
  248. &MaximumStackSize,
  249. MEM_RESERVE,
  250. PAGE_READWRITE
  251. );
  252. #else
  253. //
  254. // Take RseStack into consideration.
  255. // RSE stack has same size as memory stack, has same StackBase,
  256. // has a guard page at the end, and grows upwards towards higher
  257. // memory addresses
  258. //
  259. //
  260. // Reserve address space for the two stacks
  261. //
  262. {
  263. SIZE_T TotalStackSize = MaximumStackSize * 2;
  264. Stack = NULL;
  265. Status = NtAllocateVirtualMemory(
  266. Process,
  267. (PVOID *)&Stack,
  268. 0,
  269. &TotalStackSize,
  270. MEM_RESERVE,
  271. PAGE_READWRITE
  272. );
  273. }
  274. #endif // IA64
  275. if ( !NT_SUCCESS( Status ) ) {
  276. return Status;
  277. }
  278. InitialTeb->OldInitialTeb.OldStackBase = NULL;
  279. InitialTeb->OldInitialTeb.OldStackLimit = NULL;
  280. InitialTeb->StackAllocationBase = Stack;
  281. InitialTeb->StackBase = Stack + MaximumStackSize;
  282. #if defined (_IA64_)
  283. InitialTeb->OldInitialTeb.OldBStoreLimit = NULL;
  284. #endif //IA64
  285. Stack += MaximumStackSize - StackSize;
  286. if (MaximumStackSize > StackSize) {
  287. Stack -= PageSize;
  288. StackSize += PageSize;
  289. GuardPage = TRUE;
  290. }
  291. else {
  292. GuardPage = FALSE;
  293. }
  294. //
  295. // Commit the initially valid portion of the stack
  296. //
  297. #if !defined(_IA64_)
  298. Status = NtAllocateVirtualMemory(
  299. Process,
  300. (PVOID *)&Stack,
  301. 0,
  302. &StackSize,
  303. MEM_COMMIT,
  304. PAGE_READWRITE
  305. );
  306. #else
  307. {
  308. //
  309. // memory and rse stacks are expected to be contiguous
  310. // reserver virtual memory for both stack at once
  311. //
  312. SIZE_T NewCommittedStackSize = StackSize * 2;
  313. Status = NtAllocateVirtualMemory(
  314. Process,
  315. (PVOID *)&Stack,
  316. 0,
  317. &NewCommittedStackSize,
  318. MEM_COMMIT,
  319. PAGE_READWRITE
  320. );
  321. }
  322. #endif //IA64
  323. if ( !NT_SUCCESS( Status ) ) {
  324. //
  325. // If the commit fails, then delete the address space for the stack
  326. //
  327. RegionSize = 0;
  328. NtFreeVirtualMemory(
  329. Process,
  330. (PVOID *)&Stack,
  331. &RegionSize,
  332. MEM_RELEASE
  333. );
  334. return Status;
  335. }
  336. InitialTeb->StackLimit = Stack;
  337. #if defined(_IA64_)
  338. InitialTeb->BStoreLimit = Stack + 2 * StackSize;
  339. #endif
  340. //
  341. // if we have space, create a guard page.
  342. //
  343. if (GuardPage) {
  344. RegionSize = PageSize;
  345. Status = NtProtectVirtualMemory(
  346. Process,
  347. (PVOID *)&Stack,
  348. &RegionSize,
  349. PAGE_GUARD | PAGE_READWRITE,
  350. &OldProtect
  351. );
  352. if ( !NT_SUCCESS( Status ) ) {
  353. return Status;
  354. }
  355. InitialTeb->StackLimit = (PVOID)((PUCHAR)InitialTeb->StackLimit + RegionSize);
  356. #if defined(_IA64_)
  357. //
  358. // additional code to Create RSE stack guard page
  359. //
  360. Stack = ((PCH)InitialTeb->StackBase) + StackSize - PageSize;
  361. RegionSize = PageSize;
  362. Status = NtProtectVirtualMemory(
  363. Process,
  364. (PVOID *)&Stack,
  365. &RegionSize,
  366. PAGE_GUARD | PAGE_READWRITE,
  367. &OldProtect
  368. );
  369. if ( !NT_SUCCESS( Status ) ) {
  370. return Status;
  371. }
  372. InitialTeb->BStoreLimit = (PVOID)Stack;
  373. #endif // IA64
  374. }
  375. return STATUS_SUCCESS;
  376. }
  377. VOID
  378. BaseThreadStart(
  379. IN LPTHREAD_START_ROUTINE lpStartAddress,
  380. IN LPVOID lpParameter
  381. )
  382. /*++
  383. Routine Description:
  384. This function is called to start a Win32 thread. Its purpose
  385. is to call the thread, and if the thread returns, to terminate
  386. the thread and delete its stack.
  387. Arguments:
  388. lpStartAddress - Supplies the starting address of the new thread. The
  389. address is logically a procedure that never returns and that
  390. accepts a single 32-bit pointer argument.
  391. lpParameter - Supplies a single parameter value passed to the thread.
  392. Return Value:
  393. None.
  394. --*/
  395. {
  396. try {
  397. //
  398. // test for fiber start or new thread
  399. //
  400. //
  401. // WARNING WARNING DO NOT CHANGE INIT OF NtTib.Version. There is
  402. // external code depending on this initialization !
  403. //
  404. if ( NtCurrentTeb()->NtTib.Version == OS2_VERSION ) {
  405. if ( !BaseRunningInServerProcess ) {
  406. CsrNewThread();
  407. }
  408. }
  409. ExitThread((lpStartAddress)(lpParameter));
  410. }
  411. except(UnhandledExceptionFilter( GetExceptionInformation() )) {
  412. if ( !BaseRunningInServerProcess ) {
  413. ExitProcess(GetExceptionCode());
  414. }
  415. else {
  416. ExitThread(GetExceptionCode());
  417. }
  418. }
  419. }
  420. VOID
  421. BaseProcessStart(
  422. PPROCESS_START_ROUTINE lpStartAddress
  423. )
  424. /*++
  425. Routine Description:
  426. This function is called to start a Win32 process. Its purpose is to
  427. call the initial thread of the process, and if the thread returns,
  428. to terminate the thread and delete its stack.
  429. Arguments:
  430. lpStartAddress - Supplies the starting address of the new thread. The
  431. address is logically a procedure that never returns.
  432. Return Value:
  433. None.
  434. --*/
  435. {
  436. try {
  437. NtSetInformationThread( NtCurrentThread(),
  438. ThreadQuerySetWin32StartAddress,
  439. &lpStartAddress,
  440. sizeof( lpStartAddress )
  441. );
  442. ExitThread((lpStartAddress)());
  443. }
  444. except(UnhandledExceptionFilter( GetExceptionInformation() )) {
  445. if ( !BaseRunningInServerProcess ) {
  446. ExitProcess(GetExceptionCode());
  447. }
  448. else {
  449. ExitThread(GetExceptionCode());
  450. }
  451. }
  452. }
  453. VOID
  454. BaseFreeStackAndTerminate(
  455. IN PVOID OldStack,
  456. IN DWORD ExitCode
  457. )
  458. /*++
  459. Routine Description:
  460. This API is called during thread termination to delete a thread's
  461. stack and then terminate.
  462. Arguments:
  463. OldStack - Supplies the address of the stack to free.
  464. ExitCode - Supplies the termination status that the thread
  465. is to exit with.
  466. Return Value:
  467. None.
  468. --*/
  469. {
  470. NTSTATUS Status;
  471. SIZE_T Zero;
  472. PVOID BaseAddress;
  473. #if defined (WX86)
  474. PWX86TIB Wx86Tib;
  475. PTEB Teb;
  476. #endif
  477. Zero = 0;
  478. BaseAddress = OldStack;
  479. Status = NtFreeVirtualMemory(
  480. NtCurrentProcess(),
  481. &BaseAddress,
  482. &Zero,
  483. MEM_RELEASE
  484. );
  485. ASSERT(NT_SUCCESS(Status));
  486. #if defined (WX86)
  487. Teb = NtCurrentTeb();
  488. if (Teb && (Wx86Tib = Wx86CurrentTib())) {
  489. BaseAddress = Wx86Tib->DeallocationStack;
  490. Zero = 0;
  491. Status = NtFreeVirtualMemory(
  492. NtCurrentProcess(),
  493. &BaseAddress,
  494. &Zero,
  495. MEM_RELEASE
  496. );
  497. ASSERT(NT_SUCCESS(Status));
  498. if (Teb->Wx86Thread.DeallocationCpu) {
  499. BaseAddress = Teb->Wx86Thread.DeallocationCpu;
  500. Zero = 0;
  501. Status = NtFreeVirtualMemory(
  502. NtCurrentProcess(),
  503. &BaseAddress,
  504. &Zero,
  505. MEM_RELEASE
  506. );
  507. ASSERT(NT_SUCCESS(Status));
  508. }
  509. }
  510. #endif
  511. //
  512. // Don't worry, no commenting precedent has been set by SteveWo. this
  513. // comment was added by an innocent bystander.
  514. //
  515. // NtTerminateThread will return if this thread is the last one in
  516. // the process. So ExitProcess will only be called if that is the
  517. // case.
  518. //
  519. NtTerminateThread(NULL,(NTSTATUS)ExitCode);
  520. ExitProcess(ExitCode);
  521. }
  522. #if defined(WX86) || defined(_AXP64_)
  523. NTSTATUS
  524. BaseCreateWx86Tib(
  525. HANDLE Process,
  526. HANDLE Thread,
  527. ULONG InitialPc,
  528. ULONG CommittedStackSize,
  529. ULONG MaximumStackSize,
  530. BOOLEAN EmulateInitialPc
  531. )
  532. /*++
  533. Routine Description:
  534. This API is called to create a Wx86Tib for Wx86 emulated threads
  535. Arguments:
  536. Process - Target Process
  537. Thread - Target Thread
  538. Parameter - Supplies the thread's parameter.
  539. InitialPc - Supplies an initial program counter value.
  540. StackSize - BaseCreateStack parameters
  541. MaximumStackSize - BaseCreateStack parameters
  542. BOOLEAN
  543. Return Value:
  544. NtStatus from mem allocations
  545. --*/
  546. {
  547. NTSTATUS Status;
  548. PTEB Teb;
  549. ULONG Size, SizeWx86Tib;
  550. PVOID TargetWx86Tib;
  551. PIMAGE_NT_HEADERS NtHeaders;
  552. WX86TIB Wx86Tib;
  553. INITIAL_TEB InitialTeb;
  554. THREAD_BASIC_INFORMATION ThreadInfo;
  555. Status = NtQueryInformationThread(
  556. Thread,
  557. ThreadBasicInformation,
  558. &ThreadInfo,
  559. sizeof( ThreadInfo ),
  560. NULL
  561. );
  562. if (!NT_SUCCESS(Status)) {
  563. return Status;
  564. }
  565. Teb = ThreadInfo.TebBaseAddress;
  566. //
  567. // if stack size not supplied, get from current image
  568. //
  569. NtHeaders = RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress);
  570. if (!NtHeaders) {
  571. return STATUS_INVALID_IMAGE_FORMAT;
  572. }
  573. if (!MaximumStackSize) {
  574. MaximumStackSize = (ULONG)NtHeaders->OptionalHeader.SizeOfStackReserve;
  575. }
  576. if (!CommittedStackSize) {
  577. CommittedStackSize = (ULONG)NtHeaders->OptionalHeader.SizeOfStackCommit;
  578. }
  579. //
  580. // Increase stack size for Wx86Tib, which sits at the top of the stack.
  581. //
  582. //
  583. // x86 Borland C++ 4.1 (and perhaps other versions) Rudely assumes that
  584. // it can use the top of the stack. Even tho this is completly bogus,
  585. // leave some space on the top of the stack, to avoid problems.
  586. //
  587. SizeWx86Tib = sizeof(WX86TIB) + 16;
  588. SizeWx86Tib = ROUND_UP(SizeWx86Tib, sizeof(ULONG));
  589. Size = (ULONG)ROUND_UP_TO_PAGES(SizeWx86Tib + 4096);
  590. if (CommittedStackSize < 1024 * 1024) { // 1 MB
  591. CommittedStackSize += Size;
  592. }
  593. if (MaximumStackSize < 1024 * 1024 * 16) { // 10 MB
  594. MaximumStackSize += Size;
  595. }
  596. if (MaximumStackSize < 256 * 1024) {
  597. // Enforce a minimum stack size of 256k since the CPU emulator
  598. // grabs several pages of the x86 stack for itself
  599. MaximumStackSize = 256 * 1024;
  600. }
  601. Status = BaseCreateStack( Process,
  602. CommittedStackSize,
  603. MaximumStackSize,
  604. &InitialTeb
  605. );
  606. if (!NT_SUCCESS(Status)) {
  607. return Status;
  608. }
  609. //
  610. // Fill in the Teb->Vdm with pWx86Tib
  611. //
  612. TargetWx86Tib = (PVOID)((ULONG_PTR)InitialTeb.StackBase - SizeWx86Tib);
  613. Status = NtWriteVirtualMemory(Process,
  614. &Teb->Vdm,
  615. &TargetWx86Tib,
  616. sizeof(TargetWx86Tib),
  617. NULL
  618. );
  619. if (NT_SUCCESS(Status)) {
  620. //
  621. // Write the initial Wx86Tib information
  622. //
  623. RtlZeroMemory(&Wx86Tib, sizeof(WX86TIB));
  624. Wx86Tib.Size = sizeof(WX86TIB);
  625. Wx86Tib.InitialPc = InitialPc;
  626. Wx86Tib.InitialSp = (ULONG)((ULONG_PTR)TargetWx86Tib);
  627. Wx86Tib.StackBase = (VOID * POINTER_32) InitialTeb.StackBase;
  628. Wx86Tib.StackLimit = (VOID * POINTER_32) InitialTeb.StackLimit;
  629. Wx86Tib.DeallocationStack = (VOID * POINTER_32) InitialTeb.StackAllocationBase;
  630. Wx86Tib.EmulateInitialPc = EmulateInitialPc;
  631. Status = NtWriteVirtualMemory(Process,
  632. TargetWx86Tib,
  633. &Wx86Tib,
  634. sizeof(WX86TIB),
  635. NULL
  636. );
  637. }
  638. if (!NT_SUCCESS(Status)) {
  639. BaseFreeThreadStack(Process, NULL, &InitialTeb);
  640. }
  641. return Status;
  642. }
  643. #endif
  644. VOID
  645. BaseFreeThreadStack(
  646. HANDLE hProcess,
  647. HANDLE hThread,
  648. PINITIAL_TEB InitialTeb
  649. )
  650. /*++
  651. Routine Description:
  652. Deletes a thread's stack
  653. Arguments:
  654. Process - Target process
  655. Thread - Target thread OPTIONAL
  656. InitialTeb - stack paremeters
  657. Return Value:
  658. VOID
  659. --*/
  660. {
  661. NTSTATUS Status;
  662. DWORD dwStackSize;
  663. SIZE_T stStackSize;
  664. PVOID BaseAddress;
  665. stStackSize = 0;
  666. dwStackSize = 0;
  667. BaseAddress = InitialTeb->StackAllocationBase;
  668. NtFreeVirtualMemory( hProcess,
  669. &BaseAddress,
  670. &stStackSize,
  671. MEM_RELEASE
  672. );
  673. #if defined (WX86)
  674. if (hThread) {
  675. PTEB Teb;
  676. PWX86TIB pWx86Tib;
  677. WX86TIB Wx86Tib;
  678. THREAD_BASIC_INFORMATION ThreadInfo;
  679. Status = NtQueryInformationThread(
  680. hThread,
  681. ThreadBasicInformation,
  682. &ThreadInfo,
  683. sizeof( ThreadInfo ),
  684. NULL
  685. );
  686. Teb = ThreadInfo.TebBaseAddress;
  687. if (!NT_SUCCESS(Status) || !Teb) {
  688. return;
  689. }
  690. Status = NtReadVirtualMemory(
  691. hProcess,
  692. &Teb->Vdm,
  693. &pWx86Tib,
  694. sizeof(pWx86Tib),
  695. NULL
  696. );
  697. if (!NT_SUCCESS(Status) || !pWx86Tib) {
  698. return;
  699. }
  700. Status = NtReadVirtualMemory(
  701. hProcess,
  702. pWx86Tib,
  703. &Wx86Tib,
  704. sizeof(Wx86Tib),
  705. NULL
  706. );
  707. if (NT_SUCCESS(Status) && Wx86Tib.Size == sizeof(WX86TIB)) {
  708. // release the wx86tib stack
  709. dwStackSize = 0;
  710. stStackSize = 0;
  711. BaseAddress = Wx86Tib.DeallocationStack;
  712. NtFreeVirtualMemory(hProcess,
  713. &BaseAddress,
  714. &stStackSize,
  715. MEM_RELEASE
  716. );
  717. // set Teb->Vdm = NULL;
  718. dwStackSize = 0;
  719. Status = NtWriteVirtualMemory(
  720. hProcess,
  721. &Teb->Vdm,
  722. &dwStackSize,
  723. sizeof(pWx86Tib),
  724. NULL
  725. );
  726. }
  727. }
  728. #endif
  729. }
  730. #if defined(BUILD_WOW6432)
  731. typedef struct _ENVIRONMENT_THUNK_TABLE
  732. {
  733. WCHAR *Native;
  734. WCHAR *X86;
  735. WCHAR *FakeName;
  736. } ENVIRONMENT_THUNK_TABLE, *PENVIRONMENT_THUNK_TABLE;
  737. ENVIRONMENT_THUNK_TABLE ProgramFilesEnvironment[] =
  738. {
  739. {
  740. L"ProgramFiles",
  741. L"ProgramFiles(x86)",
  742. L"ProgramW6432"
  743. },
  744. {
  745. L"CommonProgramFiles",
  746. L"CommonProgramFiles(x86)",
  747. L"CommonProgramW6432"
  748. },
  749. {
  750. L"PROCESSOR_ARCHITECTURE",
  751. L"PROCESSOR_ARCHITECTURE",
  752. L"PROCESSOR_ARCHITEW6432"
  753. }
  754. };
  755. NTSTATUS
  756. Wow64pThunkEnvironmentVariables (
  757. IN OUT PVOID *Environment
  758. )
  759. /*++
  760. Routine Description:
  761. This routine is called when we are about to create a 64-bit process for
  762. a 32-bit process. It thunks back the ProgramFiles environment
  763. variables so that they point to the native directory.
  764. This routine must stay in sync with what's in \base\wow64\wow64\init.c.
  765. Arguments:
  766. Environment - Address of pointer of environment variable to thunk.
  767. Return Value:
  768. NTSTATUS.
  769. --*/
  770. {
  771. UNICODE_STRING Name, Value;
  772. WCHAR Buffer [ MAX_PATH ];
  773. NTSTATUS NtStatus;
  774. ULONG i=0;
  775. while (i < (sizeof(ProgramFilesEnvironment) / sizeof(ProgramFilesEnvironment[0]))) {
  776. RtlInitUnicodeString (&Name, ProgramFilesEnvironment[i].FakeName);
  777. Value.Length = 0;
  778. Value.MaximumLength = sizeof (Buffer);
  779. Value.Buffer = Buffer;
  780. NtStatus = RtlQueryEnvironmentVariable_U (*Environment,
  781. &Name,
  782. &Value
  783. );
  784. if (NT_SUCCESS (NtStatus)) {
  785. RtlSetEnvironmentVariable (Environment,
  786. &Name,
  787. NULL
  788. );
  789. RtlInitUnicodeString (&Name, ProgramFilesEnvironment[i].Native);
  790. NtStatus = RtlSetEnvironmentVariable (Environment,
  791. &Name,
  792. &Value
  793. );
  794. }
  795. if (!NT_SUCCESS (NtStatus)) {
  796. break;
  797. }
  798. i++;
  799. }
  800. return NtStatus;
  801. }
  802. #endif
  803. BOOL
  804. BasePushProcessParameters(
  805. DWORD dwFlags,
  806. HANDLE Process,
  807. PPEB Peb,
  808. LPCWSTR ApplicationPathName,
  809. LPCWSTR CurrentDirectory,
  810. LPCWSTR CommandLine,
  811. LPVOID Environment,
  812. LPSTARTUPINFOW lpStartupInfo,
  813. DWORD dwCreationFlags,
  814. BOOL bInheritHandles,
  815. DWORD dwSubsystem,
  816. PVOID pAppCompatData,
  817. DWORD cbAppCompatData
  818. )
  819. /*++
  820. Routine Description:
  821. This function allocates a process parameters record and
  822. formats it. The parameter record is then written into the
  823. address space of the specified process.
  824. Arguments:
  825. dwFlags - bitmask of flags to affect the behavior of
  826. BasePushProcessParameters.
  827. BASE_PUSH_PROCESS_PARAMETERS_FLAG_APP_MANIFEST_PRESENT
  828. Set to indicate that an application manifest was found/used
  829. for the given executable.
  830. Process - Supplies a handle to the process that is to get the
  831. parameters.
  832. Peb - Supplies the address of the new processes PEB.
  833. ApplicationPathName - Supplies the application path name for the
  834. process.
  835. CurrentDirectory - Supplies an optional current directory for the
  836. process. If not specified, then the current directory is used.
  837. CommandLine - Supplies a command line for the new process.
  838. Environment - Supplies an optional environment variable list for the
  839. process. If not specified, then the current processes arguments
  840. are passed.
  841. lpStartupInfo - Supplies the startup information for the processes
  842. main window.
  843. dwCreationFlags - Supplies creation flags for the process
  844. bInheritHandles - TRUE if child process inherited handles from parent
  845. dwSubsystem - if non-zero, then value will be stored in child process
  846. PEB. Only non-zero for separate VDM applications, where the child
  847. process has NTVDM.EXE subsystem type, not the 16-bit application
  848. type, which is what we want.
  849. pAppCompatData - data that is needed for appcompat backend
  850. cbAppCompatData - data size in bytes
  851. Return Value:
  852. TRUE - The operation was successful.
  853. FALSE - The operation Failed.
  854. --*/
  855. {
  856. UNICODE_STRING ImagePathName;
  857. UNICODE_STRING CommandLineString;
  858. UNICODE_STRING CurrentDirString;
  859. UNICODE_STRING DllPath;
  860. UNICODE_STRING WindowTitle;
  861. UNICODE_STRING DesktopInfo;
  862. UNICODE_STRING ShellInfo;
  863. UNICODE_STRING RuntimeInfo;
  864. PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
  865. PRTL_USER_PROCESS_PARAMETERS ParametersInNewProcess;
  866. ULONG ParameterLength, EnvironmentLength;
  867. SIZE_T RegionSize;
  868. PWCHAR s;
  869. NTSTATUS Status;
  870. WCHAR FullPathBuffer[MAX_PATH+5];
  871. WCHAR *fp;
  872. DWORD Rvalue;
  873. LPWSTR DllPathData;
  874. LPVOID pAppCompatDataInNewProcess;
  875. #if defined(BUILD_WOW6432)
  876. ULONG_PTR Peb32;
  877. PVOID TempEnvironment = NULL;
  878. #endif
  879. Rvalue = GetFullPathNameW(ApplicationPathName,MAX_PATH+4,FullPathBuffer,&fp);
  880. if ( Rvalue == 0 || Rvalue > MAX_PATH+4 ) {
  881. DllPathData = BaseComputeProcessDllPath( ApplicationPathName, Environment);
  882. if ( !DllPathData ) {
  883. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  884. return FALSE;
  885. }
  886. RtlInitUnicodeString( &DllPath, DllPathData );
  887. RtlInitUnicodeString( &ImagePathName, ApplicationPathName );
  888. }
  889. else {
  890. DllPathData = BaseComputeProcessDllPath( FullPathBuffer, Environment);
  891. if ( !DllPathData ) {
  892. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  893. return FALSE;
  894. }
  895. RtlInitUnicodeString( &DllPath, DllPathData );
  896. RtlInitUnicodeString( &ImagePathName, FullPathBuffer );
  897. }
  898. RtlInitUnicodeString( &CommandLineString, CommandLine );
  899. RtlInitUnicodeString( &CurrentDirString, CurrentDirectory );
  900. if ( lpStartupInfo->lpDesktop ) {
  901. RtlInitUnicodeString( &DesktopInfo, lpStartupInfo->lpDesktop );
  902. }
  903. else {
  904. RtlInitUnicodeString( &DesktopInfo, L"");
  905. }
  906. if ( lpStartupInfo->lpReserved ) {
  907. RtlInitUnicodeString( &ShellInfo, lpStartupInfo->lpReserved );
  908. }
  909. else {
  910. RtlInitUnicodeString( &ShellInfo, L"");
  911. }
  912. RuntimeInfo.Buffer = (PWSTR)lpStartupInfo->lpReserved2;
  913. RuntimeInfo.Length = lpStartupInfo->cbReserved2;
  914. RuntimeInfo.MaximumLength = RuntimeInfo.Length;
  915. if (NULL == pAppCompatData) {
  916. cbAppCompatData = 0;
  917. }
  918. if ( lpStartupInfo->lpTitle ) {
  919. RtlInitUnicodeString( &WindowTitle, lpStartupInfo->lpTitle );
  920. }
  921. else {
  922. RtlInitUnicodeString( &WindowTitle, ApplicationPathName );
  923. }
  924. Status = RtlCreateProcessParameters( &ProcessParameters,
  925. &ImagePathName,
  926. &DllPath,
  927. (ARGUMENT_PRESENT(CurrentDirectory) ? &CurrentDirString : NULL),
  928. &CommandLineString,
  929. Environment,
  930. &WindowTitle,
  931. &DesktopInfo,
  932. &ShellInfo,
  933. &RuntimeInfo
  934. );
  935. if (!NT_SUCCESS( Status )) {
  936. BaseSetLastNTError(Status);
  937. return FALSE;
  938. }
  939. if ( !bInheritHandles ) {
  940. ProcessParameters->CurrentDirectory.Handle = NULL;
  941. }
  942. try {
  943. if (s = ProcessParameters->Environment) {
  944. while (*s) {
  945. while (*s++) {
  946. }
  947. }
  948. s++;
  949. Environment = ProcessParameters->Environment;
  950. EnvironmentLength = (ULONG)((PUCHAR)s - (PUCHAR)Environment);
  951. ProcessParameters->Environment = NULL;
  952. RegionSize = EnvironmentLength;
  953. Status = NtAllocateVirtualMemory( Process,
  954. (PVOID *)&ProcessParameters->Environment,
  955. 0,
  956. &RegionSize,
  957. MEM_COMMIT,
  958. PAGE_READWRITE
  959. );
  960. if ( !NT_SUCCESS( Status ) ) {
  961. BaseSetLastNTError(Status);
  962. return( FALSE );
  963. }
  964. #if defined(BUILD_WOW6432)
  965. //
  966. // Let's try and thunk back some environment variables if we are about to
  967. // launch a 64-bit process
  968. //
  969. Status = NtQueryInformationProcess (Process,
  970. ProcessWow64Information,
  971. &Peb32,
  972. sizeof (Peb32),
  973. NULL
  974. );
  975. if (NT_SUCCESS (Status) && (Peb32 == 0)) {
  976. RegionSize = EnvironmentLength;
  977. Status = NtAllocateVirtualMemory (NtCurrentProcess(),
  978. &TempEnvironment,
  979. 0,
  980. &RegionSize,
  981. MEM_COMMIT,
  982. PAGE_READWRITE
  983. );
  984. if (NT_SUCCESS (Status)) {
  985. try {
  986. RtlCopyMemory (TempEnvironment,
  987. Environment,
  988. EnvironmentLength
  989. );
  990. } except (EXCEPTION_EXECUTE_HANDLER) {
  991. Status = GetExceptionCode ();
  992. }
  993. if (NT_SUCCESS (Status)) {
  994. //
  995. // Thunk back special environment variables so that they won't be inherited
  996. // for 64-bit processes
  997. //
  998. Status = Wow64pThunkEnvironmentVariables (&TempEnvironment);
  999. if (NT_SUCCESS (Status)) {
  1000. Environment = TempEnvironment;
  1001. }
  1002. }
  1003. }
  1004. }
  1005. #endif
  1006. Status = NtWriteVirtualMemory( Process,
  1007. ProcessParameters->Environment,
  1008. Environment,
  1009. EnvironmentLength,
  1010. NULL
  1011. );
  1012. #if defined(BUILD_WOW6432)
  1013. if (TempEnvironment != NULL) {
  1014. RegionSize = 0;
  1015. NtFreeVirtualMemory(Process,
  1016. &TempEnvironment,
  1017. &RegionSize,
  1018. MEM_RELEASE
  1019. );
  1020. }
  1021. #endif
  1022. if ( !NT_SUCCESS( Status ) ) {
  1023. BaseSetLastNTError(Status);
  1024. return( FALSE );
  1025. }
  1026. }
  1027. //
  1028. // Push the parameters into the new process
  1029. //
  1030. ProcessParameters->StartingX = lpStartupInfo->dwX;
  1031. ProcessParameters->StartingY = lpStartupInfo->dwY;
  1032. ProcessParameters->CountX = lpStartupInfo->dwXSize;
  1033. ProcessParameters->CountY = lpStartupInfo->dwYSize;
  1034. ProcessParameters->CountCharsX = lpStartupInfo->dwXCountChars;
  1035. ProcessParameters->CountCharsY = lpStartupInfo->dwYCountChars;
  1036. ProcessParameters->FillAttribute = lpStartupInfo->dwFillAttribute;
  1037. ProcessParameters->WindowFlags = lpStartupInfo->dwFlags;
  1038. ProcessParameters->ShowWindowFlags = lpStartupInfo->wShowWindow;
  1039. if (lpStartupInfo->dwFlags & (STARTF_USESTDHANDLES | STARTF_USEHOTKEY | STARTF_HASSHELLDATA)) {
  1040. ProcessParameters->StandardInput = lpStartupInfo->hStdInput;
  1041. ProcessParameters->StandardOutput = lpStartupInfo->hStdOutput;
  1042. ProcessParameters->StandardError = lpStartupInfo->hStdError;
  1043. }
  1044. if (dwCreationFlags & DETACHED_PROCESS) {
  1045. ProcessParameters->ConsoleHandle = (HANDLE)CONSOLE_DETACHED_PROCESS;
  1046. } else if (dwCreationFlags & CREATE_NEW_CONSOLE) {
  1047. ProcessParameters->ConsoleHandle = (HANDLE)CONSOLE_NEW_CONSOLE;
  1048. } else if (dwCreationFlags & CREATE_NO_WINDOW) {
  1049. ProcessParameters->ConsoleHandle = (HANDLE)CONSOLE_CREATE_NO_WINDOW;
  1050. } else {
  1051. ProcessParameters->ConsoleHandle =
  1052. NtCurrentPeb()->ProcessParameters->ConsoleHandle;
  1053. if (!(lpStartupInfo->dwFlags & (STARTF_USESTDHANDLES | STARTF_USEHOTKEY | STARTF_HASSHELLDATA))) {
  1054. if (bInheritHandles ||
  1055. CONSOLE_HANDLE( NtCurrentPeb()->ProcessParameters->StandardInput )
  1056. ) {
  1057. ProcessParameters->StandardInput =
  1058. NtCurrentPeb()->ProcessParameters->StandardInput;
  1059. }
  1060. if (bInheritHandles ||
  1061. CONSOLE_HANDLE( NtCurrentPeb()->ProcessParameters->StandardOutput )
  1062. ) {
  1063. ProcessParameters->StandardOutput =
  1064. NtCurrentPeb()->ProcessParameters->StandardOutput;
  1065. }
  1066. if (bInheritHandles ||
  1067. CONSOLE_HANDLE( NtCurrentPeb()->ProcessParameters->StandardError )
  1068. ) {
  1069. ProcessParameters->StandardError =
  1070. NtCurrentPeb()->ProcessParameters->StandardError;
  1071. }
  1072. }
  1073. }
  1074. if (dwCreationFlags & CREATE_NEW_PROCESS_GROUP) {
  1075. ProcessParameters->ConsoleFlags = 1;
  1076. }
  1077. ProcessParameters->Flags |=
  1078. (NtCurrentPeb()->ProcessParameters->Flags & RTL_USER_PROC_DISABLE_HEAP_DECOMMIT);
  1079. ParameterLength = ProcessParameters->Length;
  1080. if (dwFlags & BASE_PUSH_PROCESS_PARAMETERS_FLAG_APP_MANIFEST_PRESENT)
  1081. ProcessParameters->Flags |= RTL_USER_PROC_APP_MANIFEST_PRESENT;
  1082. //
  1083. // Allocate memory in the new process to push the parameters
  1084. //
  1085. ParametersInNewProcess = NULL;
  1086. RegionSize = ParameterLength;
  1087. Status = NtAllocateVirtualMemory(
  1088. Process,
  1089. (PVOID *)&ParametersInNewProcess,
  1090. 0,
  1091. &RegionSize,
  1092. MEM_COMMIT,
  1093. PAGE_READWRITE
  1094. );
  1095. ParameterLength = (ULONG)RegionSize;
  1096. if ( !NT_SUCCESS( Status ) ) {
  1097. BaseSetLastNTError(Status);
  1098. return FALSE;
  1099. }
  1100. ProcessParameters->MaximumLength = ParameterLength;
  1101. if ( dwCreationFlags & PROFILE_USER ) {
  1102. ProcessParameters->Flags |= RTL_USER_PROC_PROFILE_USER;
  1103. }
  1104. if ( dwCreationFlags & PROFILE_KERNEL ) {
  1105. ProcessParameters->Flags |= RTL_USER_PROC_PROFILE_KERNEL;
  1106. }
  1107. if ( dwCreationFlags & PROFILE_SERVER ) {
  1108. ProcessParameters->Flags |= RTL_USER_PROC_PROFILE_SERVER;
  1109. }
  1110. //
  1111. // Push the parameters
  1112. //
  1113. Status = NtWriteVirtualMemory(
  1114. Process,
  1115. ParametersInNewProcess,
  1116. ProcessParameters,
  1117. ProcessParameters->Length,
  1118. NULL
  1119. );
  1120. if ( !NT_SUCCESS( Status ) ) {
  1121. BaseSetLastNTError(Status);
  1122. return FALSE;
  1123. }
  1124. //
  1125. // Make the processes PEB point to the parameters.
  1126. //
  1127. Status = NtWriteVirtualMemory(
  1128. Process,
  1129. &Peb->ProcessParameters,
  1130. &ParametersInNewProcess,
  1131. sizeof( ParametersInNewProcess ),
  1132. NULL
  1133. );
  1134. if ( !NT_SUCCESS( Status ) ) {
  1135. BaseSetLastNTError(Status);
  1136. return FALSE;
  1137. }
  1138. //
  1139. // allocate and write appcompat data for the new process
  1140. //
  1141. pAppCompatDataInNewProcess = NULL;
  1142. if ( NULL != pAppCompatData ) {
  1143. RegionSize = cbAppCompatData;
  1144. Status = NtAllocateVirtualMemory(
  1145. Process,
  1146. (PVOID*)&pAppCompatDataInNewProcess,
  1147. 0,
  1148. &RegionSize,
  1149. MEM_COMMIT,
  1150. PAGE_READWRITE
  1151. );
  1152. if ( !NT_SUCCESS( Status ) ) {
  1153. BaseSetLastNTError(Status);
  1154. return FALSE;
  1155. }
  1156. //
  1157. // write the data itself
  1158. //
  1159. Status = NtWriteVirtualMemory(
  1160. Process,
  1161. pAppCompatDataInNewProcess,
  1162. pAppCompatData,
  1163. cbAppCompatData,
  1164. NULL
  1165. );
  1166. if ( !NT_SUCCESS( Status ) ) {
  1167. BaseSetLastNTError(Status);
  1168. return FALSE;
  1169. }
  1170. }
  1171. //
  1172. // save the pointer to appcompat data in peb
  1173. //
  1174. Status = NtWriteVirtualMemory(
  1175. Process,
  1176. &Peb->pShimData,
  1177. &pAppCompatDataInNewProcess,
  1178. sizeof( pAppCompatDataInNewProcess ),
  1179. NULL
  1180. );
  1181. if ( !NT_SUCCESS( Status ) ) {
  1182. BaseSetLastNTError(Status);
  1183. return FALSE;
  1184. }
  1185. //
  1186. // Set subsystem type in PEB if requested by caller. Ignore error
  1187. //
  1188. if (dwSubsystem != 0) {
  1189. NtWriteVirtualMemory(
  1190. Process,
  1191. &Peb->ImageSubsystem,
  1192. &dwSubsystem,
  1193. sizeof( Peb->ImageSubsystem ),
  1194. NULL
  1195. );
  1196. }
  1197. }
  1198. finally {
  1199. RtlFreeHeap(RtlProcessHeap(), 0,DllPath.Buffer);
  1200. if ( ProcessParameters ) {
  1201. RtlDestroyProcessParameters(ProcessParameters);
  1202. }
  1203. }
  1204. return TRUE;
  1205. }
  1206. LPCWSTR
  1207. BasepEndOfDirName(
  1208. IN LPCWSTR FileName
  1209. )
  1210. {
  1211. LPCWSTR FileNameEnd,
  1212. FileNameFirstWhack = wcschr(FileName, L'\\');
  1213. if (FileNameFirstWhack) {
  1214. FileNameEnd = wcsrchr(FileNameFirstWhack, L'\\');
  1215. ASSERT(FileNameEnd);
  1216. if (FileNameEnd == FileNameFirstWhack)
  1217. FileNameEnd++;
  1218. } else {
  1219. FileNameEnd = NULL;
  1220. }
  1221. return FileNameEnd;
  1222. }
  1223. VOID
  1224. BasepLocateExeLdrEntry(
  1225. IN PCLDR_DATA_TABLE_ENTRY Entry,
  1226. IN PVOID Context,
  1227. IN OUT BOOLEAN *StopEnumeration
  1228. )
  1229. /*++
  1230. Routine Description:
  1231. This function is a LDR_LOADED_MODULE_ENUMBERATION_CALLBACK_FUNCTION
  1232. which locates the exe's loader data table entry.
  1233. Arguments:
  1234. Entry - the entry currently being enumerated.
  1235. Context - the image base address (NtCurrentPeb()->ImageBaseAddress).
  1236. StopEnumeration - used to stop the enumeration.
  1237. Return Value:
  1238. None. The exe's loader data table entry, if found, is stored in
  1239. the global BasepExeLdrEntry.
  1240. --*/
  1241. {
  1242. ASSERT(Entry);
  1243. ASSERT(Context);
  1244. ASSERT(StopEnumeration);
  1245. if (BasepExeLdrEntry) {
  1246. *StopEnumeration = TRUE;
  1247. } else if (Entry->DllBase == Context) {
  1248. BasepExeLdrEntry = Entry;
  1249. *StopEnumeration = TRUE;
  1250. }
  1251. }
  1252. LPWSTR
  1253. BasepComputeProcessPath(
  1254. IN const BASEP_SEARCH_PATH_ELEMENT *Elements,
  1255. IN LPCWSTR AppName,
  1256. IN LPVOID Environment
  1257. )
  1258. /*++
  1259. Routine Description:
  1260. This function computes a process path.
  1261. Arguments:
  1262. Elements - The elements to build into a path.
  1263. AppName - An optional argument that specifies the name of
  1264. the application. If this parameter is not specified,
  1265. then the current application is used.
  1266. Environment - Supplies the environment block to be used to calculate
  1267. the path variable value.
  1268. Return Value:
  1269. The return value is the value of the requested path.
  1270. --*/
  1271. {
  1272. LPCWSTR AppNameEnd;
  1273. const BASEP_SEARCH_PATH_ELEMENT *Element;
  1274. UNICODE_STRING EnvPath;
  1275. LPWSTR EnvPathBuffer = NULL;
  1276. LPWSTR PathBuffer = NULL,
  1277. PathCurrent;
  1278. ULONG PathLengthInBytes;
  1279. NTSTATUS Status = STATUS_SUCCESS;
  1280. __try {
  1281. // First, figure out how much space we'll need.
  1282. PathLengthInBytes = 0;
  1283. for (Element = Elements;
  1284. *Element != BasepSearchPathEnd;
  1285. Element++) {
  1286. switch (*Element) {
  1287. case BasepSearchPathCurdir:
  1288. PathLengthInBytes += 2 * sizeof(UNICODE_NULL); // .;
  1289. break;
  1290. case BasepSearchPathDlldir:
  1291. ASSERT(BaseDllDirectory.Buffer != NULL);
  1292. PathLengthInBytes += BaseDllDirectory.Length;
  1293. if (BaseDllDirectory.Length) {
  1294. PathLengthInBytes += sizeof(UNICODE_NULL);
  1295. }
  1296. break;
  1297. case BasepSearchPathAppdir:
  1298. if (AppName) {
  1299. // Try to use the passed-in appname
  1300. AppNameEnd = BasepEndOfDirName(AppName);
  1301. }
  1302. if (!AppName || !AppNameEnd) {
  1303. // We didn't have or were unable to use the passed-in
  1304. // appname -- so attempt to use the current exe's name
  1305. if (RtlGetPerThreadCurdir()
  1306. && RtlGetPerThreadCurdir()->ImageName) {
  1307. AppName = RtlGetPerThreadCurdir()->ImageName->Buffer;
  1308. } else {
  1309. BasepCheckExeLdrEntry();
  1310. if (BasepExeLdrEntry) {
  1311. AppName = BasepExeLdrEntry->FullDllName.Buffer;
  1312. }
  1313. }
  1314. if (AppName) {
  1315. AppNameEnd = BasepEndOfDirName(AppName);
  1316. }
  1317. }
  1318. if (AppName && AppNameEnd) {
  1319. // Either we had a passed-in appname which worked, or
  1320. // we found the current exe's name and that worked.
  1321. //
  1322. // AppNameEnd points to the end of the base of the exe
  1323. // name -- so the difference is the number of
  1324. // characters in the base name, and we add one for the
  1325. // trailing semicolon / NULL.
  1326. PathLengthInBytes += ((AppNameEnd - AppName + 1)
  1327. * sizeof(UNICODE_NULL));
  1328. }
  1329. break;
  1330. case BasepSearchPathDefaultDirs:
  1331. ASSERT(! (BaseDefaultPath.Length & 1));
  1332. // We don't need an extra UNICODE_NULL here -- baseinit.c
  1333. // appends our trailing semicolon for us.
  1334. PathLengthInBytes += BaseDefaultPath.Length;
  1335. break;
  1336. case BasepSearchPathEnvPath:
  1337. if (! Environment) {
  1338. RtlAcquirePebLock();
  1339. }
  1340. __try {
  1341. EnvPath.MaximumLength = 0;
  1342. Status = RtlQueryEnvironmentVariable_U(Environment,
  1343. &BasePathVariableName,
  1344. &EnvPath);
  1345. if (Status == STATUS_BUFFER_TOO_SMALL) {
  1346. // Now that we know how much to allocate, attempt
  1347. // to alloc a buffer that's actually big enough.
  1348. EnvPath.MaximumLength = EnvPath.Length + sizeof(UNICODE_NULL);
  1349. EnvPathBuffer = RtlAllocateHeap(RtlProcessHeap(),
  1350. MAKE_TAG(TMP_TAG),
  1351. EnvPath.MaximumLength);
  1352. if (! EnvPathBuffer) {
  1353. Status = STATUS_NO_MEMORY;
  1354. __leave;
  1355. }
  1356. EnvPath.Buffer = EnvPathBuffer;
  1357. Status = RtlQueryEnvironmentVariable_U(Environment,
  1358. &BasePathVariableName,
  1359. &EnvPath);
  1360. }
  1361. } __finally {
  1362. if (! Environment) {
  1363. RtlReleasePebLock();
  1364. }
  1365. }
  1366. if (Status == STATUS_VARIABLE_NOT_FOUND) {
  1367. EnvPath.Length = 0;
  1368. Status = STATUS_SUCCESS;
  1369. } else if (! NT_SUCCESS(Status)) {
  1370. __leave;
  1371. } else {
  1372. // The final tally is the length, in bytes, of whatever
  1373. // we're using for our path, plus a character for the
  1374. // trailing whack or NULL.
  1375. ASSERT(! (EnvPath.Length & 1));
  1376. PathLengthInBytes += EnvPath.Length + sizeof(UNICODE_NULL);
  1377. }
  1378. break;
  1379. DEFAULT_UNREACHABLE;
  1380. } // switch (*Element)
  1381. } // foreach Element (Elements) -- size loop
  1382. ASSERT(PathLengthInBytes > 0);
  1383. ASSERT(! (PathLengthInBytes & 1));
  1384. // Now we have the length, in bytes, of the buffer we'll need for
  1385. // our path. Time to allocate it...
  1386. PathBuffer = RtlAllocateHeap(RtlProcessHeap(),
  1387. MAKE_TAG(TMP_TAG),
  1388. PathLengthInBytes);
  1389. if (! PathBuffer) {
  1390. Status = STATUS_NO_MEMORY;
  1391. __leave;
  1392. }
  1393. // Now go through the loop again, this time appending onto the
  1394. // PathBuffer.
  1395. PathCurrent = PathBuffer;
  1396. for (Element = Elements;
  1397. *Element != BasepSearchPathEnd;
  1398. Element++) {
  1399. switch (*Element) {
  1400. case BasepSearchPathCurdir:
  1401. ASSERT(((PathCurrent - PathBuffer + 2)
  1402. * sizeof(UNICODE_NULL))
  1403. <= PathLengthInBytes);
  1404. *PathCurrent++ = L'.';
  1405. *PathCurrent++ = L';';
  1406. break;
  1407. case BasepSearchPathDlldir:
  1408. if (BaseDllDirectory.Length) {
  1409. ASSERT((((PathCurrent - PathBuffer + 1)
  1410. * sizeof(UNICODE_NULL))
  1411. + BaseDllDirectory.Length)
  1412. <= PathLengthInBytes);
  1413. RtlCopyMemory(PathCurrent,
  1414. BaseDllDirectory.Buffer,
  1415. BaseDllDirectory.Length);
  1416. PathCurrent += (BaseDllDirectory.Length >> 1);
  1417. *PathCurrent++ = L';';
  1418. }
  1419. break;
  1420. case BasepSearchPathAppdir:
  1421. if (AppName && AppNameEnd) {
  1422. ASSERT(((PathCurrent - PathBuffer + 1
  1423. + (AppNameEnd - AppName))
  1424. * sizeof(UNICODE_NULL))
  1425. <= PathLengthInBytes);
  1426. RtlCopyMemory(PathCurrent,
  1427. AppName,
  1428. ((AppNameEnd - AppName)
  1429. * sizeof(UNICODE_NULL)));
  1430. PathCurrent += AppNameEnd - AppName;
  1431. *PathCurrent++ = L';';
  1432. }
  1433. break;
  1434. case BasepSearchPathDefaultDirs:
  1435. ASSERT((((PathCurrent - PathBuffer)
  1436. * sizeof(UNICODE_NULL))
  1437. + BaseDefaultPath.Length)
  1438. <= PathLengthInBytes);
  1439. RtlCopyMemory(PathCurrent,
  1440. BaseDefaultPath.Buffer,
  1441. BaseDefaultPath.Length);
  1442. PathCurrent += (BaseDefaultPath.Length >> 1);
  1443. // We don't need to add a semicolon here -- baseinit.c
  1444. // appends our trailing semicolon for us.
  1445. break;
  1446. case BasepSearchPathEnvPath:
  1447. if (EnvPath.Length) {
  1448. ASSERT((((PathCurrent - PathBuffer + 1)
  1449. * sizeof(UNICODE_NULL))
  1450. + EnvPath.Length)
  1451. <= PathLengthInBytes);
  1452. RtlCopyMemory(PathCurrent,
  1453. EnvPath.Buffer,
  1454. EnvPath.Length);
  1455. PathCurrent += (EnvPath.Length >> 1);
  1456. *PathCurrent++ = L';';
  1457. }
  1458. break;
  1459. DEFAULT_UNREACHABLE;
  1460. } // switch (*Element)
  1461. } // foreach Element (Elements) -- append loop
  1462. // At this point, PathCurrent points just beyond PathBuffer.
  1463. // Let's assert that...
  1464. ASSERT((PathCurrent - PathBuffer) * sizeof(UNICODE_NULL)
  1465. == PathLengthInBytes);
  1466. // ... and turn the final ';' into the string terminator.
  1467. ASSERT(PathCurrent > PathBuffer);
  1468. PathCurrent[-1] = UNICODE_NULL;
  1469. } __finally {
  1470. if (EnvPathBuffer) {
  1471. RtlFreeHeap(RtlProcessHeap(),
  1472. 0,
  1473. EnvPathBuffer);
  1474. }
  1475. if (PathBuffer
  1476. && (AbnormalTermination()
  1477. || ! NT_SUCCESS(Status))) {
  1478. RtlFreeHeap(RtlProcessHeap(),
  1479. 0,
  1480. PathBuffer);
  1481. PathBuffer = NULL;
  1482. }
  1483. }
  1484. return PathBuffer;
  1485. }
  1486. LPWSTR
  1487. BaseComputeProcessDllPath(
  1488. IN LPCWSTR AppName,
  1489. IN LPVOID Environment
  1490. )
  1491. /*++
  1492. Routine Description:
  1493. This function computes a process DLL path.
  1494. Arguments:
  1495. AppName - An optional argument that specifies the name of
  1496. the application. If this parameter is not specified, then the
  1497. current application is used.
  1498. Environment - Supplies the environment block to be used to calculate
  1499. the path variable value.
  1500. Return Value:
  1501. The return value is the value of the processes DLL path.
  1502. --*/
  1503. {
  1504. NTSTATUS Status;
  1505. HANDLE Key;
  1506. static UNICODE_STRING
  1507. KeyName = RTL_CONSTANT_STRING(L"\\Registry\\MACHINE\\System\\CurrentControlSet\\Control\\Session Manager"),
  1508. ValueName = RTL_CONSTANT_STRING(L"SafeDllSearchMode");
  1509. static OBJECT_ATTRIBUTES
  1510. ObjA = RTL_CONSTANT_OBJECT_ATTRIBUTES(&KeyName, OBJ_CASE_INSENSITIVE);
  1511. CHAR Buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data)
  1512. + sizeof(DWORD)];
  1513. PKEY_VALUE_PARTIAL_INFORMATION Info;
  1514. ULONG ResultLength;
  1515. LONG CurrentDirPlacement,
  1516. PrevCurrentDirPlacement;
  1517. LPWSTR Result;
  1518. static const BASEP_SEARCH_PATH_ELEMENT DllDirSearchPath[] = {
  1519. BasepSearchPathAppdir,
  1520. BasepSearchPathDlldir,
  1521. BasepSearchPathDefaultDirs,
  1522. BasepSearchPathEnvPath,
  1523. BasepSearchPathEnd
  1524. };
  1525. RtlEnterCriticalSection(&BaseDllDirectoryLock);
  1526. if (BaseDllDirectory.Buffer) {
  1527. Result = BasepComputeProcessPath(DllDirSearchPath,
  1528. AppName,
  1529. Environment);
  1530. RtlLeaveCriticalSection(&BaseDllDirectoryLock);
  1531. return Result;
  1532. }
  1533. RtlLeaveCriticalSection(&BaseDllDirectoryLock);
  1534. CurrentDirPlacement = BasepDllCurrentDirPlacement;
  1535. if (CurrentDirPlacement == BasepCurrentDirUninitialized) {
  1536. Status = NtOpenKey(&Key,
  1537. KEY_QUERY_VALUE,
  1538. &ObjA);
  1539. if (! NT_SUCCESS(Status)) {
  1540. goto compute_path;
  1541. }
  1542. Info = (PKEY_VALUE_PARTIAL_INFORMATION) Buffer;
  1543. Status = NtQueryValueKey(Key,
  1544. &ValueName,
  1545. KeyValuePartialInformation,
  1546. Info,
  1547. sizeof(Buffer),
  1548. &ResultLength);
  1549. if (! NT_SUCCESS(Status)) {
  1550. goto close_key;
  1551. }
  1552. if (ResultLength != sizeof(Buffer)) {
  1553. goto close_key;
  1554. }
  1555. RtlCopyMemory(&CurrentDirPlacement,
  1556. Info->Data,
  1557. sizeof(DWORD));
  1558. close_key:
  1559. NtClose(Key);
  1560. compute_path:
  1561. if (! BASEP_VALID_CURDIR_PLACEMENT_P(CurrentDirPlacement)) {
  1562. CurrentDirPlacement = BASEP_DEFAULT_DLL_CURDIR_PLACEMENT;
  1563. }
  1564. PrevCurrentDirPlacement = InterlockedCompareExchange(&BasepDllCurrentDirPlacement,
  1565. CurrentDirPlacement,
  1566. BasepCurrentDirUninitialized);
  1567. if (PrevCurrentDirPlacement != BasepCurrentDirUninitialized) {
  1568. CurrentDirPlacement = PrevCurrentDirPlacement;
  1569. }
  1570. }
  1571. if (! BASEP_VALID_CURDIR_PLACEMENT_P(CurrentDirPlacement)) {
  1572. CurrentDirPlacement = BASEP_DEFAULT_DLL_CURDIR_PLACEMENT;
  1573. }
  1574. return BasepComputeProcessPath(BasepDllSearchPaths[CurrentDirPlacement],
  1575. AppName,
  1576. Environment);
  1577. }
  1578. LPWSTR
  1579. BaseComputeProcessSearchPath(
  1580. VOID
  1581. )
  1582. /*++
  1583. Routine Description:
  1584. This function computes a process search path.
  1585. Arguments:
  1586. None
  1587. Return Value:
  1588. The return value is the value of the processes search path.
  1589. --*/
  1590. {
  1591. static const BASEP_SEARCH_PATH_ELEMENT SearchPath[] = {
  1592. BasepSearchPathAppdir,
  1593. BasepSearchPathCurdir,
  1594. BasepSearchPathDefaultDirs,
  1595. BasepSearchPathEnvPath,
  1596. BasepSearchPathEnd
  1597. };
  1598. return BasepComputeProcessPath(SearchPath,
  1599. NULL,
  1600. NULL);
  1601. }
  1602. PUNICODE_STRING
  1603. Basep8BitStringToStaticUnicodeString(
  1604. IN LPCSTR lpSourceString
  1605. )
  1606. /*++
  1607. Routine Description:
  1608. Captures and converts a 8-bit (OEM or ANSI) string into the Teb Static
  1609. Unicode String
  1610. Arguments:
  1611. lpSourceString - string in OEM or ANSI
  1612. Return Value:
  1613. Pointer to the Teb static string if conversion was successful, NULL
  1614. otherwise. If a failure occurred, the last error is set.
  1615. --*/
  1616. {
  1617. PUNICODE_STRING StaticUnicode;
  1618. ANSI_STRING AnsiString;
  1619. NTSTATUS Status;
  1620. //
  1621. // Get pointer to static per-thread string
  1622. //
  1623. StaticUnicode = &NtCurrentTeb()->StaticUnicodeString;
  1624. //
  1625. // Convert input string into unicode string
  1626. //
  1627. RtlInitAnsiString( &AnsiString, lpSourceString );
  1628. Status = Basep8BitStringToUnicodeString( StaticUnicode, &AnsiString, FALSE );
  1629. //
  1630. // If we couldn't convert the string
  1631. //
  1632. if ( !NT_SUCCESS( Status ) ) {
  1633. if ( Status == STATUS_BUFFER_OVERFLOW ) {
  1634. SetLastError( ERROR_FILENAME_EXCED_RANGE );
  1635. } else {
  1636. BaseSetLastNTError( Status );
  1637. }
  1638. return NULL;
  1639. } else {
  1640. return StaticUnicode;
  1641. }
  1642. }
  1643. BOOL
  1644. Basep8BitStringToDynamicUnicodeString(
  1645. OUT PUNICODE_STRING UnicodeString,
  1646. IN LPCSTR lpSourceString
  1647. )
  1648. /*++
  1649. Routine Description:
  1650. Captures and converts a 8-bit (OEM or ANSI) string into a heap-allocated
  1651. UNICODE string
  1652. Arguments:
  1653. UnicodeString - location where UNICODE_STRING is stored
  1654. lpSourceString - string in OEM or ANSI
  1655. Return Value:
  1656. TRUE if string is correctly stored, FALSE if an error occurred. In the
  1657. error case, the last error is correctly set.
  1658. --*/
  1659. {
  1660. ANSI_STRING AnsiString;
  1661. NTSTATUS Status;
  1662. //
  1663. // Convert input into dynamic unicode string
  1664. //
  1665. RtlInitString( &AnsiString, lpSourceString );
  1666. Status = Basep8BitStringToUnicodeString( UnicodeString, &AnsiString, TRUE );
  1667. //
  1668. // If we couldn't do this, fail
  1669. //
  1670. if (!NT_SUCCESS( Status )){
  1671. if ( Status == STATUS_BUFFER_OVERFLOW ) {
  1672. SetLastError( ERROR_FILENAME_EXCED_RANGE );
  1673. } else {
  1674. BaseSetLastNTError( Status );
  1675. }
  1676. return FALSE;
  1677. }
  1678. return TRUE;
  1679. }
  1680. //
  1681. // Thunks for converting between ANSI/OEM and UNICODE
  1682. //
  1683. ULONG
  1684. BasepAnsiStringToUnicodeSize(
  1685. PANSI_STRING AnsiString
  1686. )
  1687. /*++
  1688. Routine Description:
  1689. Determines the size of a UNICODE version of an ANSI string
  1690. Arguments:
  1691. AnsiString - string to examine
  1692. Return Value:
  1693. Byte size of UNICODE version of string including a trailing L'\0'.
  1694. --*/
  1695. {
  1696. return RtlAnsiStringToUnicodeSize( AnsiString );
  1697. }
  1698. ULONG
  1699. BasepOemStringToUnicodeSize(
  1700. PANSI_STRING OemString
  1701. )
  1702. /*++
  1703. Routine Description:
  1704. Determines the size of a UNICODE version of an OEM string
  1705. Arguments:
  1706. OemString - string to examine
  1707. Return Value:
  1708. Byte size of UNICODE version of string including a trailing L'\0'.
  1709. --*/
  1710. {
  1711. return RtlOemStringToUnicodeSize( OemString );
  1712. }
  1713. ULONG
  1714. BasepUnicodeStringToOemSize(
  1715. PUNICODE_STRING UnicodeString
  1716. )
  1717. /*++
  1718. Routine Description:
  1719. Determines the size of an OEM version of a UNICODE string
  1720. Arguments:
  1721. UnicodeString - string to examine
  1722. Return Value:
  1723. Byte size of OEM version of string including a trailing '\0'.
  1724. --*/
  1725. {
  1726. return RtlUnicodeStringToOemSize( UnicodeString );
  1727. }
  1728. ULONG
  1729. BasepUnicodeStringToAnsiSize(
  1730. PUNICODE_STRING UnicodeString
  1731. )
  1732. /*++
  1733. Routine Description:
  1734. Determines the size of an ANSI version of a UNICODE string
  1735. Arguments:
  1736. UnicodeString - string to examine
  1737. Return Value:
  1738. Byte size of ANSI version of string including a trailing '\0'.
  1739. --*/
  1740. {
  1741. return RtlUnicodeStringToAnsiSize( UnicodeString );
  1742. }
  1743. typedef struct _BASEP_ACQUIRE_STATE {
  1744. HANDLE Token;
  1745. PTOKEN_PRIVILEGES OldPrivileges;
  1746. PTOKEN_PRIVILEGES NewPrivileges;
  1747. ULONG Revert;
  1748. ULONG Spare;
  1749. BYTE OldPrivBuffer[ 1024 ];
  1750. } BASEP_ACQUIRE_STATE, *PBASEP_ACQUIRE_STATE;
  1751. //
  1752. // This function does the correct thing - it checks for the thread token
  1753. // before opening the process token.
  1754. //
  1755. NTSTATUS
  1756. BasepAcquirePrivilegeEx(
  1757. ULONG Privilege,
  1758. PVOID *ReturnedState
  1759. )
  1760. {
  1761. PBASEP_ACQUIRE_STATE State;
  1762. ULONG cbNeeded;
  1763. LUID LuidPrivilege;
  1764. NTSTATUS Status, Status1;
  1765. BOOL St;
  1766. //
  1767. // Make sure we have access to adjust and to get the old token privileges
  1768. //
  1769. *ReturnedState = NULL;
  1770. State = RtlAllocateHeap (RtlProcessHeap(),
  1771. MAKE_TAG( TMP_TAG ),
  1772. sizeof(BASEP_ACQUIRE_STATE) +
  1773. sizeof(TOKEN_PRIVILEGES) +
  1774. (1 - ANYSIZE_ARRAY) * sizeof(LUID_AND_ATTRIBUTES));
  1775. if (State == NULL) {
  1776. return STATUS_NO_MEMORY;
  1777. }
  1778. State->Revert = 0;
  1779. //
  1780. // Try opening the thread token first, in case we're impersonating.
  1781. //
  1782. Status = NtOpenThreadToken (NtCurrentThread(),
  1783. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  1784. FALSE,
  1785. &State->Token);
  1786. if ( !NT_SUCCESS( Status )) {
  1787. Status = RtlImpersonateSelf (SecurityDelegation);
  1788. if (!NT_SUCCESS (Status)) {
  1789. RtlFreeHeap (RtlProcessHeap(), 0, State);
  1790. return Status;
  1791. }
  1792. Status = NtOpenThreadToken (NtCurrentThread(),
  1793. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  1794. FALSE,
  1795. &State->Token);
  1796. if (!NT_SUCCESS (Status)) {
  1797. State->Token = NULL;
  1798. Status1 = NtSetInformationThread (NtCurrentThread(),
  1799. ThreadImpersonationToken,
  1800. &State->Token,
  1801. sizeof (State->Token));
  1802. ASSERT (NT_SUCCESS (Status1));
  1803. RtlFreeHeap( RtlProcessHeap(), 0, State );
  1804. return Status;
  1805. }
  1806. State->Revert = 1;
  1807. }
  1808. State->NewPrivileges = (PTOKEN_PRIVILEGES)(State+1);
  1809. State->OldPrivileges = (PTOKEN_PRIVILEGES)(State->OldPrivBuffer);
  1810. //
  1811. // Initialize the privilege adjustment structure
  1812. //
  1813. LuidPrivilege = RtlConvertUlongToLuid(Privilege);
  1814. State->NewPrivileges->PrivilegeCount = 1;
  1815. State->NewPrivileges->Privileges[0].Luid = LuidPrivilege;
  1816. State->NewPrivileges->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  1817. //
  1818. // Enable the privilege
  1819. //
  1820. cbNeeded = sizeof( State->OldPrivBuffer );
  1821. Status = NtAdjustPrivilegesToken (State->Token,
  1822. FALSE,
  1823. State->NewPrivileges,
  1824. cbNeeded,
  1825. State->OldPrivileges,
  1826. &cbNeeded);
  1827. if (Status == STATUS_BUFFER_TOO_SMALL) {
  1828. State->OldPrivileges = RtlAllocateHeap (RtlProcessHeap(), MAKE_TAG( TMP_TAG ), cbNeeded);
  1829. if (State->OldPrivileges == NULL) {
  1830. Status = STATUS_NO_MEMORY;
  1831. } else {
  1832. Status = NtAdjustPrivilegesToken (State->Token,
  1833. FALSE,
  1834. State->NewPrivileges,
  1835. cbNeeded,
  1836. State->OldPrivileges,
  1837. &cbNeeded);
  1838. }
  1839. }
  1840. //
  1841. // STATUS_NOT_ALL_ASSIGNED means that the privilege isn't
  1842. // in the token, so we can't proceed.
  1843. //
  1844. // This is a warning level status, so map it to an error status.
  1845. //
  1846. if (Status == STATUS_NOT_ALL_ASSIGNED) {
  1847. Status = STATUS_PRIVILEGE_NOT_HELD;
  1848. }
  1849. if (!NT_SUCCESS( Status )) {
  1850. if (State->OldPrivileges != (PTOKEN_PRIVILEGES)State->OldPrivBuffer) {
  1851. RtlFreeHeap( RtlProcessHeap(), 0, State->OldPrivileges );
  1852. }
  1853. St = CloseHandle (State->Token);
  1854. ASSERT (St);
  1855. State->Token = NULL;
  1856. if (State->Revert) {
  1857. Status1 = NtSetInformationThread (NtCurrentThread(),
  1858. ThreadImpersonationToken,
  1859. &State->Token,
  1860. sizeof (State->Token));
  1861. ASSERT (NT_SUCCESS (Status1));
  1862. }
  1863. RtlFreeHeap( RtlProcessHeap(), 0, State );
  1864. return Status;
  1865. }
  1866. *ReturnedState = State;
  1867. return STATUS_SUCCESS;
  1868. }
  1869. VOID
  1870. BasepReleasePrivilege(
  1871. PVOID StatePointer
  1872. )
  1873. {
  1874. BOOL St;
  1875. NTSTATUS Status;
  1876. PBASEP_ACQUIRE_STATE State = (PBASEP_ACQUIRE_STATE)StatePointer;
  1877. if (!State->Revert) {
  1878. NtAdjustPrivilegesToken (State->Token,
  1879. FALSE,
  1880. State->OldPrivileges,
  1881. 0,
  1882. NULL,
  1883. NULL);
  1884. }
  1885. if (State->OldPrivileges != (PTOKEN_PRIVILEGES)State->OldPrivBuffer) {
  1886. RtlFreeHeap( RtlProcessHeap(), 0, State->OldPrivileges );
  1887. }
  1888. St = CloseHandle( State->Token );
  1889. ASSERT (St);
  1890. State->Token = NULL;
  1891. if (State->Revert) {
  1892. Status = NtSetInformationThread (NtCurrentThread(),
  1893. ThreadImpersonationToken,
  1894. &State->Token,
  1895. sizeof (State->Token));
  1896. ASSERT (NT_SUCCESS (Status));
  1897. }
  1898. RtlFreeHeap( RtlProcessHeap(), 0, State );
  1899. return;
  1900. }