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