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.

923 lines
25 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. tokenopn.c
  5. Abstract:
  6. This module implements the open thread and process token services.
  7. Author:
  8. Jim Kelly (JimK) 2-Aug-1990
  9. Environment:
  10. Kernel mode only.
  11. Revision History:
  12. --*/
  13. //#ifndef TOKEN_DEBUG
  14. //#define TOKEN_DEBUG
  15. //#endif
  16. #include "pch.h"
  17. #pragma hdrstop
  18. NTSTATUS
  19. SepCreateImpersonationTokenDacl(
  20. IN PTOKEN Token,
  21. IN PACCESS_TOKEN PrimaryToken,
  22. OUT PACL *Acl
  23. );
  24. #ifdef ALLOC_PRAGMA
  25. NTSTATUS
  26. SepOpenTokenOfThread(
  27. IN HANDLE ThreadHandle,
  28. IN BOOLEAN OpenAsSelf,
  29. OUT PACCESS_TOKEN *Token,
  30. OUT PETHREAD *Thread,
  31. OUT PBOOLEAN CopyOnOpen,
  32. OUT PBOOLEAN EffectiveOnly,
  33. OUT PSECURITY_IMPERSONATION_LEVEL ImpersonationLevel
  34. );
  35. #pragma alloc_text(PAGE,SepCreateImpersonationTokenDacl)
  36. #pragma alloc_text(PAGE,NtOpenProcessToken)
  37. #pragma alloc_text(PAGE,NtOpenProcessTokenEx)
  38. #pragma alloc_text(PAGE,SepOpenTokenOfThread)
  39. #pragma alloc_text(PAGE,NtOpenThreadToken)
  40. #pragma alloc_text(PAGE,NtOpenThreadTokenEx)
  41. #endif
  42. NTSTATUS
  43. SepCreateImpersonationTokenDacl(
  44. IN PTOKEN Token,
  45. IN PACCESS_TOKEN PrimaryToken,
  46. OUT PACL *Acl
  47. )
  48. /*++
  49. Routine Description:
  50. This routine modifies the DACL protecting the passed token to allow
  51. the current user (described by the PrimaryToken parameter) full access.
  52. This permits callers of NtOpenThreadToken to call with OpenAsSelf==TRUE
  53. and succeed.
  54. The new DACL placed on the token is as follows:
  55. ACE 0 - Server gets TOKEN_ALL_ACCESS
  56. ACE 1 - Client gets TOKEN_ALL_ACCESS
  57. ACE 2 - Admins gets TOKEN_ALL_ACCESS
  58. ACE 3 - System gets TOKEN_ALL_ACCESS
  59. ACE 4 - Restricted gets TOKEN_ALL_ACCESS
  60. Arguments:
  61. Token - The token whose protection is to be modified.
  62. PrimaryToken - Token representing the subject to be granted access.
  63. Acl - Returns the modified ACL, allocated out of PagedPool.
  64. Return Value:
  65. --*/
  66. {
  67. PSID ServerUserSid;
  68. PSID ClientUserSid;
  69. NTSTATUS Status = STATUS_SUCCESS;
  70. ULONG AclLength;
  71. PACL NewDacl;
  72. PSECURITY_DESCRIPTOR OldDescriptor;
  73. BOOLEAN MemoryAllocated;
  74. PACL OldDacl;
  75. BOOLEAN DaclPresent;
  76. BOOLEAN DaclDefaulted;
  77. PAGED_CODE();
  78. ServerUserSid = ((PTOKEN)PrimaryToken)->UserAndGroups[0].Sid;
  79. ClientUserSid = Token->UserAndGroups[0].Sid;
  80. //
  81. // Compute how much space we'll need for the new DACL.
  82. //
  83. AclLength = 5 * sizeof( ACCESS_ALLOWED_ACE ) - 5 * sizeof( ULONG ) +
  84. SeLengthSid( ServerUserSid ) + SeLengthSid( SeLocalSystemSid ) +
  85. SeLengthSid( ClientUserSid ) + SeLengthSid( SeAliasAdminsSid ) +
  86. SeLengthSid( SeRestrictedSid ) + sizeof( ACL );
  87. NewDacl = ExAllocatePool( PagedPool, AclLength );
  88. if (NewDacl == NULL) {
  89. *Acl = NULL;
  90. return STATUS_INSUFFICIENT_RESOURCES;
  91. }
  92. Status = RtlCreateAcl( NewDacl, AclLength, ACL_REVISION2 );
  93. ASSERT(NT_SUCCESS( Status ));
  94. Status = RtlAddAccessAllowedAce (
  95. NewDacl,
  96. ACL_REVISION2,
  97. TOKEN_ALL_ACCESS,
  98. ServerUserSid
  99. );
  100. ASSERT( NT_SUCCESS( Status ));
  101. Status = RtlAddAccessAllowedAce (
  102. NewDacl,
  103. ACL_REVISION2,
  104. TOKEN_ALL_ACCESS,
  105. ClientUserSid
  106. );
  107. ASSERT( NT_SUCCESS( Status ));
  108. Status = RtlAddAccessAllowedAce (
  109. NewDacl,
  110. ACL_REVISION2,
  111. TOKEN_ALL_ACCESS,
  112. SeAliasAdminsSid
  113. );
  114. ASSERT( NT_SUCCESS( Status ));
  115. Status = RtlAddAccessAllowedAce (
  116. NewDacl,
  117. ACL_REVISION2,
  118. TOKEN_ALL_ACCESS,
  119. SeLocalSystemSid
  120. );
  121. ASSERT( NT_SUCCESS( Status ));
  122. if(ARGUMENT_PRESENT(((PTOKEN)PrimaryToken)->RestrictedSids) ||
  123. ARGUMENT_PRESENT(Token->RestrictedSids)) {
  124. Status = RtlAddAccessAllowedAce (
  125. NewDacl,
  126. ACL_REVISION2,
  127. TOKEN_ALL_ACCESS,
  128. SeRestrictedSid
  129. );
  130. ASSERT( NT_SUCCESS( Status ));
  131. }
  132. *Acl = NewDacl;
  133. return STATUS_SUCCESS;
  134. }
  135. NTSTATUS
  136. NtOpenProcessToken(
  137. IN HANDLE ProcessHandle,
  138. IN ACCESS_MASK DesiredAccess,
  139. OUT PHANDLE TokenHandle
  140. )
  141. /*++
  142. Routine Description:
  143. Open a token object associated with a process and return a handle
  144. that may be used to access that token.
  145. Arguments:
  146. ProcessHandle - Specifies the process whose token is to be
  147. opened.
  148. DesiredAccess - Is an access mask indicating which access types
  149. are desired to the token. These access types are reconciled
  150. with the Discretionary Access Control list of the token to
  151. determine whether the accesses will be granted or denied.
  152. TokenHandle - Receives the handle of the newly opened token.
  153. Return Value:
  154. STATUS_SUCCESS - Indicates the operation was successful.
  155. --*/
  156. {
  157. return NtOpenProcessTokenEx (ProcessHandle,
  158. DesiredAccess,
  159. 0,
  160. TokenHandle);
  161. }
  162. NTSTATUS
  163. NtOpenProcessTokenEx(
  164. IN HANDLE ProcessHandle,
  165. IN ACCESS_MASK DesiredAccess,
  166. IN ULONG HandleAttributes,
  167. OUT PHANDLE TokenHandle
  168. )
  169. /*++
  170. Routine Description:
  171. Open a token object associated with a process and return a handle
  172. that may be used to access that token.
  173. Arguments:
  174. ProcessHandle - Specifies the process whose token is to be
  175. opened.
  176. DesiredAccess - Is an access mask indicating which access types
  177. are desired to the token. These access types are reconciled
  178. with the Discretionary Access Control list of the token to
  179. determine whether the accesses will be granted or denied.
  180. HandleAttributes - Attributes for the created handle. Only OBJ_KERNEL_HANDLE at present.
  181. TokenHandle - Receives the handle of the newly opened token.
  182. Return Value:
  183. STATUS_SUCCESS - Indicates the operation was successful.
  184. --*/
  185. {
  186. PVOID Token;
  187. KPROCESSOR_MODE PreviousMode;
  188. NTSTATUS Status;
  189. HANDLE LocalHandle;
  190. PAGED_CODE();
  191. PreviousMode = KeGetPreviousMode();
  192. //
  193. // Reject bad flags
  194. //
  195. if (HandleAttributes&~OBJ_KERNEL_HANDLE) {
  196. return STATUS_INVALID_PARAMETER;
  197. }
  198. //
  199. // Probe parameters
  200. //
  201. if (PreviousMode != KernelMode) {
  202. try {
  203. ProbeForWriteHandle(TokenHandle);
  204. } except(EXCEPTION_EXECUTE_HANDLER) {
  205. return GetExceptionCode();
  206. } // end_try
  207. HandleAttributes &= ~OBJ_KERNEL_HANDLE;
  208. } //end_if
  209. //
  210. // Valdiate access to the process and obtain a pointer to the
  211. // process's token. If successful, this will cause the token's
  212. // reference count to be incremented.
  213. //
  214. Status = PsOpenTokenOfProcess( ProcessHandle, ((PACCESS_TOKEN *)&Token));
  215. if (!NT_SUCCESS(Status)) {
  216. return Status;
  217. }
  218. //
  219. // Now try to open the token for the specified desired access
  220. //
  221. Status = ObOpenObjectByPointer(
  222. (PVOID)Token, // Object
  223. HandleAttributes, // HandleAttributes
  224. NULL, // AccessState
  225. DesiredAccess, // DesiredAccess
  226. SeTokenObjectType, // ObjectType
  227. PreviousMode, // AccessMode
  228. &LocalHandle // Handle
  229. );
  230. //
  231. // And decrement the reference count of the token to counter
  232. // the action performed by PsOpenTokenOfProcess(). If the open
  233. // was successful, the handle will have caused the token's
  234. // reference count to have been incremented.
  235. //
  236. ObDereferenceObject( Token );
  237. //
  238. // Return the new handle
  239. //
  240. if (NT_SUCCESS(Status)) {
  241. try {
  242. *TokenHandle = LocalHandle;
  243. } except(EXCEPTION_EXECUTE_HANDLER) {
  244. return GetExceptionCode();
  245. }
  246. }
  247. return Status;
  248. }
  249. NTSTATUS
  250. SepOpenTokenOfThread(
  251. IN HANDLE ThreadHandle,
  252. IN BOOLEAN OpenAsSelf,
  253. OUT PACCESS_TOKEN *Token,
  254. OUT PETHREAD *Thread,
  255. OUT PBOOLEAN CopyOnOpen,
  256. OUT PBOOLEAN EffectiveOnly,
  257. OUT PSECURITY_IMPERSONATION_LEVEL ImpersonationLevel
  258. )
  259. /*++
  260. Routine Description:
  261. This function does the thread specific processing of
  262. an NtOpenThreadToken() service.
  263. The service validates that the handle has appropriate access
  264. to reference the thread. If so, it goes on to increment
  265. the reference count of the token object to prevent it from
  266. going away while the rest of the NtOpenThreadToken() request
  267. is processed.
  268. NOTE: If this call completes successfully, the caller is responsible
  269. for decrementing the reference count of the target token.
  270. This must be done using PsDereferenceImpersonationToken().
  271. Arguments:
  272. ThreadHandle - Supplies a handle to a thread object.
  273. OpenAsSelf - Is a boolean value indicating whether the access should
  274. be made using the calling thread's current security context, which
  275. may be that of a client (if impersonating), or using the caller's
  276. process-level security context. A value of FALSE indicates the
  277. caller's current context should be used un-modified. A value of
  278. TRUE indicates the request should be fulfilled using the process
  279. level security context.
  280. Token - If successful, receives a pointer to the thread's token
  281. object.
  282. CopyOnOpen - The current value of the Thread->Client->CopyOnOpen field.
  283. EffectiveOnly - The current value of the Thread->Client->EffectiveOnly field.
  284. ImpersonationLevel - The current value of the Thread->Client->ImpersonationLevel
  285. field.
  286. Return Value:
  287. STATUS_SUCCESS - Indicates the call completed successfully.
  288. STATUS_NO_TOKEN - Indicates the referenced thread is not currently
  289. impersonating a client.
  290. STATUS_CANT_OPEN_ANONYMOUS - Indicates the client requested anonymous
  291. impersonation level. An anonymous token can not be openned.
  292. status may also be any value returned by an attemp the reference
  293. the thread object for THREAD_QUERY_INFORMATION access.
  294. --*/
  295. {
  296. NTSTATUS
  297. Status;
  298. KPROCESSOR_MODE
  299. PreviousMode;
  300. SE_IMPERSONATION_STATE
  301. DisabledImpersonationState;
  302. BOOLEAN
  303. RestoreImpersonationState = FALSE;
  304. PAGED_CODE();
  305. PreviousMode = KeGetPreviousMode();
  306. //
  307. // Make sure the handle grants the appropriate access to the specified
  308. // thread.
  309. //
  310. Status = ObReferenceObjectByHandle(
  311. ThreadHandle,
  312. THREAD_QUERY_INFORMATION,
  313. PsThreadType,
  314. PreviousMode,
  315. (PVOID *)Thread,
  316. NULL
  317. );
  318. if (!NT_SUCCESS(Status)) {
  319. return Status;
  320. }
  321. //
  322. // Reference the impersonation token, if there is one
  323. //
  324. (*Token) = PsReferenceImpersonationToken( *Thread,
  325. CopyOnOpen,
  326. EffectiveOnly,
  327. ImpersonationLevel
  328. );
  329. //
  330. // Make sure there is a token
  331. //
  332. if ((*Token) == NULL) {
  333. ObDereferenceObject( *Thread );
  334. (*Thread) = NULL;
  335. return STATUS_NO_TOKEN;
  336. }
  337. //
  338. // Make sure the ImpersonationLevel is high enough to allow
  339. // the token to be openned.
  340. //
  341. if ((*ImpersonationLevel) <= SecurityAnonymous) {
  342. PsDereferenceImpersonationToken( (*Token) );
  343. ObDereferenceObject( *Thread );
  344. (*Thread) = NULL;
  345. (*Token) = NULL;
  346. return STATUS_CANT_OPEN_ANONYMOUS;
  347. }
  348. return STATUS_SUCCESS;
  349. }
  350. NTSTATUS
  351. NtOpenThreadToken(
  352. IN HANDLE ThreadHandle,
  353. IN ACCESS_MASK DesiredAccess,
  354. IN BOOLEAN OpenAsSelf,
  355. OUT PHANDLE TokenHandle
  356. )
  357. /*++
  358. Routine Description:
  359. Open a token object associated with a thread and return a handle that
  360. may be used to access that token.
  361. Arguments:
  362. ThreadHandle - Specifies the thread whose token is to be opened.
  363. DesiredAccess - Is an access mask indicating which access types
  364. are desired to the token. These access types are reconciled
  365. with the Discretionary Access Control list of the token to
  366. determine whether the accesses will be granted or denied.
  367. OpenAsSelf - Is a boolean value indicating whether the access should
  368. be made using the calling thread's current security context, which
  369. may be that of a client if impersonating, or using the caller's
  370. process-level security context. A value of FALSE indicates the
  371. caller's current context should be used un-modified. A value of
  372. TRUE indicates the request should be fulfilled using the process
  373. level security context.
  374. This parameter is necessary to allow a server process to open
  375. a client's token when the client specified IDENTIFICATION level
  376. impersonation. In this case, the caller would not be able to
  377. open the client's token using the client's context (because you
  378. can't create executive level objects using IDENTIFICATION level
  379. impersonation).
  380. TokenHandle - Receives the handle of the newly opened token.
  381. Return Value:
  382. STATUS_SUCCESS - Indicates the operation was successful.
  383. STATUS_NO_TOKEN - Indicates an attempt has been made to open a
  384. token associated with a thread that is not currently
  385. impersonating a client.
  386. STATUS_CANT_OPEN_ANONYMOUS - Indicates the client requested anonymous
  387. impersonation level. An anonymous token can not be openned.
  388. --*/
  389. {
  390. return NtOpenThreadTokenEx (ThreadHandle,
  391. DesiredAccess,
  392. OpenAsSelf,
  393. 0,
  394. TokenHandle);
  395. }
  396. NTSTATUS
  397. NtOpenThreadTokenEx(
  398. IN HANDLE ThreadHandle,
  399. IN ACCESS_MASK DesiredAccess,
  400. IN BOOLEAN OpenAsSelf,
  401. IN ULONG HandleAttributes,
  402. OUT PHANDLE TokenHandle
  403. )
  404. /*++
  405. Routine Description:
  406. Open a token object associated with a thread and return a handle that
  407. may be used to access that token.
  408. Arguments:
  409. ThreadHandle - Specifies the thread whose token is to be opened.
  410. DesiredAccess - Is an access mask indicating which access types
  411. are desired to the token. These access types are reconciled
  412. with the Discretionary Access Control list of the token to
  413. determine whether the accesses will be granted or denied.
  414. OpenAsSelf - Is a boolean value indicating whether the access should
  415. be made using the calling thread's current security context, which
  416. may be that of a client if impersonating, or using the caller's
  417. process-level security context. A value of FALSE indicates the
  418. caller's current context should be used un-modified. A value of
  419. TRUE indicates the request should be fulfilled using the process
  420. level security context.
  421. This parameter is necessary to allow a server process to open
  422. a client's token when the client specified IDENTIFICATION level
  423. impersonation. In this case, the caller would not be able to
  424. open the client's token using the client's context (because you
  425. can't create executive level objects using IDENTIFICATION level
  426. impersonation).
  427. HandleAttributes - Attributes applied to the handle OBJ_KERNEL_HANDLE
  428. TokenHandle - Receives the handle of the newly opened token.
  429. Return Value:
  430. STATUS_SUCCESS - Indicates the operation was successful.
  431. STATUS_NO_TOKEN - Indicates an attempt has been made to open a
  432. token associated with a thread that is not currently
  433. impersonating a client.
  434. STATUS_CANT_OPEN_ANONYMOUS - Indicates the client requested anonymous
  435. impersonation level. An anonymous token can not be openned.
  436. --*/
  437. {
  438. KPROCESSOR_MODE PreviousMode;
  439. NTSTATUS Status;
  440. PVOID Token;
  441. PTOKEN NewToken = NULL;
  442. BOOLEAN CopyOnOpen;
  443. BOOLEAN EffectiveOnly;
  444. SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
  445. SE_IMPERSONATION_STATE DisabledImpersonationState;
  446. BOOLEAN RestoreImpersonationState = FALSE;
  447. HANDLE LocalHandle = NULL;
  448. SECURITY_DESCRIPTOR SecurityDescriptor;
  449. OBJECT_ATTRIBUTES ObjectAttributes;
  450. PACL NewAcl = NULL;
  451. PETHREAD Thread = NULL;
  452. PETHREAD OriginalThread = NULL;
  453. PACCESS_TOKEN PrimaryToken;
  454. SECURITY_SUBJECT_CONTEXT SubjectSecurityContext;
  455. PAGED_CODE();
  456. PreviousMode = KeGetPreviousMode();
  457. //
  458. // Probe parameters
  459. //
  460. //
  461. // Reject bad flags
  462. //
  463. if (HandleAttributes&~OBJ_KERNEL_HANDLE) {
  464. return STATUS_INVALID_PARAMETER;
  465. }
  466. if (PreviousMode != KernelMode) {
  467. try {
  468. ProbeForWriteHandle(TokenHandle);
  469. } except(EXCEPTION_EXECUTE_HANDLER) {
  470. return GetExceptionCode();
  471. } // end_try
  472. HandleAttributes &= ~OBJ_KERNEL_HANDLE;
  473. } //end_if
  474. //
  475. // Valdiate access to the thread and obtain a pointer to the
  476. // thread's token (if there is one). If successful, this will
  477. // cause the token's reference count to be incremented.
  478. //
  479. // This routine disabled impersonation as necessary to properly
  480. // honor the OpenAsSelf flag.
  481. //
  482. Status = SepOpenTokenOfThread( ThreadHandle,
  483. OpenAsSelf,
  484. ((PACCESS_TOKEN *)&Token),
  485. &OriginalThread,
  486. &CopyOnOpen,
  487. &EffectiveOnly,
  488. &ImpersonationLevel
  489. );
  490. if (!NT_SUCCESS(Status)) {
  491. return Status;
  492. }
  493. //
  494. // The token was successfully referenced.
  495. //
  496. //
  497. // We need to create and/or open a token object, so disable impersonation
  498. // if necessary.
  499. //
  500. if (OpenAsSelf) {
  501. RestoreImpersonationState = PsDisableImpersonation(
  502. PsGetCurrentThread(),
  503. &DisabledImpersonationState
  504. );
  505. }
  506. //
  507. // If the CopyOnOpen flag is not set, then the token can be
  508. // opened directly. Otherwise, the token must be duplicated,
  509. // and a handle to the duplicate returned.
  510. //
  511. if (CopyOnOpen) {
  512. //
  513. // Create the new security descriptor for the token.
  514. //
  515. // We must obtain the correct SID to put into the Dacl. Do this
  516. // by finding the process associated with the passed thread
  517. // and grabbing the User SID out of that process's token.
  518. // If we just use the current SubjectContext, we'll get the
  519. // SID of whoever is calling us, which isn't what we want.
  520. //
  521. Status = ObReferenceObjectByHandle(
  522. ThreadHandle,
  523. THREAD_ALL_ACCESS,
  524. PsThreadType,
  525. KernelMode,
  526. (PVOID)&Thread,
  527. NULL
  528. );
  529. //
  530. // Verify that the handle is still pointer to the same thread
  531. //
  532. if (NT_SUCCESS(Status) && (Thread != OriginalThread)) {
  533. Status = STATUS_OBJECT_TYPE_MISMATCH;
  534. }
  535. if (NT_SUCCESS(Status)) {
  536. PEPROCESS Process = THREAD_TO_PROCESS(Thread);
  537. PrimaryToken = PsReferencePrimaryToken(Process);
  538. Status = SepCreateImpersonationTokenDacl(
  539. (PTOKEN)Token,
  540. PrimaryToken,
  541. &NewAcl
  542. );
  543. PsDereferencePrimaryTokenEx( Process, PrimaryToken );
  544. if (NT_SUCCESS( Status )) {
  545. if (NewAcl != NULL) {
  546. //
  547. // There exist tokens that either do not have security descriptors at all,
  548. // or have security descriptors, but do not have DACLs. In either case, do
  549. // nothing.
  550. //
  551. Status = RtlCreateSecurityDescriptor ( &SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION );
  552. ASSERT( NT_SUCCESS( Status ));
  553. Status = RtlSetDaclSecurityDescriptor (
  554. &SecurityDescriptor,
  555. TRUE,
  556. NewAcl,
  557. FALSE
  558. );
  559. ASSERT( NT_SUCCESS( Status ));
  560. }
  561. InitializeObjectAttributes(
  562. &ObjectAttributes,
  563. NULL,
  564. HandleAttributes,
  565. NULL,
  566. NewAcl == NULL ? NULL : &SecurityDescriptor
  567. );
  568. //
  569. // Open a copy of the token
  570. //
  571. Status = SepDuplicateToken(
  572. (PTOKEN)Token, // ExistingToken
  573. &ObjectAttributes, // ObjectAttributes
  574. EffectiveOnly, // EffectiveOnly
  575. TokenImpersonation, // TokenType
  576. ImpersonationLevel, // ImpersonationLevel
  577. KernelMode, // RequestorMode must be kernel mode
  578. &NewToken
  579. );
  580. if (NT_SUCCESS( Status )) {
  581. //
  582. // Reference the token so it doesn't go away
  583. //
  584. ObReferenceObject(NewToken);
  585. //
  586. // Insert the new token
  587. //
  588. Status = ObInsertObject( NewToken,
  589. NULL,
  590. DesiredAccess,
  591. 0,
  592. (PVOID *)NULL,
  593. &LocalHandle
  594. );
  595. }
  596. }
  597. }
  598. } else {
  599. //
  600. // We do not have to modify the security on the token in the static case,
  601. // because in all the places in the system where impersonation takes place
  602. // over a secure transport (e.g., LPC), CopyOnOpen is set. The only reason
  603. // we'be be here is if the impersonation is taking place because someone did
  604. // an NtSetInformationThread and passed in a token.
  605. //
  606. // In that case, we absolutely do not want to give the caller guaranteed
  607. // access, because that would allow anyone who has access to a thread to
  608. // impersonate any of that thread's clients for any access.
  609. //
  610. //
  611. // Open the existing token
  612. //
  613. Status = ObOpenObjectByPointer(
  614. (PVOID)Token, // Object
  615. HandleAttributes, // HandleAttributes
  616. NULL, // AccessState
  617. DesiredAccess, // DesiredAccess
  618. SeTokenObjectType, // ObjectType
  619. PreviousMode, // AccessMode
  620. &LocalHandle // Handle
  621. );
  622. }
  623. if (NewAcl != NULL) {
  624. ExFreePool( NewAcl );
  625. }
  626. if (RestoreImpersonationState) {
  627. PsRestoreImpersonation(
  628. PsGetCurrentThread(),
  629. &DisabledImpersonationState
  630. );
  631. }
  632. //
  633. // And decrement the reference count of the existing token to counter
  634. // the action performed by PsOpenTokenOfThread. If the open
  635. // was successful, the handle will have caused the token's
  636. // reference count to have been incremented.
  637. //
  638. ObDereferenceObject( Token );
  639. if (NT_SUCCESS( Status ) && CopyOnOpen) {
  640. //
  641. // Assign the newly duplicated token to the thread.
  642. //
  643. PsImpersonateClient( Thread,
  644. NewToken,
  645. FALSE, // turn off CopyOnOpen flag
  646. EffectiveOnly,
  647. ImpersonationLevel
  648. );
  649. }
  650. //
  651. // We've impersonated the token so let go of oure reference
  652. //
  653. if (NewToken != NULL) {
  654. ObDereferenceObject( NewToken );
  655. }
  656. if (CopyOnOpen && (Thread != NULL)) {
  657. ObDereferenceObject( Thread );
  658. }
  659. if (OriginalThread != NULL) {
  660. ObDereferenceObject(OriginalThread);
  661. }
  662. //
  663. // Return the new handle
  664. //
  665. if (NT_SUCCESS(Status)) {
  666. try {
  667. *TokenHandle = LocalHandle;
  668. } except(EXCEPTION_EXECUTE_HANDLER) {
  669. return GetExceptionCode();
  670. }
  671. }
  672. return Status;
  673. }