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.

917 lines
26 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. // Sanitize the handle attribute flags
  194. //
  195. HandleAttributes = ObSanitizeHandleAttributes (HandleAttributes, PreviousMode);
  196. //
  197. // Probe parameters
  198. //
  199. if (PreviousMode != KernelMode) {
  200. try {
  201. ProbeForWriteHandle(TokenHandle);
  202. } except(EXCEPTION_EXECUTE_HANDLER) {
  203. return GetExceptionCode();
  204. } // end_try
  205. } //end_if
  206. //
  207. // Valdiate access to the process and obtain a pointer to the
  208. // process's token. If successful, this will cause the token's
  209. // reference count to be incremented.
  210. //
  211. Status = PsOpenTokenOfProcess( ProcessHandle, ((PACCESS_TOKEN *)&Token));
  212. if (!NT_SUCCESS(Status)) {
  213. return Status;
  214. }
  215. //
  216. // Now try to open the token for the specified desired access
  217. //
  218. Status = ObOpenObjectByPointer(
  219. (PVOID)Token, // Object
  220. HandleAttributes, // HandleAttributes
  221. NULL, // AccessState
  222. DesiredAccess, // DesiredAccess
  223. SeTokenObjectType, // ObjectType
  224. PreviousMode, // AccessMode
  225. &LocalHandle // Handle
  226. );
  227. //
  228. // And decrement the reference count of the token to counter
  229. // the action performed by PsOpenTokenOfProcess(). If the open
  230. // was successful, the handle will have caused the token's
  231. // reference count to have been incremented.
  232. //
  233. ObDereferenceObject( Token );
  234. //
  235. // Return the new handle
  236. //
  237. if (NT_SUCCESS(Status)) {
  238. try {
  239. *TokenHandle = LocalHandle;
  240. } except(EXCEPTION_EXECUTE_HANDLER) {
  241. return GetExceptionCode();
  242. }
  243. }
  244. return Status;
  245. }
  246. NTSTATUS
  247. SepOpenTokenOfThread(
  248. IN HANDLE ThreadHandle,
  249. IN BOOLEAN OpenAsSelf,
  250. OUT PACCESS_TOKEN *Token,
  251. OUT PETHREAD *Thread,
  252. OUT PBOOLEAN CopyOnOpen,
  253. OUT PBOOLEAN EffectiveOnly,
  254. OUT PSECURITY_IMPERSONATION_LEVEL ImpersonationLevel
  255. )
  256. /*++
  257. Routine Description:
  258. This function does the thread specific processing of
  259. an NtOpenThreadToken() service.
  260. The service validates that the handle has appropriate access
  261. to reference the thread. If so, it goes on to increment
  262. the reference count of the token object to prevent it from
  263. going away while the rest of the NtOpenThreadToken() request
  264. is processed.
  265. NOTE: If this call completes successfully, the caller is responsible
  266. for decrementing the reference count of the target token.
  267. This must be done using PsDereferenceImpersonationToken().
  268. Arguments:
  269. ThreadHandle - Supplies a handle to a thread object.
  270. OpenAsSelf - Is a boolean value indicating whether the access should
  271. be made using the calling thread's current security context, which
  272. may be that of a client (if impersonating), or using the caller's
  273. process-level security context. A value of FALSE indicates the
  274. caller's current context should be used un-modified. A value of
  275. TRUE indicates the request should be fulfilled using the process
  276. level security context.
  277. Token - If successful, receives a pointer to the thread's token
  278. object.
  279. CopyOnOpen - The current value of the Thread->Client->CopyOnOpen field.
  280. EffectiveOnly - The current value of the Thread->Client->EffectiveOnly field.
  281. ImpersonationLevel - The current value of the Thread->Client->ImpersonationLevel
  282. field.
  283. Return Value:
  284. STATUS_SUCCESS - Indicates the call completed successfully.
  285. STATUS_NO_TOKEN - Indicates the referenced thread is not currently
  286. impersonating a client.
  287. STATUS_CANT_OPEN_ANONYMOUS - Indicates the client requested anonymous
  288. impersonation level. An anonymous token can not be openned.
  289. status may also be any value returned by an attemp the reference
  290. the thread object for THREAD_QUERY_INFORMATION access.
  291. --*/
  292. {
  293. NTSTATUS
  294. Status;
  295. KPROCESSOR_MODE
  296. PreviousMode;
  297. SE_IMPERSONATION_STATE
  298. DisabledImpersonationState;
  299. BOOLEAN
  300. RestoreImpersonationState = FALSE;
  301. PAGED_CODE();
  302. PreviousMode = KeGetPreviousMode();
  303. //
  304. // Make sure the handle grants the appropriate access to the specified
  305. // thread.
  306. //
  307. Status = ObReferenceObjectByHandle(
  308. ThreadHandle,
  309. THREAD_QUERY_INFORMATION,
  310. PsThreadType,
  311. PreviousMode,
  312. (PVOID *)Thread,
  313. NULL
  314. );
  315. if (!NT_SUCCESS(Status)) {
  316. return Status;
  317. }
  318. //
  319. // Reference the impersonation token, if there is one
  320. //
  321. (*Token) = PsReferenceImpersonationToken( *Thread,
  322. CopyOnOpen,
  323. EffectiveOnly,
  324. ImpersonationLevel
  325. );
  326. //
  327. // Make sure there is a token
  328. //
  329. if ((*Token) == NULL) {
  330. ObDereferenceObject( *Thread );
  331. (*Thread) = NULL;
  332. return STATUS_NO_TOKEN;
  333. }
  334. //
  335. // Make sure the ImpersonationLevel is high enough to allow
  336. // the token to be openned.
  337. //
  338. if ((*ImpersonationLevel) <= SecurityAnonymous) {
  339. PsDereferenceImpersonationToken( (*Token) );
  340. ObDereferenceObject( *Thread );
  341. (*Thread) = NULL;
  342. (*Token) = NULL;
  343. return STATUS_CANT_OPEN_ANONYMOUS;
  344. }
  345. return STATUS_SUCCESS;
  346. }
  347. NTSTATUS
  348. NtOpenThreadToken(
  349. IN HANDLE ThreadHandle,
  350. IN ACCESS_MASK DesiredAccess,
  351. IN BOOLEAN OpenAsSelf,
  352. OUT PHANDLE TokenHandle
  353. )
  354. /*++
  355. Routine Description:
  356. Open a token object associated with a thread and return a handle that
  357. may be used to access that token.
  358. Arguments:
  359. ThreadHandle - Specifies the thread whose token is to be opened.
  360. DesiredAccess - Is an access mask indicating which access types
  361. are desired to the token. These access types are reconciled
  362. with the Discretionary Access Control list of the token to
  363. determine whether the accesses will be granted or denied.
  364. OpenAsSelf - Is a boolean value indicating whether the access should
  365. be made using the calling thread's current security context, which
  366. may be that of a client if impersonating, or using the caller's
  367. process-level security context. A value of FALSE indicates the
  368. caller's current context should be used un-modified. A value of
  369. TRUE indicates the request should be fulfilled using the process
  370. level security context.
  371. This parameter is necessary to allow a server process to open
  372. a client's token when the client specified IDENTIFICATION level
  373. impersonation. In this case, the caller would not be able to
  374. open the client's token using the client's context (because you
  375. can't create executive level objects using IDENTIFICATION level
  376. impersonation).
  377. TokenHandle - Receives the handle of the newly opened token.
  378. Return Value:
  379. STATUS_SUCCESS - Indicates the operation was successful.
  380. STATUS_NO_TOKEN - Indicates an attempt has been made to open a
  381. token associated with a thread that is not currently
  382. impersonating a client.
  383. STATUS_CANT_OPEN_ANONYMOUS - Indicates the client requested anonymous
  384. impersonation level. An anonymous token can not be openned.
  385. --*/
  386. {
  387. return NtOpenThreadTokenEx (ThreadHandle,
  388. DesiredAccess,
  389. OpenAsSelf,
  390. 0,
  391. TokenHandle);
  392. }
  393. NTSTATUS
  394. NtOpenThreadTokenEx(
  395. IN HANDLE ThreadHandle,
  396. IN ACCESS_MASK DesiredAccess,
  397. IN BOOLEAN OpenAsSelf,
  398. IN ULONG HandleAttributes,
  399. OUT PHANDLE TokenHandle
  400. )
  401. /*++
  402. Routine Description:
  403. Open a token object associated with a thread and return a handle that
  404. may be used to access that token.
  405. Arguments:
  406. ThreadHandle - Specifies the thread whose token is to be opened.
  407. DesiredAccess - Is an access mask indicating which access types
  408. are desired to the token. These access types are reconciled
  409. with the Discretionary Access Control list of the token to
  410. determine whether the accesses will be granted or denied.
  411. OpenAsSelf - Is a boolean value indicating whether the access should
  412. be made using the calling thread's current security context, which
  413. may be that of a client if impersonating, or using the caller's
  414. process-level security context. A value of FALSE indicates the
  415. caller's current context should be used un-modified. A value of
  416. TRUE indicates the request should be fulfilled using the process
  417. level security context.
  418. This parameter is necessary to allow a server process to open
  419. a client's token when the client specified IDENTIFICATION level
  420. impersonation. In this case, the caller would not be able to
  421. open the client's token using the client's context (because you
  422. can't create executive level objects using IDENTIFICATION level
  423. impersonation).
  424. HandleAttributes - Attributes applied to the handle OBJ_KERNEL_HANDLE
  425. TokenHandle - Receives the handle of the newly opened token.
  426. Return Value:
  427. STATUS_SUCCESS - Indicates the operation was successful.
  428. STATUS_NO_TOKEN - Indicates an attempt has been made to open a
  429. token associated with a thread that is not currently
  430. impersonating a client.
  431. STATUS_CANT_OPEN_ANONYMOUS - Indicates the client requested anonymous
  432. impersonation level. An anonymous token can not be openned.
  433. --*/
  434. {
  435. KPROCESSOR_MODE PreviousMode;
  436. NTSTATUS Status;
  437. PVOID Token;
  438. PTOKEN NewToken = NULL;
  439. BOOLEAN CopyOnOpen;
  440. BOOLEAN EffectiveOnly;
  441. SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
  442. SE_IMPERSONATION_STATE DisabledImpersonationState;
  443. BOOLEAN RestoreImpersonationState = FALSE;
  444. HANDLE LocalHandle = NULL;
  445. SECURITY_DESCRIPTOR SecurityDescriptor;
  446. OBJECT_ATTRIBUTES ObjectAttributes;
  447. PACL NewAcl = NULL;
  448. PETHREAD Thread = NULL;
  449. PETHREAD OriginalThread = NULL;
  450. PACCESS_TOKEN PrimaryToken;
  451. SECURITY_SUBJECT_CONTEXT SubjectSecurityContext;
  452. PAGED_CODE();
  453. PreviousMode = KeGetPreviousMode();
  454. //
  455. // Sanitize the handle attribute flags
  456. //
  457. HandleAttributes = ObSanitizeHandleAttributes (HandleAttributes, PreviousMode);
  458. //
  459. // Probe parameters
  460. //
  461. if (PreviousMode != KernelMode) {
  462. try {
  463. ProbeForWriteHandle(TokenHandle);
  464. } except(EXCEPTION_EXECUTE_HANDLER) {
  465. return GetExceptionCode();
  466. } // end_try
  467. } //end_if
  468. //
  469. // Valdiate access to the thread and obtain a pointer to the
  470. // thread's token (if there is one). If successful, this will
  471. // cause the token's reference count to be incremented.
  472. //
  473. // This routine disabled impersonation as necessary to properly
  474. // honor the OpenAsSelf flag.
  475. //
  476. Status = SepOpenTokenOfThread( ThreadHandle,
  477. OpenAsSelf,
  478. ((PACCESS_TOKEN *)&Token),
  479. &OriginalThread,
  480. &CopyOnOpen,
  481. &EffectiveOnly,
  482. &ImpersonationLevel
  483. );
  484. if (!NT_SUCCESS(Status)) {
  485. return Status;
  486. }
  487. //
  488. // The token was successfully referenced.
  489. //
  490. //
  491. // We need to create and/or open a token object, so disable impersonation
  492. // if necessary.
  493. //
  494. if (OpenAsSelf) {
  495. RestoreImpersonationState = PsDisableImpersonation(
  496. PsGetCurrentThread(),
  497. &DisabledImpersonationState
  498. );
  499. }
  500. //
  501. // If the CopyOnOpen flag is not set, then the token can be
  502. // opened directly. Otherwise, the token must be duplicated,
  503. // and a handle to the duplicate returned.
  504. //
  505. if (CopyOnOpen) {
  506. //
  507. // Create the new security descriptor for the token.
  508. //
  509. // We must obtain the correct SID to put into the Dacl. Do this
  510. // by finding the process associated with the passed thread
  511. // and grabbing the User SID out of that process's token.
  512. // If we just use the current SubjectContext, we'll get the
  513. // SID of whoever is calling us, which isn't what we want.
  514. //
  515. Status = ObReferenceObjectByHandle(
  516. ThreadHandle,
  517. THREAD_ALL_ACCESS,
  518. PsThreadType,
  519. KernelMode,
  520. (PVOID)&Thread,
  521. NULL
  522. );
  523. //
  524. // Verify that the handle is still pointer to the same thread
  525. //
  526. if (NT_SUCCESS(Status) && (Thread != OriginalThread)) {
  527. Status = STATUS_OBJECT_TYPE_MISMATCH;
  528. }
  529. if (NT_SUCCESS(Status)) {
  530. PEPROCESS Process = THREAD_TO_PROCESS(Thread);
  531. PrimaryToken = PsReferencePrimaryToken(Process);
  532. Status = SepCreateImpersonationTokenDacl(
  533. (PTOKEN)Token,
  534. PrimaryToken,
  535. &NewAcl
  536. );
  537. PsDereferencePrimaryTokenEx( Process, PrimaryToken );
  538. if (NT_SUCCESS( Status )) {
  539. if (NewAcl != NULL) {
  540. //
  541. // There exist tokens that either do not have security descriptors at all,
  542. // or have security descriptors, but do not have DACLs. In either case, do
  543. // nothing.
  544. //
  545. Status = RtlCreateSecurityDescriptor ( &SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION );
  546. ASSERT( NT_SUCCESS( Status ));
  547. Status = RtlSetDaclSecurityDescriptor (
  548. &SecurityDescriptor,
  549. TRUE,
  550. NewAcl,
  551. FALSE
  552. );
  553. ASSERT( NT_SUCCESS( Status ));
  554. }
  555. InitializeObjectAttributes(
  556. &ObjectAttributes,
  557. NULL,
  558. HandleAttributes,
  559. NULL,
  560. NewAcl == NULL ? NULL : &SecurityDescriptor
  561. );
  562. //
  563. // Open a copy of the token
  564. //
  565. Status = SepDuplicateToken(
  566. (PTOKEN)Token, // ExistingToken
  567. &ObjectAttributes, // ObjectAttributes
  568. EffectiveOnly, // EffectiveOnly
  569. TokenImpersonation, // TokenType
  570. ImpersonationLevel, // ImpersonationLevel
  571. KernelMode, // RequestorMode must be kernel mode
  572. &NewToken
  573. );
  574. if (NT_SUCCESS( Status )) {
  575. //
  576. // Reference the token so it doesn't go away
  577. //
  578. ObReferenceObject(NewToken);
  579. //
  580. // Insert the new token
  581. //
  582. Status = ObInsertObject( NewToken,
  583. NULL,
  584. DesiredAccess,
  585. 0,
  586. (PVOID *)NULL,
  587. &LocalHandle
  588. );
  589. }
  590. }
  591. }
  592. } else {
  593. //
  594. // We do not have to modify the security on the token in the static case,
  595. // because in all the places in the system where impersonation takes place
  596. // over a secure transport (e.g., LPC), CopyOnOpen is set. The only reason
  597. // we'be be here is if the impersonation is taking place because someone did
  598. // an NtSetInformationThread and passed in a token.
  599. //
  600. // In that case, we absolutely do not want to give the caller guaranteed
  601. // access, because that would allow anyone who has access to a thread to
  602. // impersonate any of that thread's clients for any access.
  603. //
  604. //
  605. // Open the existing token
  606. //
  607. Status = ObOpenObjectByPointer(
  608. (PVOID)Token, // Object
  609. HandleAttributes, // HandleAttributes
  610. NULL, // AccessState
  611. DesiredAccess, // DesiredAccess
  612. SeTokenObjectType, // ObjectType
  613. PreviousMode, // AccessMode
  614. &LocalHandle // Handle
  615. );
  616. }
  617. if (NewAcl != NULL) {
  618. ExFreePool( NewAcl );
  619. }
  620. if (RestoreImpersonationState) {
  621. PsRestoreImpersonation(
  622. PsGetCurrentThread(),
  623. &DisabledImpersonationState
  624. );
  625. }
  626. //
  627. // And decrement the reference count of the existing token to counter
  628. // the action performed by PsOpenTokenOfThread. If the open
  629. // was successful, the handle will have caused the token's
  630. // reference count to have been incremented.
  631. //
  632. ObDereferenceObject( Token );
  633. if (NT_SUCCESS( Status ) && CopyOnOpen) {
  634. //
  635. // Assign the newly duplicated token to the thread.
  636. //
  637. PsImpersonateClient( Thread,
  638. NewToken,
  639. FALSE, // turn off CopyOnOpen flag
  640. EffectiveOnly,
  641. ImpersonationLevel
  642. );
  643. }
  644. //
  645. // We've impersonated the token so let go of oure reference
  646. //
  647. if (NewToken != NULL) {
  648. ObDereferenceObject( NewToken );
  649. }
  650. if (CopyOnOpen && (Thread != NULL)) {
  651. ObDereferenceObject( Thread );
  652. }
  653. if (OriginalThread != NULL) {
  654. ObDereferenceObject(OriginalThread);
  655. }
  656. //
  657. // Return the new handle
  658. //
  659. if (NT_SUCCESS(Status)) {
  660. try {
  661. *TokenHandle = LocalHandle;
  662. } except(EXCEPTION_EXECUTE_HANDLER) {
  663. return GetExceptionCode();
  664. }
  665. }
  666. return Status;
  667. }