Sync with trunk head (part 1 of x)
[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 0);//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 SepTokenObjectType,
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;
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 SepTokenObjectType,
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 /* Open the process token */
375 Status = PsOpenTokenOfProcess(ProcessHandle, &Token);
376 if (NT_SUCCESS(Status))
377 {
378 /* Reference it by handle and dereference the pointer */
379 Status = ObOpenObjectByPointer(Token,
380 HandleAttributes,
381 NULL,
382 DesiredAccess,
383 SepTokenObjectType,
384 PreviousMode,
385 &hToken);
386 ObDereferenceObject(Token);
387
388 /* Make sure we got a handle */
389 if (NT_SUCCESS(Status))
390 {
391 /* Enter SEH for write */
392 _SEH2_TRY
393 {
394 /* Return the handle */
395 *TokenHandle = hToken;
396 }
397 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
398 {
399 /* Get exception code */
400 Status = _SEH2_GetExceptionCode();
401 }
402 _SEH2_END;
403 }
404 }
405
406 /* Return status */
407 return Status;
408 }
409
410 /*
411 * @implemented
412 */
413 PACCESS_TOKEN
414 NTAPI
415 PsReferencePrimaryToken(PEPROCESS Process)
416 {
417 PACCESS_TOKEN Token;
418 PAGED_CODE();
419 PSTRACE(PS_SECURITY_DEBUG, "Process: %p\n", Process);
420
421 /* Fast Reference the Token */
422 Token = ObFastReferenceObject(&Process->Token);
423
424 /* Check if we got the Token or if we got locked */
425 if (!Token)
426 {
427 /* Lock the Process */
428 PspLockProcessSecurityShared(Process);
429
430 /* Do a Locked Fast Reference */
431 Token = ObFastReferenceObjectLocked(&Process->Token);
432
433 /* Unlock the Process */
434 PspUnlockProcessSecurityShared(Process);
435 }
436
437 /* Return the Token */
438 return Token;
439 }
440
441 /*
442 * @implemented
443 */
444 NTSTATUS
445 NTAPI
446 PsOpenTokenOfProcess(IN HANDLE ProcessHandle,
447 OUT PACCESS_TOKEN* Token)
448 {
449 PEPROCESS Process;
450 NTSTATUS Status;
451 PAGED_CODE();
452 PSTRACE(PS_SECURITY_DEBUG, "Process: %p\n", ProcessHandle);
453
454 /* Get the Token */
455 Status = ObReferenceObjectByHandle(ProcessHandle,
456 PROCESS_QUERY_INFORMATION,
457 PsProcessType,
458 ExGetPreviousMode(),
459 (PVOID*)&Process,
460 NULL);
461 if (NT_SUCCESS(Status))
462 {
463 /* Reference the token and dereference the process */
464 *Token = PsReferencePrimaryToken(Process);
465 ObDereferenceObject(Process);
466 }
467
468 /* Return */
469 return Status;
470 }
471
472 /*
473 * @implemented
474 */
475 NTSTATUS
476 NTAPI
477 PsAssignImpersonationToken(IN PETHREAD Thread,
478 IN HANDLE TokenHandle)
479 {
480 PACCESS_TOKEN Token;
481 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
482 NTSTATUS Status;
483 PAGED_CODE();
484 PSTRACE(PS_SECURITY_DEBUG, "Thread: %p Token: %p\n", Thread, TokenHandle);
485
486 /* Check if we were given a handle */
487 if (!TokenHandle)
488 {
489 /* Undo impersonation */
490 PsRevertThreadToSelf(Thread);
491 return STATUS_SUCCESS;
492 }
493
494 /* Get the token object */
495 Status = ObReferenceObjectByHandle(TokenHandle,
496 TOKEN_IMPERSONATE,
497 SepTokenObjectType,
498 KeGetPreviousMode(),
499 (PVOID*)&Token,
500 NULL);
501 if (!NT_SUCCESS(Status)) return(Status);
502
503 /* Make sure it's an impersonation token */
504 if (SeTokenType(Token) != TokenImpersonation)
505 {
506 /* Fail */
507 ObDereferenceObject(Token);
508 return STATUS_BAD_TOKEN_TYPE;
509 }
510
511 /* Get the impersonation level */
512 ImpersonationLevel = SeTokenImpersonationLevel(Token);
513
514 /* Call the impersonation API */
515 Status = PsImpersonateClient(Thread,
516 Token,
517 FALSE,
518 FALSE,
519 ImpersonationLevel);
520
521 /* Dereference the token and return status */
522 ObDereferenceObject(Token);
523 return Status;
524 }
525
526 /*
527 * @implemented
528 */
529 VOID
530 NTAPI
531 PsRevertToSelf(VOID)
532 {
533 /* Call the per-thread API */
534 PAGED_CODE();
535 PsRevertThreadToSelf(PsGetCurrentThread());
536 }
537
538 /*
539 * @implemented
540 */
541 VOID
542 NTAPI
543 PsRevertThreadToSelf(IN PETHREAD Thread)
544 {
545 PTOKEN Token = NULL;
546 PAGED_CODE();
547 PSTRACE(PS_SECURITY_DEBUG, "Thread: %p\n", Thread);
548
549 /* Make sure we had impersonation information */
550 if (Thread->ActiveImpersonationInfo)
551 {
552 /* Lock the thread security */
553 PspLockThreadSecurityExclusive(Thread);
554
555 /* Make sure it's still active */
556 if (Thread->ActiveImpersonationInfo)
557 {
558 /* Disable impersonation */
559 PspClearCrossThreadFlag(Thread, CT_ACTIVE_IMPERSONATION_INFO_BIT);
560
561 /* Get the token */
562 Token = Thread->ImpersonationInfo->Token;
563 }
564
565 /* Release thread security */
566 PspUnlockThreadSecurityExclusive(Thread);
567
568 /* Check if we had a token */
569 if (Token)
570 {
571 /* Dereference the impersonation token */
572 ObDereferenceObject(Token);
573
574 /* Write impersonation info to the TEB */
575 PspWriteTebImpersonationInfo(Thread, PsGetCurrentThread());
576 }
577 }
578 }
579
580 /*
581 * @implemented
582 */
583 NTSTATUS
584 NTAPI
585 PsImpersonateClient(IN PETHREAD Thread,
586 IN PACCESS_TOKEN Token,
587 IN BOOLEAN CopyOnOpen,
588 IN BOOLEAN EffectiveOnly,
589 IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
590 {
591 PPS_IMPERSONATION_INFORMATION Impersonation, OldData;
592 PTOKEN OldToken = NULL;
593 PAGED_CODE();
594 PSTRACE(PS_SECURITY_DEBUG, "Thread: %p, Token: %p\n", Thread, Token);
595
596 /* Check if we don't have a token */
597 if (!Token)
598 {
599 /* Make sure we're impersonating */
600 if (Thread->ActiveImpersonationInfo)
601 {
602 /* We seem to be, lock the thread */
603 PspLockThreadSecurityExclusive(Thread);
604
605 /* Make sure we're still impersonating */
606 if (Thread->ActiveImpersonationInfo)
607 {
608 /* Disable impersonation */
609 PspClearCrossThreadFlag(Thread,
610 CT_ACTIVE_IMPERSONATION_INFO_BIT);
611
612 /* Get the token */
613 OldToken = Thread->ImpersonationInfo->Token;
614 }
615
616 /* Unlock the process and write TEB information */
617 PspUnlockThreadSecurityExclusive(Thread);
618 PspWriteTebImpersonationInfo(Thread, PsGetCurrentThread());
619 }
620 }
621 else
622 {
623 /* Check if we have impersonation info */
624 Impersonation = Thread->ImpersonationInfo;
625 if (!Impersonation)
626 {
627 /* We need to allocate a new one */
628 Impersonation = ExAllocatePoolWithTag(PagedPool,
629 sizeof(*Impersonation),
630 TAG_PS_IMPERSONATION);
631 if (!Impersonation) return STATUS_INSUFFICIENT_RESOURCES;
632
633 /* Update the pointer */
634 OldData = InterlockedCompareExchangePointer((PVOID*)&Thread->
635 ImpersonationInfo,
636 Impersonation,
637 NULL);
638 if (OldData)
639 {
640 /* Someone beat us to it, free our copy */
641 ExFreePool(Impersonation);
642 Impersonation = OldData;
643 }
644 }
645
646 /* Check if this is a job, which we don't support yet */
647 if (Thread->ThreadsProcess->Job) ASSERT(FALSE);
648
649 /* Lock thread security */
650 PspLockThreadSecurityExclusive(Thread);
651
652 /* Check if we're impersonating */
653 if (Thread->ActiveImpersonationInfo)
654 {
655 /* Get the token */
656 OldToken = Impersonation->Token;
657 }
658 else
659 {
660 /* Otherwise, enable impersonation */
661 PspSetCrossThreadFlag(Thread, CT_ACTIVE_IMPERSONATION_INFO_BIT);
662 }
663
664 /* Now fill it out */
665 Impersonation->ImpersonationLevel = ImpersonationLevel;
666 Impersonation->CopyOnOpen = CopyOnOpen;
667 Impersonation->EffectiveOnly = EffectiveOnly;
668 Impersonation->Token = Token;
669 ObReferenceObject(Token);
670
671 /* Unlock the thread */
672 PspUnlockThreadSecurityExclusive(Thread);
673
674 /* Write impersonation info to the TEB */
675 PspWriteTebImpersonationInfo(Thread, PsGetCurrentThread());
676 }
677
678 /* Dereference the token and return success */
679 if (OldToken) PsDereferenceImpersonationToken(OldToken);
680 return STATUS_SUCCESS;
681 }
682
683 /*
684 * @implemented
685 */
686 PACCESS_TOKEN
687 NTAPI
688 PsReferenceEffectiveToken(IN PETHREAD Thread,
689 OUT IN PTOKEN_TYPE TokenType,
690 OUT PBOOLEAN EffectiveOnly,
691 OUT PSECURITY_IMPERSONATION_LEVEL Level)
692 {
693 PEPROCESS Process;
694 PACCESS_TOKEN Token = NULL;
695 PAGED_CODE();
696 PSTRACE(PS_SECURITY_DEBUG,
697 "Thread: %p, TokenType: %p\n", Thread, TokenType);
698
699 /* Check if we don't have impersonation info */
700 Process = Thread->ThreadsProcess;
701 if (!Thread->ActiveImpersonationInfo)
702 {
703 /* Fast Reference the Token */
704 Token = ObFastReferenceObject(&Process->Token);
705
706 /* Check if we got the Token or if we got locked */
707 if (!Token)
708 {
709 /* Lock the Process */
710 PspLockProcessSecurityShared(Process);
711
712 /* Do a Locked Fast Reference */
713 Token = ObFastReferenceObjectLocked(&Process->Token);
714
715 /* Unlock the Process */
716 PspUnlockProcessSecurityShared(Process);
717 }
718 }
719 else
720 {
721 /* Lock the Process */
722 PspLockProcessSecurityShared(Process);
723
724 /* Make sure impersonation is still active */
725 if (Thread->ActiveImpersonationInfo)
726 {
727 /* Get the token */
728 Token = Thread->ImpersonationInfo->Token;
729 ObReferenceObject(Token);
730
731 /* Return data to caller */
732 *TokenType = TokenImpersonation;
733 *EffectiveOnly = Thread->ImpersonationInfo->EffectiveOnly;
734 *Level = Thread->ImpersonationInfo->ImpersonationLevel;
735
736 /* Unlock the Process */
737 PspUnlockProcessSecurityShared(Process);
738 return Token;
739 }
740
741 /* Unlock the Process */
742 PspUnlockProcessSecurityShared(Process);
743 }
744
745 /* Return the token */
746 *TokenType = TokenPrimary;
747 *EffectiveOnly = FALSE;
748 return Token;
749 }
750
751 /*
752 * @implemented
753 */
754 PACCESS_TOKEN
755 NTAPI
756 PsReferenceImpersonationToken(IN PETHREAD Thread,
757 OUT PBOOLEAN CopyOnOpen,
758 OUT PBOOLEAN EffectiveOnly,
759 OUT PSECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
760 {
761 PTOKEN Token = NULL;
762 PAGED_CODE();
763 PSTRACE(PS_SECURITY_DEBUG, "Thread: %p\n", Thread);
764
765 /* If we don't have impersonation info, just quit */
766 if (!Thread->ActiveImpersonationInfo) return NULL;
767
768 /* Lock the thread */
769 PspLockThreadSecurityShared(Thread);
770
771 /* Make sure we still have active impersonation */
772 if (Thread->ActiveImpersonationInfo)
773 {
774 /* Return data from caller */
775 ObReferenceObject(Thread->ImpersonationInfo->Token);
776 *ImpersonationLevel = Thread->ImpersonationInfo->ImpersonationLevel;
777 *CopyOnOpen = Thread->ImpersonationInfo->CopyOnOpen;
778 *EffectiveOnly = Thread->ImpersonationInfo->EffectiveOnly;
779
780 /* Set the token */
781 Token = Thread->ImpersonationInfo->Token;
782 }
783
784 /* Unlock thread and return impersonation token */
785 PspUnlockThreadSecurityShared(Thread);
786 return Token;
787 }
788
789 #undef PsDereferenceImpersonationToken
790 /*
791 * @implemented
792 */
793 VOID
794 NTAPI
795 PsDereferenceImpersonationToken(IN PACCESS_TOKEN ImpersonationToken)
796 {
797 PAGED_CODE();
798
799 /* If we got a token, dereference it */
800 if (ImpersonationToken) ObDereferenceObject(ImpersonationToken);
801 }
802
803 #undef PsDereferencePrimaryToken
804 /*
805 * @implemented
806 */
807 VOID
808 NTAPI
809 PsDereferencePrimaryToken(IN PACCESS_TOKEN PrimaryToken)
810 {
811 PAGED_CODE();
812
813 /* Dereference the token*/
814 ObDereferenceObject(PrimaryToken);
815 }
816
817 /*
818 * @implemented
819 */
820 BOOLEAN
821 NTAPI
822 PsDisableImpersonation(IN PETHREAD Thread,
823 IN PSE_IMPERSONATION_STATE ImpersonationState)
824 {
825 PPS_IMPERSONATION_INFORMATION Impersonation = NULL;
826 LONG NewValue, OldValue;
827 PAGED_CODE();
828 PSTRACE(PS_SECURITY_DEBUG,
829 "Thread: %p State: %p\n", Thread, ImpersonationState);
830
831 /* Check if we don't have impersonation */
832 if (Thread->ActiveImpersonationInfo)
833 {
834 /* Lock thread security */
835 PspLockThreadSecurityExclusive(Thread);
836
837 /* Disable impersonation */
838 OldValue = Thread->CrossThreadFlags;
839 do
840 {
841 /* Attempt to change the flag */
842 NewValue =
843 InterlockedCompareExchange((PLONG)&Thread->CrossThreadFlags,
844 OldValue &~
845 CT_ACTIVE_IMPERSONATION_INFO_BIT,
846 OldValue);
847 } while (NewValue != OldValue);
848
849 /* Make sure nobody disabled it behind our back */
850 if (NewValue & CT_ACTIVE_IMPERSONATION_INFO_BIT)
851 {
852 /* Copy the old state */
853 Impersonation = Thread->ImpersonationInfo;
854 ImpersonationState->Token = Impersonation->Token;
855 ImpersonationState->CopyOnOpen = Impersonation->CopyOnOpen;
856 ImpersonationState->EffectiveOnly = Impersonation->EffectiveOnly;
857 ImpersonationState->Level = Impersonation->ImpersonationLevel;
858 }
859
860 /* Unlock thread security */
861 PspUnlockThreadSecurityExclusive(Thread);
862
863 /* If we had impersonation info, return true */
864 if (Impersonation) return TRUE;
865 }
866
867 /* Clear everything */
868 ImpersonationState->Token = NULL;
869 ImpersonationState->CopyOnOpen = FALSE;
870 ImpersonationState->EffectiveOnly = FALSE;
871 ImpersonationState->Level = SecurityAnonymous;
872 return FALSE;
873 }
874
875 /*
876 * @implemented
877 */
878 VOID
879 NTAPI
880 PsRestoreImpersonation(IN PETHREAD Thread,
881 IN PSE_IMPERSONATION_STATE ImpersonationState)
882 {
883 PTOKEN Token = NULL;
884 PPS_IMPERSONATION_INFORMATION Impersonation;
885 PAGED_CODE();
886 PSTRACE(PS_SECURITY_DEBUG,
887 "Thread: %p State: %p\n", Thread, ImpersonationState);
888
889 /* Lock thread security */
890 PspLockThreadSecurityExclusive(Thread);
891
892 /* Get the impersonation info */
893 Impersonation = Thread->ImpersonationInfo;
894
895 /* Check if we're impersonating */
896 if (Thread->ActiveImpersonationInfo)
897 {
898 /* Get the token */
899 Token = Impersonation->Token;
900 }
901
902 /* Check if we have an impersonation state */
903 if (ImpersonationState)
904 {
905 /* Fill out the impersonation info */
906 Impersonation->ImpersonationLevel = ImpersonationState->Level;
907 Impersonation->CopyOnOpen = ImpersonationState->CopyOnOpen;
908 Impersonation->EffectiveOnly = ImpersonationState->EffectiveOnly;
909 Impersonation->Token = ImpersonationState->Token;
910
911 /* Enable impersonation */
912 PspSetCrossThreadFlag(Thread, CT_ACTIVE_IMPERSONATION_INFO_BIT);
913 }
914 else
915 {
916 /* Disable impersonation */
917 PspClearCrossThreadFlag(Thread, CT_ACTIVE_IMPERSONATION_INFO_BIT);
918 }
919
920 /* Unlock the thread */
921 PspUnlockThreadSecurityExclusive(Thread);
922
923 /* Dereference the token */
924 if (Token) ObDereferenceObject(Token);
925 }
926
927 NTSTATUS
928 NTAPI
929 NtImpersonateThread(IN HANDLE ThreadHandle,
930 IN HANDLE ThreadToImpersonateHandle,
931 IN PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService)
932 {
933 SECURITY_QUALITY_OF_SERVICE SafeServiceQoS;
934 SECURITY_CLIENT_CONTEXT ClientContext;
935 PETHREAD Thread;
936 PETHREAD ThreadToImpersonate;
937 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
938 NTSTATUS Status;
939 PAGED_CODE();
940 PSTRACE(PS_SECURITY_DEBUG,
941 "Threads: %p %p\n", ThreadHandle, ThreadToImpersonateHandle);
942
943 /* Check if call came from user mode */
944 if (PreviousMode != KernelMode)
945 {
946 /* Enter SEH for probing */
947 _SEH2_TRY
948 {
949 /* Probe QoS */
950 ProbeForRead(SecurityQualityOfService,
951 sizeof(SECURITY_QUALITY_OF_SERVICE),
952 sizeof(ULONG));
953
954 /* Capture it */
955 SafeServiceQoS = *SecurityQualityOfService;
956 SecurityQualityOfService = &SafeServiceQoS;
957 }
958 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
959 {
960 /* Return the exception code */
961 _SEH2_YIELD(return _SEH2_GetExceptionCode());
962 }
963 _SEH2_END;
964 }
965
966 /* Reference the thread */
967 Status = ObReferenceObjectByHandle(ThreadHandle,
968 THREAD_DIRECT_IMPERSONATION,
969 PsThreadType,
970 PreviousMode,
971 (PVOID*)&Thread,
972 NULL);
973 if (NT_SUCCESS(Status))
974 {
975 /* Reference the impersonating thead */
976 Status = ObReferenceObjectByHandle(ThreadToImpersonateHandle,
977 THREAD_IMPERSONATE,
978 PsThreadType,
979 PreviousMode,
980 (PVOID*)&ThreadToImpersonate,
981 NULL);
982 if (NT_SUCCESS(Status))
983 {
984 /* Create a client security context */
985 Status = SeCreateClientSecurity(ThreadToImpersonate,
986 SecurityQualityOfService,
987 0,
988 &ClientContext);
989 if (NT_SUCCESS(Status))
990 {
991 /* Do the impersonation */
992 SeImpersonateClient(&ClientContext, Thread);
993 if (ClientContext.ClientToken)
994 {
995 /* Dereference the client token if we had one */
996 ObDereferenceObject(ClientContext.ClientToken);
997 }
998 }
999
1000 /* Dereference the thread to impersonate */
1001 ObDereferenceObject(ThreadToImpersonate);
1002 }
1003
1004 /* Dereference the main thread */
1005 ObDereferenceObject(Thread);
1006 }
1007
1008 /* Return status */
1009 return Status;
1010 }
1011 /* EOF */