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