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