f696d0f3e51c20c069e11e7374c42d4595127774
[reactos.git] / ntoskrnl / ps / security.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ps/security.c
5 * PURPOSE: Process Manager: Process/Thread Security
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Eric Kohl
8 * Thomas Weidenmueller (w3seek@reactos.org)
9 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <debug.h>
16
17 PTOKEN PspBootAccessToken;
18
19 VOID
20 NTAPI
21 SeAssignPrimaryToken(
22 IN PEPROCESS Process,
23 IN PTOKEN Token
24 );
25
26 /* PRIVATE FUNCTIONS *********************************************************/
27
28 VOID
29 NTAPI
30 PspDeleteProcessSecurity(IN PEPROCESS Process)
31 {
32 PAGED_CODE();
33 PSTRACE(PS_SECURITY_DEBUG, "Process: %p\n", Process);
34
35 /* Check if we have a token */
36 if (Process->Token.Object)
37 {
38 /* Deassign it */
39 SeDeassignPrimaryToken(Process);
40 Process->Token.Object = NULL;
41 }
42 }
43
44 VOID
45 NTAPI
46 PspDeleteThreadSecurity(IN PETHREAD Thread)
47 {
48 PPS_IMPERSONATION_INFORMATION ImpersonationInfo = Thread->ImpersonationInfo;
49 PAGED_CODE();
50 PSTRACE(PS_SECURITY_DEBUG, "Thread: %p\n", Thread);
51
52 /* Check if we have active impersonation info */
53 if (Thread->ActiveImpersonationInfo)
54 {
55 /* Dereference its token */
56 ObDereferenceObject(ImpersonationInfo->Token);
57 }
58
59 /* Check if we have impersonation info */
60 if (ImpersonationInfo)
61 {
62 /* Free it */
63 ExFreePool(ImpersonationInfo);
64 PspClearCrossThreadFlag(Thread, CT_ACTIVE_IMPERSONATION_INFO_BIT);
65 Thread->ImpersonationInfo = NULL;
66 }
67 }
68
69 NTSTATUS
70 NTAPI
71 PspInitializeProcessSecurity(IN PEPROCESS Process,
72 IN PEPROCESS Parent OPTIONAL)
73 {
74 NTSTATUS Status = STATUS_SUCCESS;
75 PTOKEN NewToken, ParentToken;
76 PAGED_CODE();
77 PSTRACE(PS_SECURITY_DEBUG, "Process: %p\n", Process);
78
79 /* If we have a parent, then duplicate the Token */
80 if (Parent)
81 {
82 /* Get the Parent Token */
83 ParentToken = PsReferencePrimaryToken(Parent);
84
85 /* Duplicate it */
86 Status = SeSubProcessToken(ParentToken,
87 &NewToken,
88 TRUE,
89 MmGetSessionId(Process));
90
91 /* Dereference the Parent */
92 ObFastDereferenceObject(&Parent->Token, ParentToken);
93
94 /* Set the new Token */
95 if (NT_SUCCESS(Status))
96 {
97 /* Initailize the fast reference */
98 ObInitializeFastReference(&Process->Token, NewToken);
99 }
100 }
101 else
102 {
103 /* No parent, assign the Boot Token */
104 ObInitializeFastReference(&Process->Token, NULL);
105 SeAssignPrimaryToken(Process, PspBootAccessToken);
106 }
107
108 /* Return to caller */
109 return Status;
110 }
111
112 NTSTATUS
113 NTAPI
114 PspWriteTebImpersonationInfo(IN PETHREAD Thread,
115 IN PETHREAD CurrentThread)
116 {
117 PEPROCESS Process;
118 PTEB Teb;
119 BOOLEAN Attached = FALSE;
120 BOOLEAN IsImpersonating;
121 KAPC_STATE ApcState;
122 PAGED_CODE();
123 PSTRACE(PS_SECURITY_DEBUG, "Thread: %p\n", Thread);
124
125 /* Sanity check */
126 ASSERT(CurrentThread == PsGetCurrentThread());
127
128 /* Get process and TEB */
129 Process = Thread->ThreadsProcess;
130 Teb = Thread->Tcb.Teb;
131 if (Teb)
132 {
133 /* Check if we're not in the right process */
134 if (Thread->Tcb.ApcState.Process != &Process->Pcb)
135 {
136 /* Attach to the process */
137 KeStackAttachProcess(&Process->Pcb, &ApcState);
138 Attached = TRUE;
139 }
140
141 /* Check if we're in a different thread or acquire rundown */
142 if ((Thread == CurrentThread) ||
143 (ExAcquireRundownProtection(&Thread->RundownProtect)))
144 {
145 /* Check if the thread is impersonating */
146 IsImpersonating = (BOOLEAN)Thread->ActiveImpersonationInfo;
147 if (IsImpersonating)
148 {
149 /* Set TEB data */
150 Teb->ImpersonationLocale = -1;
151 Teb->IsImpersonating = 1;
152 }
153 else
154 {
155 /* Set TEB data */
156 Teb->ImpersonationLocale = 0;
157 Teb->IsImpersonating = 0;
158 }
159 }
160
161 /* Check if we're in a different thread */
162 if (Thread != CurrentThread)
163 {
164 /* Release protection */
165 ExReleaseRundownProtection(&Thread->RundownProtect);
166 }
167
168 /* Detach */
169 if (Attached) KeUnstackDetachProcess(&ApcState);
170 }
171
172 /* Return to caller */
173 return STATUS_SUCCESS;
174 }
175
176 NTSTATUS
177 NTAPI
178 PspAssignPrimaryToken(IN PEPROCESS Process,
179 IN HANDLE Token,
180 IN PACCESS_TOKEN AccessToken OPTIONAL)
181 {
182 PACCESS_TOKEN NewToken = AccessToken, OldToken;
183 NTSTATUS Status;
184 PAGED_CODE();
185 PSTRACE(PS_SECURITY_DEBUG, "Process: %p Token: %p\n", Process, Token);
186
187 /* Check if we don't have a pointer */
188 if (!AccessToken)
189 {
190 /* Reference it from the handle */
191 Status = ObReferenceObjectByHandle(Token,
192 TOKEN_ASSIGN_PRIMARY,
193 SeTokenObjectType,
194 ExGetPreviousMode(),
195 &NewToken,
196 NULL);
197 if (!NT_SUCCESS(Status)) return Status;
198 }
199
200 /* Exchange tokens */
201 Status = SeExchangePrimaryToken(Process, NewToken, &OldToken);
202
203 /* Acquire and release the lock */
204 PspLockProcessSecurityExclusive(Process);
205 PspUnlockProcessSecurityExclusive(Process);
206
207 /* Dereference Tokens and Return */
208 if (NT_SUCCESS(Status)) ObDereferenceObject(OldToken);
209 if (!AccessToken) ObDereferenceObject(NewToken);
210 return Status;
211 }
212
213 NTSTATUS
214 NTAPI
215 PspSetPrimaryToken(IN PEPROCESS Process,
216 IN HANDLE TokenHandle OPTIONAL,
217 IN PACCESS_TOKEN Token OPTIONAL)
218 {
219 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
220 BOOLEAN IsChild;
221 PACCESS_TOKEN NewToken = Token;
222 NTSTATUS Status, AccessStatus;
223 BOOLEAN Result, SdAllocated;
224 PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
225 SECURITY_SUBJECT_CONTEXT SubjectContext;
226 PSTRACE(PS_SECURITY_DEBUG, "Process: %p Token: %p\n", Process, Token);
227
228 /* Make sure we got a handle */
229 if (TokenHandle)
230 {
231 /* Reference it */
232 Status = ObReferenceObjectByHandle(TokenHandle,
233 TOKEN_ASSIGN_PRIMARY,
234 SeTokenObjectType,
235 PreviousMode,
236 (PVOID*)&NewToken,
237 NULL);
238 if (!NT_SUCCESS(Status)) return Status;
239 }
240
241 /* Check if this is a child */
242 Status = SeIsTokenChild(NewToken, &IsChild);
243 if (!NT_SUCCESS(Status))
244 {
245 /* Failed, dereference */
246 if (TokenHandle) ObDereferenceObject(NewToken);
247 return Status;
248 }
249
250 /* Check if this was an independent token */
251 if (!IsChild)
252 {
253 /* Make sure we have the privilege to assign a new one */
254 if (!SeSinglePrivilegeCheck(SeAssignPrimaryTokenPrivilege,
255 PreviousMode))
256 {
257 /* Failed, dereference */
258 if (TokenHandle) ObDereferenceObject(NewToken);
259 return STATUS_PRIVILEGE_NOT_HELD;
260 }
261 }
262
263 /* Assign the token */
264 Status = PspAssignPrimaryToken(Process, NULL, NewToken);
265 if (NT_SUCCESS(Status))
266 {
267 /*
268 * We need to completely reverify if the process still has access to
269 * itself under this new token.
270 */
271 Status = ObGetObjectSecurity(Process,
272 &SecurityDescriptor,
273 &SdAllocated);
274 if (NT_SUCCESS(Status))
275 {
276 /* Setup the security context */
277 SubjectContext.ProcessAuditId = Process;
278 SubjectContext.PrimaryToken = PsReferencePrimaryToken(Process);
279 SubjectContext.ClientToken = NULL;
280
281 /* Do the access check */
282 Result = SeAccessCheck(SecurityDescriptor,
283 &SubjectContext,
284 FALSE,
285 MAXIMUM_ALLOWED,
286 0,
287 NULL,
288 &PsProcessType->TypeInfo.GenericMapping,
289 PreviousMode,
290 &Process->GrantedAccess,
291 &AccessStatus);
292
293 /* Dereference the token and let go the SD */
294 ObFastDereferenceObject(&Process->Token,
295 SubjectContext.PrimaryToken);
296 ObReleaseObjectSecurity(SecurityDescriptor, SdAllocated);
297
298 /* Remove access if it failed */
299 if (!Result) Process->GrantedAccess = 0;
300
301 /* Setup granted access */
302 Process->GrantedAccess |= (PROCESS_VM_OPERATION |
303 PROCESS_VM_READ |
304 PROCESS_VM_WRITE |
305 PROCESS_QUERY_INFORMATION |
306 PROCESS_TERMINATE |
307 PROCESS_CREATE_THREAD |
308 PROCESS_DUP_HANDLE |
309 PROCESS_CREATE_PROCESS |
310 PROCESS_SET_INFORMATION |
311 STANDARD_RIGHTS_ALL |
312 PROCESS_SET_QUOTA);
313 }
314 }
315
316 /* Dereference the token */
317 if (TokenHandle) ObDereferenceObject(NewToken);
318 return Status;
319 }
320
321 /* FUNCTIONS *****************************************************************/
322
323 /*
324 * @implemented
325 */
326 NTSTATUS
327 NTAPI
328 NtOpenProcessToken(IN HANDLE ProcessHandle,
329 IN ACCESS_MASK DesiredAccess,
330 OUT PHANDLE TokenHandle)
331 {
332 /* Call the newer API */
333 return NtOpenProcessTokenEx(ProcessHandle,
334 DesiredAccess,
335 0,
336 TokenHandle);
337 }
338
339 /*
340 * @implemented
341 */
342 NTSTATUS
343 NTAPI
344 NtOpenProcessTokenEx(IN HANDLE ProcessHandle,
345 IN ACCESS_MASK DesiredAccess,
346 IN ULONG HandleAttributes,
347 OUT PHANDLE TokenHandle)
348 {
349 PACCESS_TOKEN Token;
350 HANDLE hToken;
351 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
352 NTSTATUS Status;
353 PAGED_CODE();
354 PSTRACE(PS_SECURITY_DEBUG,
355 "Process: %p DesiredAccess: %lx\n", ProcessHandle, DesiredAccess);
356
357 /* Check if caller was user-mode */
358 if (PreviousMode != KernelMode)
359 {
360 /* Enter SEH for probing */
361 _SEH2_TRY
362 {
363 /* Probe the token handle */
364 ProbeForWriteHandle(TokenHandle);
365 }
366 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
367 {
368 /* Return the exception code */
369 _SEH2_YIELD(return _SEH2_GetExceptionCode());
370 }
371 _SEH2_END;
372 }
373
374 /* Validate object attributes */
375 HandleAttributes = ObpValidateAttributes(HandleAttributes, PreviousMode);
376
377 /* Open the process token */
378 Status = PsOpenTokenOfProcess(ProcessHandle, &Token);
379 if (NT_SUCCESS(Status))
380 {
381 /* Reference it by handle and dereference the pointer */
382 Status = ObOpenObjectByPointer(Token,
383 HandleAttributes,
384 NULL,
385 DesiredAccess,
386 SeTokenObjectType,
387 PreviousMode,
388 &hToken);
389 ObDereferenceObject(Token);
390
391 /* Make sure we got a handle */
392 if (NT_SUCCESS(Status))
393 {
394 /* Enter SEH for write */
395 _SEH2_TRY
396 {
397 /* Return the handle */
398 *TokenHandle = hToken;
399 }
400 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
401 {
402 /* Get exception code */
403 Status = _SEH2_GetExceptionCode();
404 }
405 _SEH2_END;
406 }
407 }
408
409 /* Return status */
410 return Status;
411 }
412
413 /*
414 * @implemented
415 */
416 PACCESS_TOKEN
417 NTAPI
418 PsReferencePrimaryToken(PEPROCESS Process)
419 {
420 PACCESS_TOKEN Token;
421 PAGED_CODE();
422 PSTRACE(PS_SECURITY_DEBUG, "Process: %p\n", Process);
423
424 /* Fast Reference the Token */
425 Token = ObFastReferenceObject(&Process->Token);
426
427 /* Check if we got the Token or if we got locked */
428 if (!Token)
429 {
430 /* Lock the Process */
431 PspLockProcessSecurityShared(Process);
432
433 /* Do a Locked Fast Reference */
434 Token = ObFastReferenceObjectLocked(&Process->Token);
435
436 /* Unlock the Process */
437 PspUnlockProcessSecurityShared(Process);
438 }
439
440 /* Return the Token */
441 return Token;
442 }
443
444 /*
445 * @implemented
446 */
447 NTSTATUS
448 NTAPI
449 PsOpenTokenOfProcess(IN HANDLE ProcessHandle,
450 OUT PACCESS_TOKEN* Token)
451 {
452 PEPROCESS Process;
453 NTSTATUS Status;
454 PAGED_CODE();
455 PSTRACE(PS_SECURITY_DEBUG, "Process: %p\n", ProcessHandle);
456
457 /* Get the Token */
458 Status = ObReferenceObjectByHandle(ProcessHandle,
459 PROCESS_QUERY_INFORMATION,
460 PsProcessType,
461 ExGetPreviousMode(),
462 (PVOID*)&Process,
463 NULL);
464 if (NT_SUCCESS(Status))
465 {
466 /* Reference the token and dereference the process */
467 *Token = PsReferencePrimaryToken(Process);
468 ObDereferenceObject(Process);
469 }
470
471 /* Return */
472 return Status;
473 }
474
475 /*
476 * @implemented
477 */
478 NTSTATUS
479 NTAPI
480 PsAssignImpersonationToken(IN PETHREAD Thread,
481 IN HANDLE TokenHandle)
482 {
483 PACCESS_TOKEN Token;
484 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
485 NTSTATUS Status;
486 PAGED_CODE();
487 PSTRACE(PS_SECURITY_DEBUG, "Thread: %p Token: %p\n", Thread, TokenHandle);
488
489 /* Check if we were given a handle */
490 if (!TokenHandle)
491 {
492 /* Undo impersonation */
493 PsRevertThreadToSelf(Thread);
494 return STATUS_SUCCESS;
495 }
496
497 /* Get the token object */
498 Status = ObReferenceObjectByHandle(TokenHandle,
499 TOKEN_IMPERSONATE,
500 SeTokenObjectType,
501 KeGetPreviousMode(),
502 (PVOID*)&Token,
503 NULL);
504 if (!NT_SUCCESS(Status)) return(Status);
505
506 /* Make sure it's an impersonation token */
507 if (SeTokenType(Token) != TokenImpersonation)
508 {
509 /* Fail */
510 ObDereferenceObject(Token);
511 return STATUS_BAD_TOKEN_TYPE;
512 }
513
514 /* Get the impersonation level */
515 ImpersonationLevel = SeTokenImpersonationLevel(Token);
516
517 /* Call the impersonation API */
518 Status = PsImpersonateClient(Thread,
519 Token,
520 FALSE,
521 FALSE,
522 ImpersonationLevel);
523
524 /* Dereference the token and return status */
525 ObDereferenceObject(Token);
526 return Status;
527 }
528
529 /*
530 * @implemented
531 */
532 VOID
533 NTAPI
534 PsRevertToSelf(VOID)
535 {
536 /* Call the per-thread API */
537 PAGED_CODE();
538 PsRevertThreadToSelf(PsGetCurrentThread());
539 }
540
541 /*
542 * @implemented
543 */
544 VOID
545 NTAPI
546 PsRevertThreadToSelf(IN PETHREAD Thread)
547 {
548 PTOKEN Token = NULL;
549 PAGED_CODE();
550 PSTRACE(PS_SECURITY_DEBUG, "Thread: %p\n", Thread);
551
552 /* Make sure we had impersonation information */
553 if (Thread->ActiveImpersonationInfo)
554 {
555 /* Lock the thread security */
556 PspLockThreadSecurityExclusive(Thread);
557
558 /* Make sure it's still active */
559 if (Thread->ActiveImpersonationInfo)
560 {
561 /* Disable impersonation */
562 PspClearCrossThreadFlag(Thread, CT_ACTIVE_IMPERSONATION_INFO_BIT);
563
564 /* Get the token */
565 Token = Thread->ImpersonationInfo->Token;
566 }
567
568 /* Release thread security */
569 PspUnlockThreadSecurityExclusive(Thread);
570
571 /* Check if we had a token */
572 if (Token)
573 {
574 /* Dereference the impersonation token */
575 ObDereferenceObject(Token);
576
577 /* Write impersonation info to the TEB */
578 PspWriteTebImpersonationInfo(Thread, PsGetCurrentThread());
579 }
580 }
581 }
582
583 /*
584 * @implemented
585 */
586 NTSTATUS
587 NTAPI
588 PsImpersonateClient(IN PETHREAD Thread,
589 IN PACCESS_TOKEN Token,
590 IN BOOLEAN CopyOnOpen,
591 IN BOOLEAN EffectiveOnly,
592 IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
593 {
594 PPS_IMPERSONATION_INFORMATION Impersonation, OldData;
595 PTOKEN OldToken = NULL;
596 PAGED_CODE();
597 PSTRACE(PS_SECURITY_DEBUG, "Thread: %p, Token: %p\n", Thread, Token);
598
599 /* Check if we don't have a token */
600 if (!Token)
601 {
602 /* Make sure we're impersonating */
603 if (Thread->ActiveImpersonationInfo)
604 {
605 /* We seem to be, lock the thread */
606 PspLockThreadSecurityExclusive(Thread);
607
608 /* Make sure we're still impersonating */
609 if (Thread->ActiveImpersonationInfo)
610 {
611 /* Disable impersonation */
612 PspClearCrossThreadFlag(Thread,
613 CT_ACTIVE_IMPERSONATION_INFO_BIT);
614
615 /* Get the token */
616 OldToken = Thread->ImpersonationInfo->Token;
617 }
618
619 /* Unlock the process and write TEB information */
620 PspUnlockThreadSecurityExclusive(Thread);
621 PspWriteTebImpersonationInfo(Thread, PsGetCurrentThread());
622 }
623 }
624 else
625 {
626 /* Check if we have impersonation info */
627 Impersonation = Thread->ImpersonationInfo;
628 if (!Impersonation)
629 {
630 /* We need to allocate a new one */
631 Impersonation = ExAllocatePoolWithTag(PagedPool,
632 sizeof(*Impersonation),
633 TAG_PS_IMPERSONATION);
634 if (!Impersonation) return STATUS_INSUFFICIENT_RESOURCES;
635
636 /* Update the pointer */
637 OldData = InterlockedCompareExchangePointer((PVOID*)&Thread->
638 ImpersonationInfo,
639 Impersonation,
640 NULL);
641 if (OldData)
642 {
643 /* Someone beat us to it, free our copy */
644 ExFreePoolWithTag(Impersonation, TAG_PS_IMPERSONATION);
645 Impersonation = OldData;
646 }
647 }
648
649 /* Check if this is a job, which we don't support yet */
650 if (Thread->ThreadsProcess->Job) ASSERT(FALSE);
651
652 /* Lock thread security */
653 PspLockThreadSecurityExclusive(Thread);
654
655 /* Check if we're impersonating */
656 if (Thread->ActiveImpersonationInfo)
657 {
658 /* Get the token */
659 OldToken = Impersonation->Token;
660 }
661 else
662 {
663 /* Otherwise, enable impersonation */
664 PspSetCrossThreadFlag(Thread, CT_ACTIVE_IMPERSONATION_INFO_BIT);
665 }
666
667 /* Now fill it out */
668 Impersonation->ImpersonationLevel = ImpersonationLevel;
669 Impersonation->CopyOnOpen = CopyOnOpen;
670 Impersonation->EffectiveOnly = EffectiveOnly;
671 Impersonation->Token = Token;
672 ObReferenceObject(Token);
673
674 /* Unlock the thread */
675 PspUnlockThreadSecurityExclusive(Thread);
676
677 /* Write impersonation info to the TEB */
678 PspWriteTebImpersonationInfo(Thread, PsGetCurrentThread());
679 }
680
681 /* Dereference the token and return success */
682 if (OldToken) PsDereferenceImpersonationToken(OldToken);
683 return STATUS_SUCCESS;
684 }
685
686 /*
687 * @implemented
688 */
689 PACCESS_TOKEN
690 NTAPI
691 PsReferenceEffectiveToken(IN PETHREAD Thread,
692 OUT IN PTOKEN_TYPE TokenType,
693 OUT PBOOLEAN EffectiveOnly,
694 OUT PSECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
695 {
696 PEPROCESS Process;
697 PACCESS_TOKEN Token = NULL;
698
699 PAGED_CODE();
700
701 PSTRACE(PS_SECURITY_DEBUG,
702 "Thread: %p, TokenType: %p\n", Thread, TokenType);
703
704 /* Check if we don't have impersonation info */
705 Process = Thread->ThreadsProcess;
706 if (Thread->ActiveImpersonationInfo)
707 {
708 /* Lock the Process */
709 PspLockProcessSecurityShared(Process);
710
711 /* Make sure impersonation is still active */
712 if (Thread->ActiveImpersonationInfo)
713 {
714 /* Get the token */
715 Token = Thread->ImpersonationInfo->Token;
716 ObReferenceObject(Token);
717
718 /* Return data to caller */
719 *TokenType = TokenImpersonation;
720 *EffectiveOnly = Thread->ImpersonationInfo->EffectiveOnly;
721 *ImpersonationLevel = Thread->ImpersonationInfo->ImpersonationLevel;
722
723 /* Unlock the Process */
724 PspUnlockProcessSecurityShared(Process);
725 return Token;
726 }
727
728 /* Unlock the Process */
729 PspUnlockProcessSecurityShared(Process);
730 }
731
732 /* Fast Reference the Token */
733 Token = ObFastReferenceObject(&Process->Token);
734
735 /* Check if we got the Token or if we got locked */
736 if (!Token)
737 {
738 /* Lock the Process */
739 PspLockProcessSecurityShared(Process);
740
741 /* Do a Locked Fast Reference */
742 Token = ObFastReferenceObjectLocked(&Process->Token);
743
744 /* Unlock the Process */
745 PspUnlockProcessSecurityShared(Process);
746 }
747
748 /* Return the token */
749 *TokenType = TokenPrimary;
750 *EffectiveOnly = FALSE;
751 // NOTE: ImpersonationLevel is left untouched on purpose!
752 return Token;
753 }
754
755 /*
756 * @implemented
757 */
758 PACCESS_TOKEN
759 NTAPI
760 PsReferenceImpersonationToken(IN PETHREAD Thread,
761 OUT PBOOLEAN CopyOnOpen,
762 OUT PBOOLEAN EffectiveOnly,
763 OUT PSECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
764 {
765 PTOKEN Token = NULL;
766 PAGED_CODE();
767 PSTRACE(PS_SECURITY_DEBUG, "Thread: %p\n", Thread);
768
769 /* If we don't have impersonation info, just quit */
770 if (!Thread->ActiveImpersonationInfo) return NULL;
771
772 /* Lock the thread */
773 PspLockThreadSecurityShared(Thread);
774
775 /* Make sure we still have active impersonation */
776 if (Thread->ActiveImpersonationInfo)
777 {
778 /* Return data from caller */
779 ObReferenceObject(Thread->ImpersonationInfo->Token);
780 *ImpersonationLevel = Thread->ImpersonationInfo->ImpersonationLevel;
781 *CopyOnOpen = Thread->ImpersonationInfo->CopyOnOpen;
782 *EffectiveOnly = Thread->ImpersonationInfo->EffectiveOnly;
783
784 /* Set the token */
785 Token = Thread->ImpersonationInfo->Token;
786 }
787
788 /* Unlock thread and return impersonation token */
789 PspUnlockThreadSecurityShared(Thread);
790 return Token;
791 }
792
793 #undef PsDereferenceImpersonationToken
794 /*
795 * @implemented
796 */
797 VOID
798 NTAPI
799 PsDereferenceImpersonationToken(IN PACCESS_TOKEN ImpersonationToken)
800 {
801 PAGED_CODE();
802
803 /* If we got a token, dereference it */
804 if (ImpersonationToken) ObDereferenceObject(ImpersonationToken);
805 }
806
807 #undef PsDereferencePrimaryToken
808 /*
809 * @implemented
810 */
811 VOID
812 NTAPI
813 PsDereferencePrimaryToken(IN PACCESS_TOKEN PrimaryToken)
814 {
815 PAGED_CODE();
816
817 /* Dereference the token*/
818 ObDereferenceObject(PrimaryToken);
819 }
820
821 /*
822 * @implemented
823 */
824 BOOLEAN
825 NTAPI
826 PsDisableImpersonation(IN PETHREAD Thread,
827 OUT PSE_IMPERSONATION_STATE ImpersonationState)
828 {
829 PPS_IMPERSONATION_INFORMATION Impersonation = NULL;
830 LONG OldFlags;
831 PAGED_CODE();
832 PSTRACE(PS_SECURITY_DEBUG,
833 "Thread: %p State: %p\n", Thread, ImpersonationState);
834
835 /* Check if we don't have impersonation */
836 if (Thread->ActiveImpersonationInfo)
837 {
838 /* Lock thread security */
839 PspLockThreadSecurityExclusive(Thread);
840
841 /* Disable impersonation */
842 OldFlags = PspClearCrossThreadFlag(Thread,
843 CT_ACTIVE_IMPERSONATION_INFO_BIT);
844
845 /* Make sure nobody disabled it behind our back */
846 if (OldFlags & CT_ACTIVE_IMPERSONATION_INFO_BIT)
847 {
848 /* Copy the old state */
849 Impersonation = Thread->ImpersonationInfo;
850 ImpersonationState->Token = Impersonation->Token;
851 ImpersonationState->CopyOnOpen = Impersonation->CopyOnOpen;
852 ImpersonationState->EffectiveOnly = Impersonation->EffectiveOnly;
853 ImpersonationState->Level = Impersonation->ImpersonationLevel;
854 }
855
856 /* Unlock thread security */
857 PspUnlockThreadSecurityExclusive(Thread);
858
859 /* If we had impersonation info, return true */
860 if (Impersonation) return TRUE;
861 }
862
863 /* Clear everything */
864 ImpersonationState->Token = NULL;
865 ImpersonationState->CopyOnOpen = FALSE;
866 ImpersonationState->EffectiveOnly = FALSE;
867 ImpersonationState->Level = SecurityAnonymous;
868 return FALSE;
869 }
870
871 /*
872 * @implemented
873 */
874 VOID
875 NTAPI
876 PsRestoreImpersonation(IN PETHREAD Thread,
877 IN PSE_IMPERSONATION_STATE ImpersonationState)
878 {
879 PTOKEN Token = NULL;
880 PPS_IMPERSONATION_INFORMATION Impersonation;
881 PAGED_CODE();
882 PSTRACE(PS_SECURITY_DEBUG,
883 "Thread: %p State: %p\n", Thread, ImpersonationState);
884
885 /* Lock thread security */
886 PspLockThreadSecurityExclusive(Thread);
887
888 /* Get the impersonation info */
889 Impersonation = Thread->ImpersonationInfo;
890
891 /* Check if we're impersonating */
892 if (Thread->ActiveImpersonationInfo)
893 {
894 /* Get the token */
895 Token = Impersonation->Token;
896 }
897
898 /* Check if we have an impersonation state */
899 if (ImpersonationState)
900 {
901 /* Fill out the impersonation info */
902 Impersonation->ImpersonationLevel = ImpersonationState->Level;
903 Impersonation->CopyOnOpen = ImpersonationState->CopyOnOpen;
904 Impersonation->EffectiveOnly = ImpersonationState->EffectiveOnly;
905 Impersonation->Token = ImpersonationState->Token;
906
907 /* Enable impersonation */
908 PspSetCrossThreadFlag(Thread, CT_ACTIVE_IMPERSONATION_INFO_BIT);
909 }
910 else
911 {
912 /* Disable impersonation */
913 PspClearCrossThreadFlag(Thread, CT_ACTIVE_IMPERSONATION_INFO_BIT);
914 }
915
916 /* Unlock the thread */
917 PspUnlockThreadSecurityExclusive(Thread);
918
919 /* Dereference the token */
920 if (Token) ObDereferenceObject(Token);
921 }
922
923 NTSTATUS
924 NTAPI
925 NtImpersonateThread(IN HANDLE ThreadHandle,
926 IN HANDLE ThreadToImpersonateHandle,
927 IN PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService)
928 {
929 SECURITY_QUALITY_OF_SERVICE SafeServiceQoS;
930 SECURITY_CLIENT_CONTEXT ClientContext;
931 PETHREAD Thread;
932 PETHREAD ThreadToImpersonate;
933 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
934 NTSTATUS Status;
935 PAGED_CODE();
936 PSTRACE(PS_SECURITY_DEBUG,
937 "Threads: %p %p\n", ThreadHandle, ThreadToImpersonateHandle);
938
939 /* Check if call came from user mode */
940 if (PreviousMode != KernelMode)
941 {
942 /* Enter SEH for probing */
943 _SEH2_TRY
944 {
945 /* Probe QoS */
946 ProbeForRead(SecurityQualityOfService,
947 sizeof(SECURITY_QUALITY_OF_SERVICE),
948 sizeof(ULONG));
949
950 /* Capture it */
951 SafeServiceQoS = *SecurityQualityOfService;
952 SecurityQualityOfService = &SafeServiceQoS;
953 }
954 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
955 {
956 /* Return the exception code */
957 _SEH2_YIELD(return _SEH2_GetExceptionCode());
958 }
959 _SEH2_END;
960 }
961
962 /* Reference the thread */
963 Status = ObReferenceObjectByHandle(ThreadHandle,
964 THREAD_DIRECT_IMPERSONATION,
965 PsThreadType,
966 PreviousMode,
967 (PVOID*)&Thread,
968 NULL);
969 if (NT_SUCCESS(Status))
970 {
971 /* Reference the impersonating thead */
972 Status = ObReferenceObjectByHandle(ThreadToImpersonateHandle,
973 THREAD_IMPERSONATE,
974 PsThreadType,
975 PreviousMode,
976 (PVOID*)&ThreadToImpersonate,
977 NULL);
978 if (NT_SUCCESS(Status))
979 {
980 /* Create a client security context */
981 Status = SeCreateClientSecurity(ThreadToImpersonate,
982 SecurityQualityOfService,
983 0,
984 &ClientContext);
985 if (NT_SUCCESS(Status))
986 {
987 /* Do the impersonation */
988 SeImpersonateClient(&ClientContext, Thread);
989 if (ClientContext.ClientToken)
990 {
991 /* Dereference the client token if we had one */
992 ObDereferenceObject(ClientContext.ClientToken);
993 }
994 }
995
996 /* Dereference the thread to impersonate */
997 ObDereferenceObject(ThreadToImpersonate);
998 }
999
1000 /* Dereference the main thread */
1001 ObDereferenceObject(Thread);
1002 }
1003
1004 /* Return status */
1005 return Status;
1006 }
1007 /* EOF */