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.

1974 lines
50 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. security.c
  5. Abstract:
  6. This module implements the security related portions of the process
  7. structure.
  8. Author:
  9. Mark Lucovsky (markl) 25-Apr-1989
  10. Jim Kelly (JimK) 2-August-1990
  11. Neill Clift (NeillC) 14-Aug-2000
  12. Revamped for fast referencing the primary token and holding the security lock
  13. only over critical portions.
  14. Revision History:
  15. --*/
  16. #include "psp.h"
  17. #ifdef ALLOC_PRAGMA
  18. NTSTATUS
  19. PsOpenTokenOfJobObject(
  20. IN HANDLE JobObject,
  21. OUT PACCESS_TOKEN * Token
  22. );
  23. #pragma alloc_text(PAGE, PsReferencePrimaryToken)
  24. #pragma alloc_text(PAGE, PsReferenceImpersonationToken)
  25. #pragma alloc_text(PAGE, PsReferenceEffectiveToken)
  26. #pragma alloc_text(PAGE, PsOpenTokenOfThread)
  27. #pragma alloc_text(PAGE, PsOpenTokenOfProcess)
  28. #pragma alloc_text(PAGE, PsOpenTokenOfJobObject)
  29. #pragma alloc_text(PAGE, PsImpersonateClient)
  30. #pragma alloc_text(PAGE, PsDisableImpersonation)
  31. #pragma alloc_text(PAGE, PsRestoreImpersonation)
  32. #pragma alloc_text(PAGE, PsRevertToSelf)
  33. #pragma alloc_text(PAGE, PsRevertThreadToSelf)
  34. #pragma alloc_text(PAGE, PspInitializeProcessSecurity)
  35. #pragma alloc_text(PAGE, PspDeleteProcessSecurity)
  36. #pragma alloc_text(PAGE, PspAssignPrimaryToken)
  37. #pragma alloc_text(PAGE, PspInitializeThreadSecurity)
  38. #pragma alloc_text(PAGE, PspDeleteThreadSecurity)
  39. #pragma alloc_text(PAGE, PsAssignImpersonationToken)
  40. #pragma alloc_text(PAGE, PspWriteTebImpersonationInfo)
  41. #endif //ALLOC_PRAGMA
  42. PACCESS_TOKEN
  43. PsReferencePrimaryToken(
  44. IN PEPROCESS Process
  45. )
  46. /*++
  47. Routine Description:
  48. This function returns a pointer to the primary token of a process.
  49. The reference count of that primary token is incremented to protect
  50. the pointer returned.
  51. When the pointer is no longer needed, it should be freed using
  52. PsDereferencePrimaryToken().
  53. Arguments:
  54. Process - Supplies the address of the process whose primary token
  55. is to be referenced.
  56. Return Value:
  57. A pointer to the specified process's primary token.
  58. --*/
  59. {
  60. PACCESS_TOKEN Token;
  61. PETHREAD CurrentThread;
  62. PAGED_CODE();
  63. ASSERT( Process->Pcb.Header.Type == ProcessObject );
  64. Token = ObFastReferenceObject (&Process->Token);
  65. if (Token == NULL) {
  66. CurrentThread = PsGetCurrentThread ();
  67. PspLockProcessSecurityShared (Process, CurrentThread);
  68. Token = ObFastReferenceObjectLocked (&Process->Token);
  69. PspUnlockProcessSecurityShared (Process, CurrentThread);
  70. }
  71. return Token;
  72. }
  73. PACCESS_TOKEN
  74. PsReferenceImpersonationToken(
  75. IN PETHREAD Thread,
  76. OUT PBOOLEAN CopyOnOpen,
  77. OUT PBOOLEAN EffectiveOnly,
  78. OUT PSECURITY_IMPERSONATION_LEVEL ImpersonationLevel
  79. )
  80. /*++
  81. Routine Description:
  82. This function returns a pointer to the impersonation token of a thread.
  83. The reference count of that impersonation token is incremented to protect
  84. the pointer returned.
  85. If the thread is not currently impersonating a client, then a null pointer
  86. is returned.
  87. If the thread is impersonating a client, then information about the
  88. means of impersonation are also returned (ImpersonationLevel).
  89. If a non-null value is returned, then PsDereferenceImpersonationToken()
  90. must be called to decrement the token's reference count when the pointer
  91. is no longer needed.
  92. Arguments:
  93. Thread - Supplies the address of the thread whose impersonation token
  94. is to be referenced.
  95. CopyOnOpen - The current value of the Thread->ImpersonationInfo->CopyOnOpen field.
  96. EffectiveOnly - The current value of the Thread->ImpersonationInfo->EffectiveOnly field.
  97. ImpersonationLevel - The current value of the Thread->ImpersonationInfo->ImpersonationLevel
  98. field.
  99. Return Value:
  100. A pointer to the specified thread's impersonation token.
  101. If the thread is not currently impersonating a client, then NULL is
  102. returned.
  103. --*/
  104. {
  105. PACCESS_TOKEN Token;
  106. PETHREAD CurrentThread;
  107. PPS_IMPERSONATION_INFORMATION ImpersonationInfo;
  108. PAGED_CODE();
  109. ASSERT (Thread->Tcb.Header.Type == ThreadObject);
  110. //
  111. // before going through the lock overhead just look to see if it is
  112. // null. There is no race. Grabbing the lock is not needed until
  113. // we decide to use the token at which point we re check to see it
  114. // it is null.
  115. // This check saves about 300 instructions.
  116. //
  117. if (!PS_IS_THREAD_IMPERSONATING (Thread)) {
  118. return NULL;
  119. }
  120. //
  121. // Lock the process security fields.
  122. //
  123. CurrentThread = PsGetCurrentThread ();
  124. PspLockThreadSecurityShared (Thread, CurrentThread);
  125. //
  126. // Grab impersonation info block.
  127. //
  128. ImpersonationInfo = Thread->ImpersonationInfo;
  129. if (PS_IS_THREAD_IMPERSONATING (Thread)) {
  130. //
  131. // Return the thread's impersonation level, etc.
  132. //
  133. Token = ImpersonationInfo->Token;
  134. //
  135. // Increment the reference count of the token to protect our
  136. // pointer.
  137. //
  138. ObReferenceObject (Token);
  139. (*ImpersonationLevel) = ImpersonationInfo->ImpersonationLevel;
  140. (*CopyOnOpen) = ImpersonationInfo->CopyOnOpen;
  141. (*EffectiveOnly) = ImpersonationInfo->EffectiveOnly;
  142. } else {
  143. Token = NULL;
  144. }
  145. //
  146. // Release the security fields.
  147. //
  148. PspUnlockThreadSecurityShared (Thread, CurrentThread);
  149. return Token;
  150. }
  151. PACCESS_TOKEN
  152. PsReferenceEffectiveToken(
  153. IN PETHREAD Thread,
  154. OUT PTOKEN_TYPE TokenType,
  155. OUT PBOOLEAN EffectiveOnly,
  156. OUT PSECURITY_IMPERSONATION_LEVEL ImpersonationLevel
  157. )
  158. /*++
  159. Routine Description:
  160. This function returns a pointer to the effective token of a thread. The
  161. effective token of a thread is the thread's impersonation token if it has
  162. one. Otherwise, it is the primary token of the thread's process.
  163. The reference count of the effective token is incremented to protect
  164. the pointer returned.
  165. If the thread is impersonating a client, then the impersonation level
  166. is also returned.
  167. Either PsDereferenceImpersonationToken() (for an impersonation token) or
  168. PsDereferencePrimaryToken() (for a primary token) must be called to
  169. decrement the token's reference count when the pointer is no longer
  170. needed.
  171. Arguments:
  172. Thread - Supplies the address of the thread whose effective token
  173. is to be referenced.
  174. TokenType - Receives the type of the effective token. If the thread
  175. is currently impersonating a client, then this will be
  176. TokenImpersonation. Othwerwise, it will be TokenPrimary.
  177. EffectiveOnly - If the token type is TokenImpersonation, then this
  178. receives the value of the client thread's Thread->Client->EffectiveOnly field.
  179. Otherwise, it is set to FALSE.
  180. ImpersonationLevel - The current value of the Thread->Client->ImpersonationLevel
  181. field for an impersonation token and is not set for a primary token.
  182. Return Value:
  183. A pointer to the specified thread's effective token.
  184. --*/
  185. {
  186. PACCESS_TOKEN Token;
  187. PEPROCESS Process;
  188. PETHREAD CurrentThread;
  189. PPS_IMPERSONATION_INFORMATION ImpersonationInfo;
  190. PAGED_CODE();
  191. ASSERT (Thread->Tcb.Header.Type == ThreadObject);
  192. Process = THREAD_TO_PROCESS(Thread);
  193. //
  194. // Grab the current impersonation token pointer value
  195. //
  196. Token = NULL;
  197. if (PS_IS_THREAD_IMPERSONATING (Thread)) {
  198. //
  199. // Lock the process security fields.
  200. //
  201. CurrentThread = PsGetCurrentThread ();
  202. PspLockThreadSecurityShared (Thread, CurrentThread);
  203. if (PS_IS_THREAD_IMPERSONATING (Thread)) {
  204. //
  205. // Grab impersonation info block.
  206. //
  207. ImpersonationInfo = Thread->ImpersonationInfo;
  208. Token = ImpersonationInfo->Token;
  209. //
  210. // Return the thread's impersonation level, etc.
  211. //
  212. (*TokenType) = TokenImpersonation;
  213. (*EffectiveOnly) = ImpersonationInfo->EffectiveOnly;
  214. (*ImpersonationLevel) = ImpersonationInfo->ImpersonationLevel;
  215. //
  216. // Increment the reference count of the token to protect our
  217. // pointer.
  218. //
  219. ObReferenceObject (Token);
  220. //
  221. // Release the security fields.
  222. //
  223. PspUnlockThreadSecurityShared (Thread, CurrentThread);
  224. return Token;
  225. }
  226. //
  227. // Release the security fields.
  228. //
  229. PspUnlockThreadSecurityShared (Thread, CurrentThread);
  230. }
  231. //
  232. // Get the thread's primary token if it wasn't impersonating a client.
  233. //
  234. Token = ObFastReferenceObject (&Process->Token);
  235. if (Token == NULL) {
  236. //
  237. // Fast ref failed. We go the slow way with a lock
  238. //
  239. CurrentThread = PsGetCurrentThread ();
  240. PspLockProcessSecurityShared (Process,CurrentThread);
  241. Token = ObFastReferenceObjectLocked (&Process->Token);
  242. PspUnlockProcessSecurityShared (Process,CurrentThread);
  243. }
  244. //
  245. // Only the TokenType and CopyOnOpen OUT parameters are
  246. // returned for a primary token.
  247. //
  248. (*TokenType) = TokenPrimary;
  249. (*EffectiveOnly) = FALSE;
  250. return Token;
  251. }
  252. NTSTATUS
  253. PsOpenTokenOfThread(
  254. IN HANDLE ThreadHandle,
  255. IN BOOLEAN OpenAsSelf,
  256. OUT PACCESS_TOKEN *Token,
  257. OUT PBOOLEAN CopyOnOpen,
  258. OUT PBOOLEAN EffectiveOnly,
  259. OUT PSECURITY_IMPERSONATION_LEVEL ImpersonationLevel
  260. )
  261. /*++
  262. Routine Description:
  263. This function does the thread specific processing of
  264. an NtOpenThreadToken() service.
  265. The service validates that the handle has appropriate access
  266. to reference the thread. If so, it goes on to increment
  267. the reference count of the token object to prevent it from
  268. going away while the rest of the NtOpenThreadToken() request
  269. is processed.
  270. NOTE: If this call completes successfully, the caller is responsible
  271. for decrementing the reference count of the target token.
  272. This must be done using PsDereferenceImpersonationToken().
  273. Arguments:
  274. ThreadHandle - Supplies a handle to a thread object.
  275. OpenAsSelf - Is a boolean value indicating whether the access should
  276. be made using the calling thread's current security context, which
  277. may be that of a client (if impersonating), or using the caller's
  278. process-level security context. A value of FALSE indicates the
  279. caller's current context should be used un-modified. A value of
  280. TRUE indicates the request should be fulfilled using the process
  281. level security context.
  282. Token - If successful, receives a pointer to the thread's token
  283. object.
  284. CopyOnOpen - The current value of the Thread->Client->CopyOnOpen field.
  285. EffectiveOnly - The current value of the Thread->Client->EffectiveOnly field.
  286. ImpersonationLevel - The current value of the Thread->Client->ImpersonationLevel
  287. field.
  288. Return Value:
  289. STATUS_SUCCESS - Indicates the call completed successfully.
  290. STATUS_NO_TOKEN - Indicates the referenced thread is not currently
  291. impersonating a client.
  292. STATUS_CANT_OPEN_ANONYMOUS - Indicates the client requested anonymous
  293. impersonation level. An anonymous token can not be openned.
  294. status may also be any value returned by an attemp the reference
  295. the thread object for THREAD_QUERY_INFORMATION access.
  296. --*/
  297. {
  298. NTSTATUS
  299. Status;
  300. PETHREAD
  301. Thread;
  302. KPROCESSOR_MODE
  303. PreviousMode;
  304. PAGED_CODE();
  305. PreviousMode = KeGetPreviousMode();
  306. UNREFERENCED_PARAMETER (OpenAsSelf);
  307. //
  308. // Make sure the handle grants the appropriate access to the specified
  309. // thread.
  310. //
  311. Status = ObReferenceObjectByHandle (ThreadHandle,
  312. THREAD_QUERY_INFORMATION,
  313. PsThreadType,
  314. PreviousMode,
  315. &Thread,
  316. NULL);
  317. if (!NT_SUCCESS (Status)) {
  318. return Status;
  319. }
  320. //
  321. // Reference the impersonation token, if there is one
  322. //
  323. (*Token) = PsReferenceImpersonationToken (Thread,
  324. CopyOnOpen,
  325. EffectiveOnly,
  326. ImpersonationLevel);
  327. //
  328. // dereference the target thread.
  329. //
  330. ObDereferenceObject (Thread);
  331. //
  332. // Make sure there is a token
  333. //
  334. if (*Token == 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. (*Token) = NULL;
  344. return STATUS_CANT_OPEN_ANONYMOUS;
  345. }
  346. return STATUS_SUCCESS;
  347. }
  348. NTSTATUS
  349. PsOpenTokenOfProcess(
  350. IN HANDLE ProcessHandle,
  351. OUT PACCESS_TOKEN *Token
  352. )
  353. /*++
  354. Routine Description:
  355. This function does the process specific processing of
  356. an NtOpenProcessToken() service.
  357. The service validates that the handle has appropriate access
  358. to referenced process. If so, it goes on to reference the
  359. primary token object to prevent it from going away while the
  360. rest of the NtOpenProcessToken() request is processed.
  361. NOTE: If this call completes successfully, the caller is responsible
  362. for decrementing the reference count of the target token.
  363. This must be done using the PsDereferencePrimaryToken() API.
  364. Arguments:
  365. ProcessHandle - Supplies a handle to a process object whose primary
  366. token is to be opened.
  367. Token - If successful, receives a pointer to the process's token
  368. object.
  369. Return Value:
  370. STATUS_SUCCESS - Indicates the call completed successfully.
  371. status may also be any value returned by an attemp the reference
  372. the process object for PROCESS_QUERY_INFORMATION access.
  373. --*/
  374. {
  375. NTSTATUS
  376. Status;
  377. PEPROCESS
  378. Process;
  379. KPROCESSOR_MODE
  380. PreviousMode;
  381. PAGED_CODE();
  382. PreviousMode = KeGetPreviousMode();
  383. //
  384. // Make sure the handle grants the appropriate access to the specified
  385. // process.
  386. //
  387. Status = ObReferenceObjectByHandle (ProcessHandle,
  388. PROCESS_QUERY_INFORMATION,
  389. PsProcessType,
  390. PreviousMode,
  391. &Process,
  392. NULL);
  393. if (!NT_SUCCESS (Status)) {
  394. return Status;
  395. }
  396. //
  397. // Reference the primary token
  398. // (This takes care of gaining exlusive access to the process
  399. // security fields for us)
  400. //
  401. (*Token) = PsReferencePrimaryToken (Process);
  402. //
  403. // Done with the process object
  404. //
  405. ObDereferenceObject (Process);
  406. return STATUS_SUCCESS;
  407. }
  408. NTSTATUS
  409. PsOpenTokenOfJobObject(
  410. IN HANDLE JobObject,
  411. OUT PACCESS_TOKEN * Token
  412. )
  413. /*++
  414. Routine Description:
  415. This function does the ps/job specific work for NtOpenJobObjectToken.
  416. Arguments:
  417. JobObject - Supplies a handle to a job object whose limit token
  418. token is to be opened.
  419. Token - If successful, receives a pointer to the process's token
  420. object.
  421. Return Value:
  422. STATUS_SUCCESS - Indicates the call completed successfully.
  423. STATUS_NO_TOKEN - indicates the job object does not have a token
  424. --*/
  425. {
  426. NTSTATUS Status;
  427. PEJOB Job;
  428. KPROCESSOR_MODE PreviousMode;
  429. PAGED_CODE();
  430. PreviousMode = KeGetPreviousMode();
  431. Status = ObReferenceObjectByHandle (JobObject,
  432. JOB_OBJECT_QUERY,
  433. PsJobType,
  434. PreviousMode,
  435. &Job,
  436. NULL);
  437. if (NT_SUCCESS (Status)) {
  438. if (Job->Token != NULL) {
  439. ObReferenceObject (Job->Token);
  440. *Token = Job->Token;
  441. } else {
  442. Status = STATUS_NO_TOKEN;
  443. }
  444. }
  445. return Status;
  446. }
  447. NTSTATUS
  448. PsImpersonateClient(
  449. IN PETHREAD Thread,
  450. IN PACCESS_TOKEN Token,
  451. IN BOOLEAN CopyOnOpen,
  452. IN BOOLEAN EffectiveOnly,
  453. IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
  454. )
  455. /*++
  456. Routine Description:
  457. This routine sets up the specified thread so that it is impersonating
  458. the specified client. This will result in the reference count of the
  459. token representing the client being incremented to reflect the new
  460. reference.
  461. If the thread is currently impersonating a client, that token will be
  462. dereferenced.
  463. Arguments:
  464. Thread - points to the thread which is going to impersonate a client.
  465. Token - Points to the token to be assigned as the impersonation token.
  466. This does NOT have to be a TokenImpersonation type token. This
  467. allows direct reference of client process's primary tokens.
  468. CopyOnOpen - If TRUE, indicates the token is considered to be private
  469. by the assigner and should be copied if opened. For example, a
  470. session layer may be using a token to represent a client's context.
  471. If the session is trying to synchronize the context of the client,
  472. then user mode code should not be given direct access to the session
  473. layer's token.
  474. Basically, session layers should always specify TRUE for this, while
  475. tokens assigned by the server itself (handle based) should specify
  476. FALSE.
  477. EffectiveOnly - Is a boolean value to be assigned as the
  478. Thread->ImpersonationInfo->EffectiveOnly field value for the
  479. impersonation. A value of FALSE indicates the server is allowed
  480. to enable currently disabled groups and privileges.
  481. ImpersonationLevel - Is the impersonation level that the server is allowed
  482. to access the token with.
  483. Return Value:
  484. STATUS_SUCCESS - Indicates the call completed successfully.
  485. --*/
  486. {
  487. PPS_IMPERSONATION_INFORMATION NewClient, FreeClient;
  488. PACCESS_TOKEN OldToken;
  489. PACCESS_TOKEN NewerToken=NULL;
  490. PACCESS_TOKEN ProcessToken ;
  491. NTSTATUS Status;
  492. PPS_JOB_TOKEN_FILTER Filter;
  493. PEPROCESS Process;
  494. PETHREAD CurrentThread;
  495. PEJOB Job;
  496. PPS_IMPERSONATION_INFORMATION ImpersonationInfo;
  497. BOOLEAN DontReference = FALSE ;
  498. BOOLEAN NewTokenCreated = FALSE ;
  499. PAGED_CODE();
  500. ASSERT (Thread->Tcb.Header.Type == ThreadObject);
  501. Process = THREAD_TO_PROCESS (Thread);
  502. if (!ARGUMENT_PRESENT(Token)) {
  503. OldToken = NULL;
  504. if (PS_IS_THREAD_IMPERSONATING (Thread)) {
  505. //
  506. // Lock the process security fields
  507. //
  508. CurrentThread = PsGetCurrentThread ();
  509. PspLockThreadSecurityExclusive (Thread, CurrentThread);
  510. if (PS_IS_THREAD_IMPERSONATING (Thread)) {
  511. //
  512. // Grab impersonation info block.
  513. //
  514. ImpersonationInfo = Thread->ImpersonationInfo;
  515. //
  516. // This is a request to revert to self.
  517. // Clean up any client information.
  518. //
  519. OldToken = ImpersonationInfo->Token;
  520. PS_CLEAR_BITS (&Thread->CrossThreadFlags,
  521. PS_CROSS_THREAD_FLAGS_IMPERSONATING);
  522. }
  523. //
  524. // Release the security fields
  525. //
  526. PspUnlockThreadSecurityExclusive (Thread, CurrentThread);
  527. PspWriteTebImpersonationInfo (Thread, CurrentThread);
  528. }
  529. } else {
  530. //
  531. // Allocate and set up the Client block. We do this without holding the Process
  532. // security lock so we reduce contention. Only one thread will manage to assign this.
  533. // The client block once created never goes away until the last dereference of
  534. // the process. We can touch this without locks
  535. //
  536. NewClient = Thread->ImpersonationInfo;
  537. if (NewClient == NULL) {
  538. NewClient = ExAllocatePoolWithTag (PagedPool,
  539. sizeof (PS_IMPERSONATION_INFORMATION),
  540. 'mIsP'|PROTECTED_POOL);
  541. if (NewClient == NULL) {
  542. return STATUS_NO_MEMORY;
  543. }
  544. FreeClient = InterlockedCompareExchangePointer (&Thread->ImpersonationInfo,
  545. NewClient,
  546. NULL);
  547. //
  548. // We got beaten by another thread. Free our context and use the new one
  549. //
  550. if (FreeClient != NULL) {
  551. ExFreePoolWithTag (NewClient, 'mIsP'|PROTECTED_POOL);
  552. NewClient = FreeClient;
  553. }
  554. }
  555. //
  556. // Check process token for rules on impersonation
  557. //
  558. ProcessToken = PsReferencePrimaryToken( Process );
  559. if ( ProcessToken ) {
  560. Status = SeTokenCanImpersonate(
  561. ProcessToken,
  562. Token,
  563. ImpersonationLevel );
  564. PsDereferencePrimaryTokenEx( Process, ProcessToken );
  565. if ( !NT_SUCCESS( Status ) ) {
  566. Status = SeCopyClientToken(
  567. Token,
  568. SecurityIdentification,
  569. KernelMode,
  570. &NewerToken );
  571. if ( !NT_SUCCESS(Status)) {
  572. return Status ;
  573. }
  574. //
  575. // We have a substitute token. Change Token to be this new
  576. // one, but do not add a reference later. Right now, there
  577. // is exactly one reference, so it will go away when the
  578. // thread stops impersonating. Note that we still need to
  579. // do the job filters below, hence the switch.
  580. //
  581. Token = NewerToken ;
  582. NewerToken = NULL ;
  583. DontReference = TRUE ;
  584. NewTokenCreated = TRUE ;
  585. ImpersonationLevel = SecurityIdentification ;
  586. }
  587. }
  588. //
  589. // Check if we're allowed to impersonate based on the job
  590. // restrictions:
  591. //
  592. Job = Process->Job;
  593. if (Job != NULL) {
  594. if ((Job->SecurityLimitFlags & JOB_OBJECT_SECURITY_NO_ADMIN) &&
  595. (SeTokenIsAdmin (Token))) {
  596. if ( NewTokenCreated ) {
  597. ObDereferenceObject( Token );
  598. }
  599. return STATUS_ACCESS_DENIED;
  600. } else if ((Job->SecurityLimitFlags & JOB_OBJECT_SECURITY_RESTRICTED_TOKEN) &&
  601. (!SeTokenIsRestricted (Token))) {
  602. if ( NewTokenCreated ) {
  603. ObDereferenceObject( Token );
  604. }
  605. return STATUS_ACCESS_DENIED;
  606. } else {
  607. Filter = Job->Filter;
  608. if (Filter != NULL) {
  609. //
  610. // Filter installed. Need to create a restricted token
  611. // dynamically.
  612. //
  613. Status = SeFastFilterToken (Token,
  614. KernelMode,
  615. 0,
  616. Filter->CapturedGroupCount,
  617. Filter->CapturedGroups,
  618. Filter->CapturedPrivilegeCount,
  619. Filter->CapturedPrivileges,
  620. Filter->CapturedSidCount,
  621. Filter->CapturedSids,
  622. Filter->CapturedSidsLength,
  623. &NewerToken);
  624. if (NT_SUCCESS (Status)) {
  625. //
  626. // If we created a filtered token then we don't need to add an extra token reference
  627. // as this is a new token with a single reference we just created.
  628. //
  629. if ( NewTokenCreated ) {
  630. ObDereferenceObject( Token );
  631. }
  632. Token = NewerToken;
  633. } else {
  634. if ( NewTokenCreated ) {
  635. ObDereferenceObject( Token );
  636. }
  637. return Status;
  638. }
  639. } else {
  640. if ( !DontReference) {
  641. ObReferenceObject (Token);
  642. }
  643. }
  644. }
  645. } else {
  646. if ( !DontReference) {
  647. ObReferenceObject (Token);
  648. }
  649. }
  650. //
  651. // Lock the process security fields
  652. //
  653. CurrentThread = PsGetCurrentThread ();
  654. PspLockThreadSecurityExclusive (Thread, CurrentThread);
  655. //
  656. // If we are already impersonating someone,
  657. // use the already allocated block. This avoids
  658. // an alloc and a free.
  659. //
  660. if (PS_IS_THREAD_IMPERSONATING (Thread)) {
  661. //
  662. // capture the old token pointer.
  663. // We'll dereference it after unlocking the security fields.
  664. //
  665. OldToken = NewClient->Token;
  666. } else {
  667. OldToken = NULL;
  668. PS_SET_BITS (&Thread->CrossThreadFlags, PS_CROSS_THREAD_FLAGS_IMPERSONATING);
  669. }
  670. NewClient->ImpersonationLevel = ImpersonationLevel;
  671. NewClient->EffectiveOnly = EffectiveOnly;
  672. NewClient->CopyOnOpen = CopyOnOpen;
  673. NewClient->Token = Token;
  674. //
  675. // Release the security fields
  676. //
  677. PspUnlockThreadSecurityExclusive (Thread, CurrentThread);
  678. PspWriteTebImpersonationInfo (Thread, CurrentThread);
  679. }
  680. //
  681. // Free the old client token, if necessary.
  682. //
  683. if (OldToken != NULL) {
  684. PsDereferenceImpersonationToken (OldToken);
  685. }
  686. return STATUS_SUCCESS;
  687. }
  688. BOOLEAN
  689. PsDisableImpersonation(
  690. IN PETHREAD Thread,
  691. IN PSE_IMPERSONATION_STATE ImpersonationState
  692. )
  693. /*++
  694. Routine Description:
  695. This routine temporarily disables the impersonation of a thread.
  696. The impersonation state is saved for quick replacement later. The
  697. impersonation token is left referenced and a pointer to it is held
  698. in the IMPERSONATION_STATE data structure.
  699. PsRestoreImpersonation() must be used after this routine is called.
  700. Arguments:
  701. Thread - points to the thread whose impersonation (if any) is to
  702. be temporarily disabled.
  703. ImpersonationState - receives the current impersonation information,
  704. including a pointer to the impersonation token.
  705. Return Value:
  706. TRUE - Indicates the impersonation state has been saved and the
  707. impersonation has been temporarily disabled.
  708. FALSE - Indicates the specified thread was not impersonating a client.
  709. No action has been taken.
  710. --*/
  711. {
  712. PPS_IMPERSONATION_INFORMATION OldClient;
  713. PETHREAD CurrentThread;
  714. PAGED_CODE();
  715. ASSERT (Thread->Tcb.Header.Type == ThreadObject);
  716. //
  717. // Capture the impersonation information (if there is any).
  718. // The vast majority of cases this function is called we are not impersonating. Skip acquiring
  719. // the lock in this case.
  720. //
  721. OldClient = NULL;
  722. if (PS_IS_THREAD_IMPERSONATING (Thread)) {
  723. //
  724. // Lock the process security fields
  725. //
  726. CurrentThread = PsGetCurrentThread ();
  727. PspLockThreadSecurityExclusive (Thread, CurrentThread);
  728. //
  729. // Test and clear the impersonation bit. If we are still impersonating then capture the info.
  730. //
  731. if (PS_TEST_CLEAR_BITS (&Thread->CrossThreadFlags,
  732. PS_CROSS_THREAD_FLAGS_IMPERSONATING)&
  733. PS_CROSS_THREAD_FLAGS_IMPERSONATING) {
  734. OldClient = Thread->ImpersonationInfo;
  735. ImpersonationState->Level = OldClient->ImpersonationLevel;
  736. ImpersonationState->EffectiveOnly = OldClient->EffectiveOnly;
  737. ImpersonationState->CopyOnOpen = OldClient->CopyOnOpen;
  738. ImpersonationState->Token = OldClient->Token;
  739. }
  740. //
  741. // Release the security fields
  742. //
  743. PspUnlockThreadSecurityExclusive (Thread, CurrentThread);
  744. }
  745. if (OldClient != NULL) {
  746. return TRUE;
  747. } else {
  748. //
  749. // Not impersonating. Just make up some values.
  750. // The NULL for the token indicates we aren't impersonating.
  751. //
  752. ImpersonationState->Level = SecurityAnonymous;
  753. ImpersonationState->EffectiveOnly = FALSE;
  754. ImpersonationState->CopyOnOpen = FALSE;
  755. ImpersonationState->Token = NULL;
  756. return FALSE;
  757. }
  758. }
  759. VOID
  760. PsRestoreImpersonation(
  761. IN PETHREAD Thread,
  762. IN PSE_IMPERSONATION_STATE ImpersonationState
  763. )
  764. /*++
  765. Routine Description:
  766. This routine restores an impersonation that has been temporarily disabled
  767. using PsDisableImpersonation().
  768. Notice that if this routine finds the thread is already impersonating
  769. (again), then restoring the temporarily disabled impersonation will cause
  770. the current impersonation to be abandoned.
  771. Arguments:
  772. Thread - points to the thread whose impersonation is to be restored.
  773. ImpersontionState - receives the current impersontion information,
  774. including a pointer ot the impersonation token.
  775. Return Value:
  776. TRUE - Indicates the impersonation state has been saved and the
  777. impersonation has been temporarily disabled.
  778. FALSE - Indicates the specified thread was not impersonating a client.
  779. No action has been taken.
  780. --*/
  781. {
  782. PETHREAD CurrentThread;
  783. PACCESS_TOKEN OldToken;
  784. PPS_IMPERSONATION_INFORMATION ImpInfo;
  785. PAGED_CODE();
  786. ASSERT (Thread->Tcb.Header.Type == ThreadObject);
  787. OldToken = NULL;
  788. //
  789. // Lock the process security fields
  790. //
  791. CurrentThread = PsGetCurrentThread ();
  792. PspLockThreadSecurityExclusive (Thread, CurrentThread);
  793. ImpInfo = Thread->ImpersonationInfo;
  794. //
  795. // If the thread is currently impersonating then we must revert this
  796. //
  797. if (PS_IS_THREAD_IMPERSONATING (Thread)) {
  798. OldToken = ImpInfo->Token;
  799. }
  800. //
  801. // Restore the previous impersonation token if there was one
  802. //
  803. if (ImpersonationState->Token) {
  804. ImpInfo->ImpersonationLevel = ImpersonationState->Level;
  805. ImpInfo->EffectiveOnly = ImpersonationState->EffectiveOnly;
  806. ImpInfo->CopyOnOpen = ImpersonationState->CopyOnOpen;
  807. ImpInfo->Token = ImpersonationState->Token;
  808. PS_SET_BITS (&Thread->CrossThreadFlags, PS_CROSS_THREAD_FLAGS_IMPERSONATING);
  809. } else {
  810. PS_CLEAR_BITS (&Thread->CrossThreadFlags, PS_CROSS_THREAD_FLAGS_IMPERSONATING);
  811. }
  812. //
  813. // Release the security fields
  814. //
  815. PspUnlockThreadSecurityExclusive (Thread, CurrentThread);
  816. if (OldToken != NULL) {
  817. ObDereferenceObject (OldToken);
  818. }
  819. return;
  820. }
  821. VOID
  822. PsRevertToSelf( )
  823. /*++
  824. Routine Description:
  825. This routine causes the calling thread to discontinue
  826. impersonating a client. If the thread is not currently
  827. impersonating a client, no action is taken.
  828. Arguments:
  829. None.
  830. Return Value:
  831. None.
  832. --*/
  833. {
  834. PETHREAD Thread;
  835. PEPROCESS Process;
  836. PACCESS_TOKEN OldToken;
  837. PAGED_CODE();
  838. Thread = PsGetCurrentThread ();
  839. Process = THREAD_TO_PROCESS (Thread);
  840. //
  841. // Lock the process security fields
  842. //
  843. PspLockThreadSecurityExclusive (Thread, Thread);
  844. //
  845. // See if the thread is impersonating a client
  846. // and dereference that token if so.
  847. //
  848. if (PS_IS_THREAD_IMPERSONATING (Thread)) {
  849. PS_CLEAR_BITS (&Thread->CrossThreadFlags, PS_CROSS_THREAD_FLAGS_IMPERSONATING);
  850. OldToken = Thread->ImpersonationInfo->Token;
  851. } else {
  852. OldToken = NULL;
  853. }
  854. //
  855. // Release the security fields
  856. //
  857. PspUnlockThreadSecurityExclusive (Thread, Thread);
  858. //
  859. // Free the old client info...
  860. //
  861. if (OldToken != NULL) {
  862. ObDereferenceObject (OldToken);
  863. PspWriteTebImpersonationInfo (Thread, Thread);
  864. }
  865. return;
  866. }
  867. VOID
  868. PsRevertThreadToSelf (
  869. IN PETHREAD Thread
  870. )
  871. /*++
  872. Routine Description:
  873. This routine causes the specified thread to discontinue
  874. impersonating a client. If the thread is not currently
  875. impersonating a client, no action is taken.
  876. Arguments:
  877. Thread - Thread to remove impersonation from
  878. Return Value:
  879. None.
  880. --*/
  881. {
  882. PETHREAD CurrentThread;
  883. PACCESS_TOKEN OldToken;
  884. PPS_IMPERSONATION_INFORMATION ImpersonationInfo;
  885. PAGED_CODE();
  886. ASSERT (Thread->Tcb.Header.Type == ThreadObject);
  887. if (PS_IS_THREAD_IMPERSONATING (Thread)) {
  888. CurrentThread = PsGetCurrentThread ();
  889. //
  890. // Lock the process security fields
  891. //
  892. PspLockThreadSecurityExclusive (Thread, CurrentThread);
  893. //
  894. // See if the thread is impersonating a client
  895. // and dereference that token if so.
  896. //
  897. if (PS_IS_THREAD_IMPERSONATING (Thread)) {
  898. //
  899. // Grab impersonation info block.
  900. //
  901. ImpersonationInfo = Thread->ImpersonationInfo;
  902. PS_CLEAR_BITS (&Thread->CrossThreadFlags, PS_CROSS_THREAD_FLAGS_IMPERSONATING);
  903. OldToken = ImpersonationInfo->Token;
  904. } else {
  905. OldToken = NULL;
  906. }
  907. //
  908. // Release the security fields
  909. //
  910. PspUnlockThreadSecurityExclusive (Thread, CurrentThread);
  911. //
  912. // Free the old client info...
  913. //
  914. if (OldToken != NULL) {
  915. ObDereferenceObject (OldToken);
  916. PspWriteTebImpersonationInfo (Thread, CurrentThread);
  917. }
  918. }
  919. return;
  920. }
  921. NTSTATUS
  922. PspInitializeProcessSecurity(
  923. IN PEPROCESS Parent OPTIONAL,
  924. IN PEPROCESS Child
  925. )
  926. /*++
  927. Routine Description:
  928. This function initializes a new process's security fields, including
  929. the assignment of a new primary token.
  930. The child process is assumed to not yet have been inserted into
  931. an object table.
  932. NOTE: IT IS EXPECTED THAT THIS SERVICE WILL BE CALLED WITH A NULL
  933. PARENT PROCESS POINTER EXACTLY ONCE - FOR THE INITIAL SYSTEM
  934. PROCESS.
  935. Arguments:
  936. Parent - An optional pointer to the process being used as the parent
  937. of the new process. If this value is NULL, then the process is
  938. assumed to be the initial system process, and the boot token is
  939. assigned rather than a duplicate of the parent process's primary
  940. token.
  941. Child - Supplies the address of the process being initialized. This
  942. process does not yet require security field contention protection.
  943. In particular, the security fields may be accessed without first
  944. acquiring the process security fields lock.
  945. Return Value:
  946. --*/
  947. {
  948. NTSTATUS Status;
  949. PACCESS_TOKEN ParentToken, NewToken;
  950. PAGED_CODE();
  951. //
  952. // Assign the primary token
  953. //
  954. if (ARGUMENT_PRESENT (Parent)) {
  955. //
  956. // create the primary token
  957. // This is a duplicate of the parent's token.
  958. //
  959. ParentToken = PsReferencePrimaryToken (Parent);
  960. Status = SeSubProcessToken (ParentToken,
  961. &NewToken,
  962. TRUE,
  963. MmGetSessionId (Child));
  964. PsDereferencePrimaryTokenEx (Parent, ParentToken);
  965. if (NT_SUCCESS(Status)) {
  966. ObInitializeFastReference (&Child->Token,
  967. NewToken);
  968. }
  969. } else {
  970. //
  971. // Reference and assign the boot token
  972. //
  973. // The use of a single boot access token assumes there is
  974. // exactly one parentless process in the system - the initial
  975. // process. If this ever changes, this code will need to change
  976. // to match the new condition (so that a token doesn't end up
  977. // being shared by multiple processes.
  978. //
  979. ObInitializeFastReference (&Child->Token, NULL);
  980. SeAssignPrimaryToken (Child, PspBootAccessToken);
  981. Status = STATUS_SUCCESS;
  982. }
  983. return Status;
  984. }
  985. VOID
  986. PspDeleteProcessSecurity(
  987. IN PEPROCESS Process
  988. )
  989. /*++
  990. Routine Description:
  991. This function cleans up a process's security fields as part of process
  992. deletion. It is assumed no other references to the process can occur
  993. during or after a call to this routine. This enables us to reference
  994. the process security fields without acquiring the lock protecting those
  995. fields.
  996. NOTE: It may be desirable to add auditing capability to this routine
  997. at some point.
  998. Arguments:
  999. Process - A pointer to the process being deleted.
  1000. Return Value:
  1001. None.
  1002. --*/
  1003. {
  1004. PAGED_CODE();
  1005. //
  1006. // If we are deleting a process that didn't successfully complete
  1007. // process initialization, then there may be no token associated
  1008. // with it yet.
  1009. //
  1010. if (!ExFastRefObjectNull (Process->Token)) {
  1011. SeDeassignPrimaryToken (Process);
  1012. }
  1013. return;
  1014. }
  1015. NTSTATUS
  1016. PspAssignPrimaryToken(
  1017. IN PEPROCESS Process,
  1018. IN HANDLE Token OPTIONAL,
  1019. IN PACCESS_TOKEN TokenPointer OPTIONAL
  1020. )
  1021. /*++
  1022. Routine Description:
  1023. This function performs the security portions of primary token assignment.
  1024. It is expected that the proper access to the process and thread objects,
  1025. as well as necessary privilege, has already been established.
  1026. A primary token can only be replaced if the process has no threads, or
  1027. has one thread. This is because the thread objects point to the primary
  1028. token and must have those pointers updated when the primary token is
  1029. changed. This is only expected to be necessary at logon time, when
  1030. the process is in its infancy and either has zero threads or maybe one
  1031. inactive thread.
  1032. If the assignment is successful, the old token is dereferenced and the
  1033. new one is referenced.
  1034. Arguments:
  1035. Process - A pointer to the process whose primary token is being
  1036. replaced.
  1037. Token - The handle value of the token to be assigned as the primary
  1038. token.
  1039. Return Value:
  1040. STATUS_SUCCESS - Indicates the primary token has been successfully
  1041. replaced.
  1042. STATUS_BAD_TOKEN_TYPE - Indicates the token is not of type TokenPrimary.
  1043. STATUS_TOKEN_IN_USE - Indicates the token is already in use by
  1044. another process.
  1045. Other status may be returned when attempting to reference the token
  1046. object.
  1047. --*/
  1048. {
  1049. NTSTATUS Status;
  1050. PACCESS_TOKEN NewToken, OldToken;
  1051. KPROCESSOR_MODE PreviousMode;
  1052. PETHREAD CurrentThread;
  1053. PAGED_CODE();
  1054. CurrentThread = PsGetCurrentThread ();
  1055. if (TokenPointer == NULL) {
  1056. PreviousMode = KeGetPreviousModeByThread(&CurrentThread->Tcb);
  1057. //
  1058. // Reference the specified token, and make sure it can be assigned
  1059. // as a primary token.
  1060. //
  1061. Status = ObReferenceObjectByHandle (Token,
  1062. TOKEN_ASSIGN_PRIMARY,
  1063. SeTokenObjectType,
  1064. PreviousMode,
  1065. &NewToken,
  1066. NULL);
  1067. if (!NT_SUCCESS (Status)) {
  1068. return Status;
  1069. }
  1070. } else {
  1071. NewToken = TokenPointer;
  1072. }
  1073. //
  1074. // This routine makes sure the NewToken is suitable for assignment
  1075. // as a primary token.
  1076. //
  1077. Status = SeExchangePrimaryToken (Process, NewToken, &OldToken);
  1078. //
  1079. // Acquire and release the process security lock to force any slow
  1080. // referencers out of the slow path.
  1081. //
  1082. PspLockProcessSecurityExclusive (Process, CurrentThread);
  1083. PspUnlockProcessSecurityExclusive (Process, CurrentThread);
  1084. //
  1085. // Free the old token (we don't need it).
  1086. // This can't be done while the security fields are locked.
  1087. //
  1088. if (NT_SUCCESS (Status)) {
  1089. ObDereferenceObject (OldToken);
  1090. }
  1091. //
  1092. // Undo the handle reference
  1093. //
  1094. if (TokenPointer == NULL) {
  1095. ObDereferenceObject (NewToken);
  1096. }
  1097. return Status;
  1098. }
  1099. VOID
  1100. PspInitializeThreadSecurity(
  1101. IN PEPROCESS Process,
  1102. IN PETHREAD Thread
  1103. )
  1104. /*++
  1105. Routine Description:
  1106. This function initializes a new thread's security fields.
  1107. Arguments:
  1108. Process - Points to the process the thread belongs to.
  1109. Thread - Points to the thread object being initialized.
  1110. Return Value:
  1111. None.
  1112. --*/
  1113. {
  1114. PAGED_CODE();
  1115. UNREFERENCED_PARAMETER (Process);
  1116. //
  1117. // Initially not impersonating anyone. This is not currently called as we zero out the entire thread at create time anyway
  1118. //
  1119. Thread->ImpersonationInfo = NULL;
  1120. PS_CLEAR_BITS (&Thread->CrossThreadFlags, PS_CROSS_THREAD_FLAGS_IMPERSONATING);
  1121. return;
  1122. }
  1123. VOID
  1124. PspDeleteThreadSecurity(
  1125. IN PETHREAD Thread
  1126. )
  1127. /*++
  1128. Routine Description:
  1129. This function cleans up a thread's security fields as part of thread
  1130. deletion. It is assumed no other references to the thread can occur
  1131. during or after a call to this routine, so no locking is necessary
  1132. to access the thread security fields.
  1133. Arguments:
  1134. Thread - A pointer to the thread being deleted.
  1135. Return Value:
  1136. None.
  1137. --*/
  1138. {
  1139. PPS_IMPERSONATION_INFORMATION ImpersonationInfo;
  1140. PAGED_CODE();
  1141. ImpersonationInfo = Thread->ImpersonationInfo;
  1142. //
  1143. // clean-up client information, if there is any.
  1144. //
  1145. if (PS_IS_THREAD_IMPERSONATING (Thread)) {
  1146. ObDereferenceObject (ImpersonationInfo->Token);
  1147. }
  1148. if (ImpersonationInfo != NULL) {
  1149. ExFreePoolWithTag (ImpersonationInfo, 'mIsP'|PROTECTED_POOL);
  1150. PS_CLEAR_BITS (&Thread->CrossThreadFlags, PS_CROSS_THREAD_FLAGS_IMPERSONATING);
  1151. Thread->ImpersonationInfo = NULL;
  1152. }
  1153. return;
  1154. }
  1155. NTSTATUS
  1156. PspWriteTebImpersonationInfo (
  1157. IN PETHREAD Thread,
  1158. IN PETHREAD CurrentThread
  1159. )
  1160. /*++
  1161. Routine Description:
  1162. This function updates the thread TEB fields to reflect the impersonation status
  1163. of the thread.
  1164. Arguments:
  1165. Thread - A pointer to the thread whose impersonation token has been changed
  1166. CurrentThread - The current thread
  1167. Return Value:
  1168. NTSTATUS - Status of operation
  1169. --*/
  1170. {
  1171. PTEB Teb;
  1172. BOOLEAN AttachedToProcess = FALSE;
  1173. PEPROCESS ThreadProcess;
  1174. BOOLEAN Impersonating;
  1175. KAPC_STATE ApcState;
  1176. PAGED_CODE();
  1177. ASSERT (CurrentThread == PsGetCurrentThread ());
  1178. ThreadProcess = THREAD_TO_PROCESS (Thread);
  1179. Teb = Thread->Tcb.Teb;
  1180. if (Teb != NULL) {
  1181. if (PsGetCurrentProcessByThread (CurrentThread) != ThreadProcess) {
  1182. KeStackAttachProcess (&ThreadProcess->Pcb, &ApcState);
  1183. AttachedToProcess = TRUE;
  1184. }
  1185. //
  1186. // We are doing a cross thread TEB reference here. Protect against the TEB being freed and used by
  1187. // somebody else.
  1188. //
  1189. if (Thread == CurrentThread || ExAcquireRundownProtection (&Thread->RundownProtect)) {
  1190. while (1) {
  1191. Impersonating = (BOOLEAN) PS_IS_THREAD_IMPERSONATING (Thread);
  1192. //
  1193. // The TEB may still raise an exception in low memory conditions so we need try/except here
  1194. //
  1195. try {
  1196. if (Impersonating) {
  1197. Teb->ImpersonationLocale = (LCID)-1;
  1198. Teb->IsImpersonating = 1;
  1199. } else {
  1200. Teb->ImpersonationLocale = (LCID) 0;
  1201. Teb->IsImpersonating = 0;
  1202. }
  1203. } except (EXCEPTION_EXECUTE_HANDLER) {
  1204. }
  1205. KeMemoryBarrier ();
  1206. if (Impersonating == (BOOLEAN) PS_IS_THREAD_IMPERSONATING (Thread)) {
  1207. break;
  1208. }
  1209. }
  1210. if (Thread != CurrentThread) {
  1211. ExReleaseRundownProtection (&Thread->RundownProtect);
  1212. }
  1213. }
  1214. if (AttachedToProcess) {
  1215. KeUnstackDetachProcess (&ApcState);
  1216. }
  1217. }
  1218. return STATUS_SUCCESS;
  1219. }
  1220. NTSTATUS
  1221. PsAssignImpersonationToken(
  1222. IN PETHREAD Thread,
  1223. IN HANDLE Token
  1224. )
  1225. /*++
  1226. Routine Description:
  1227. This function performs the security portions of establishing an
  1228. impersonation token. This routine is expected to be used only in
  1229. the case where the subject has asked for impersonation explicitly
  1230. providing an impersonation token. Other services are provided for
  1231. use by communication session layers that need to establish an
  1232. impersonation on a server's behalf.
  1233. It is expected that the proper access to the thread object has already
  1234. been established.
  1235. The following rules apply:
  1236. 1) The caller must have TOKEN_IMPERSONATE access to the token
  1237. for any action to be taken.
  1238. 2) If the token may NOT be used for impersonation (e.g., not an
  1239. impersonation token) no action is taken.
  1240. 3) Otherwise, any existing impersonation token is dereferenced and
  1241. the new token is established as the impersonation token.
  1242. Arguments:
  1243. Thread - A pointer to the thread whose impersonation token is being
  1244. set.
  1245. Token - The handle value of the token to be assigned as the impersonation
  1246. token. If this value is NULL, then current impersonation (if any)
  1247. is terminated and no new impersonation is established.
  1248. Return Value:
  1249. STATUS_SUCCESS - Indicates the primary token has been successfully
  1250. replaced.
  1251. STATUS_BAD_TOKEN_TYPE - Indicates the token is not of type
  1252. TokenImpersonation.
  1253. Other status may be returned when attempting to reference the token
  1254. object.
  1255. --*/
  1256. {
  1257. NTSTATUS Status;
  1258. PACCESS_TOKEN NewToken;
  1259. KPROCESSOR_MODE PreviousMode;
  1260. SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
  1261. PETHREAD CurrentThread;
  1262. PAGED_CODE();
  1263. CurrentThread = PsGetCurrentThread ();
  1264. if (!ARGUMENT_PRESENT (Token)) {
  1265. PsRevertThreadToSelf (Thread);
  1266. Status = STATUS_SUCCESS;
  1267. } else {
  1268. PreviousMode = KeGetPreviousModeByThread (&CurrentThread->Tcb);
  1269. //
  1270. // Reference the specified token for TOKEN_IMPERSONATE access
  1271. //
  1272. Status = ObReferenceObjectByHandle (Token,
  1273. TOKEN_IMPERSONATE,
  1274. SeTokenObjectType,
  1275. PreviousMode,
  1276. &NewToken,
  1277. NULL);
  1278. if (!NT_SUCCESS (Status)) {
  1279. return Status;
  1280. }
  1281. //
  1282. // Make sure the token is an impersonation token.
  1283. //
  1284. if (SeTokenType (NewToken) != TokenImpersonation) {
  1285. ObDereferenceObject (NewToken);
  1286. return STATUS_BAD_TOKEN_TYPE;
  1287. }
  1288. ImpersonationLevel = SeTokenImpersonationLevel (NewToken);
  1289. //
  1290. // The rest can be done by PsImpersonateClient.
  1291. //
  1292. // PsImpersonateClient will reference the passed token
  1293. // on success.
  1294. //
  1295. Status = PsImpersonateClient (Thread,
  1296. NewToken,
  1297. FALSE, // CopyOnOpen
  1298. FALSE, // EffectiveOnly
  1299. ImpersonationLevel);
  1300. //
  1301. // Dereference the passed token.
  1302. //
  1303. //
  1304. ObDereferenceObject (NewToken);
  1305. }
  1306. return Status;
  1307. }
  1308. #undef PsDereferencePrimaryToken
  1309. #pragma alloc_text(PAGE, PsDereferencePrimaryToken)
  1310. VOID
  1311. PsDereferencePrimaryToken(
  1312. IN PACCESS_TOKEN PrimaryToken
  1313. )
  1314. /*++
  1315. Routine Description:
  1316. Returns the reference obtained via PsReferencePrimaryToken
  1317. Arguments:
  1318. Returns the reference
  1319. Return Value:
  1320. None.
  1321. --*/
  1322. {
  1323. PAGED_CODE();
  1324. ObDereferenceObject (PrimaryToken);
  1325. }
  1326. #undef PsDereferenceImpersonationToken
  1327. #pragma alloc_text(PAGE, PsDereferenceImpersonationToken)
  1328. VOID
  1329. PsDereferenceImpersonationToken(
  1330. IN PACCESS_TOKEN ImpersonationToken
  1331. )
  1332. /*++
  1333. Routine Description:
  1334. Returns the reference obtained via PsReferenceImpersonationToken
  1335. Arguments:
  1336. Returns the reference
  1337. Return Value:
  1338. None.
  1339. --*/
  1340. {
  1341. PAGED_CODE();
  1342. if (ImpersonationToken != NULL) {
  1343. ObDereferenceObject (ImpersonationToken);
  1344. }
  1345. }