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, ProcessToken = NULL; 618 PACCESS_TOKEN NewToken, ImpersonationToken; 619 PEJOB Job; 620 NTSTATUS Status; 621 622 PAGED_CODE(); 623 PSTRACE(PS_SECURITY_DEBUG, "Thread: %p, Token: %p\n", Thread, Token); 624 625 /* Check if we don't have a token */ 626 if (!Token) 627 { 628 /* Make sure we're impersonating */ 629 if (Thread->ActiveImpersonationInfo) 630 { 631 /* We seem to be, lock the thread */ 632 PspLockThreadSecurityExclusive(Thread); 633 634 /* Make sure we're still impersonating */ 635 if (Thread->ActiveImpersonationInfo) 636 { 637 /* Disable impersonation */ 638 PspClearCrossThreadFlag(Thread, 639 CT_ACTIVE_IMPERSONATION_INFO_BIT); 640 641 /* Get the token */ 642 OldToken = Thread->ImpersonationInfo->Token; 643 } 644 645 /* Unlock the process and write TEB information */ 646 PspUnlockThreadSecurityExclusive(Thread); 647 PspWriteTebImpersonationInfo(Thread, PsGetCurrentThread()); 648 } 649 } 650 else 651 { 652 /* Check if we have impersonation info */ 653 Impersonation = Thread->ImpersonationInfo; 654 if (!Impersonation) 655 { 656 /* We need to allocate a new one */ 657 Impersonation = ExAllocatePoolWithTag(PagedPool, 658 sizeof(*Impersonation), 659 TAG_PS_IMPERSONATION); 660 if (!Impersonation) return STATUS_INSUFFICIENT_RESOURCES; 661 662 /* Update the pointer */ 663 OldData = InterlockedCompareExchangePointer((PVOID*)&Thread-> 664 ImpersonationInfo, 665 Impersonation, 666 NULL); 667 if (OldData) 668 { 669 /* Someone beat us to it, free our copy */ 670 ExFreePoolWithTag(Impersonation, TAG_PS_IMPERSONATION); 671 Impersonation = OldData; 672 } 673 } 674 675 /* 676 * Assign the token we get from the caller first. The reason 677 * we have to do that is because we're unsure if we can impersonate 678 * in the first place. In the scenario where we cannot then the 679 * last resort is to make a copy of the token and assign that newly 680 * token to the impersonation information. 681 */ 682 ImpersonationToken = Token; 683 684 /* Obtain a token from the process */ 685 ProcessToken = PsReferencePrimaryToken(Thread->ThreadsProcess); 686 if (!ProcessToken) 687 { 688 /* We can't continue this way without having the process' token... */ 689 return STATUS_UNSUCCESSFUL; 690 } 691 692 /* Make sure we can impersonate */ 693 if (!SeTokenCanImpersonate(ProcessToken, 694 Token, 695 ImpersonationLevel)) 696 { 697 /* We can't, make a copy of the token instead */ 698 Status = SeCopyClientToken(Token, 699 SecurityIdentification, 700 KernelMode, 701 &NewToken); 702 if (!NT_SUCCESS(Status)) 703 { 704 /* We can't even make a copy of the token? Then bail out... */ 705 ObFastDereferenceObject(&Thread->ThreadsProcess->Token, ProcessToken); 706 return Status; 707 } 708 709 /* Since we cannot impersonate, assign the newly copied token */ 710 ImpersonationToken = NewToken; 711 } 712 713 /* We no longer need the process' token */ 714 ObFastDereferenceObject(&Thread->ThreadsProcess->Token, ProcessToken); 715 716 /* Check if this is a job */ 717 Job = Thread->ThreadsProcess->Job; 718 if (Job != NULL) 719 { 720 /* No admin allowed in this job */ 721 if ((Job->SecurityLimitFlags & JOB_OBJECT_SECURITY_NO_ADMIN) && 722 SeTokenIsAdmin(ImpersonationToken)) 723 { 724 return STATUS_ACCESS_DENIED; 725 } 726 727 /* No restricted tokens allowed in this job */ 728 if ((Job->SecurityLimitFlags & JOB_OBJECT_SECURITY_RESTRICTED_TOKEN) && 729 SeTokenIsRestricted(ImpersonationToken)) 730 { 731 return STATUS_ACCESS_DENIED; 732 } 733 734 /* We don't support job filters yet */ 735 if (Job->Filter != NULL) 736 { 737 ASSERT(Job->Filter == NULL); 738 } 739 } 740 741 /* Lock thread security */ 742 PspLockThreadSecurityExclusive(Thread); 743 744 /* Check if we're impersonating */ 745 if (Thread->ActiveImpersonationInfo) 746 { 747 /* Get the token */ 748 OldToken = Impersonation->Token; 749 } 750 else 751 { 752 /* Otherwise, enable impersonation */ 753 PspSetCrossThreadFlag(Thread, CT_ACTIVE_IMPERSONATION_INFO_BIT); 754 } 755 756 /* Now fill it out */ 757 Impersonation->ImpersonationLevel = ImpersonationLevel; 758 Impersonation->CopyOnOpen = CopyOnOpen; 759 Impersonation->EffectiveOnly = EffectiveOnly; 760 Impersonation->Token = ImpersonationToken; 761 ObReferenceObject(ImpersonationToken); 762 763 /* Unlock the thread */ 764 PspUnlockThreadSecurityExclusive(Thread); 765 766 /* Write impersonation info to the TEB */ 767 PspWriteTebImpersonationInfo(Thread, PsGetCurrentThread()); 768 } 769 770 /* Dereference the token and return success */ 771 if (OldToken) PsDereferenceImpersonationToken(OldToken); 772 return STATUS_SUCCESS; 773 } 774 775 /* 776 * @implemented 777 */ 778 PACCESS_TOKEN 779 NTAPI 780 PsReferenceEffectiveToken(IN PETHREAD Thread, 781 OUT IN PTOKEN_TYPE TokenType, 782 OUT PBOOLEAN EffectiveOnly, 783 OUT PSECURITY_IMPERSONATION_LEVEL ImpersonationLevel) 784 { 785 PEPROCESS Process; 786 PACCESS_TOKEN Token = NULL; 787 788 PAGED_CODE(); 789 790 PSTRACE(PS_SECURITY_DEBUG, 791 "Thread: %p, TokenType: %p\n", Thread, TokenType); 792 793 /* Check if we don't have impersonation info */ 794 Process = Thread->ThreadsProcess; 795 if (Thread->ActiveImpersonationInfo) 796 { 797 /* Lock the Process */ 798 PspLockProcessSecurityShared(Process); 799 800 /* Make sure impersonation is still active */ 801 if (Thread->ActiveImpersonationInfo) 802 { 803 /* Get the token */ 804 Token = Thread->ImpersonationInfo->Token; 805 ObReferenceObject(Token); 806 807 /* Return data to caller */ 808 *TokenType = TokenImpersonation; 809 *EffectiveOnly = Thread->ImpersonationInfo->EffectiveOnly; 810 *ImpersonationLevel = Thread->ImpersonationInfo->ImpersonationLevel; 811 812 /* Unlock the Process */ 813 PspUnlockProcessSecurityShared(Process); 814 return Token; 815 } 816 817 /* Unlock the Process */ 818 PspUnlockProcessSecurityShared(Process); 819 } 820 821 /* Fast Reference the Token */ 822 Token = ObFastReferenceObject(&Process->Token); 823 824 /* Check if we got the Token or if we got locked */ 825 if (!Token) 826 { 827 /* Lock the Process */ 828 PspLockProcessSecurityShared(Process); 829 830 /* Do a Locked Fast Reference */ 831 Token = ObFastReferenceObjectLocked(&Process->Token); 832 833 /* Unlock the Process */ 834 PspUnlockProcessSecurityShared(Process); 835 } 836 837 /* Return the token */ 838 *TokenType = TokenPrimary; 839 *EffectiveOnly = FALSE; 840 // NOTE: ImpersonationLevel is left untouched on purpose! 841 return Token; 842 } 843 844 /* 845 * @implemented 846 */ 847 PACCESS_TOKEN 848 NTAPI 849 PsReferenceImpersonationToken(IN PETHREAD Thread, 850 OUT PBOOLEAN CopyOnOpen, 851 OUT PBOOLEAN EffectiveOnly, 852 OUT PSECURITY_IMPERSONATION_LEVEL ImpersonationLevel) 853 { 854 PTOKEN Token = NULL; 855 PAGED_CODE(); 856 PSTRACE(PS_SECURITY_DEBUG, "Thread: %p\n", Thread); 857 858 /* If we don't have impersonation info, just quit */ 859 if (!Thread->ActiveImpersonationInfo) return NULL; 860 861 /* Lock the thread */ 862 PspLockThreadSecurityShared(Thread); 863 864 /* Make sure we still have active impersonation */ 865 if (Thread->ActiveImpersonationInfo) 866 { 867 /* Return data from caller */ 868 ObReferenceObject(Thread->ImpersonationInfo->Token); 869 *ImpersonationLevel = Thread->ImpersonationInfo->ImpersonationLevel; 870 *CopyOnOpen = Thread->ImpersonationInfo->CopyOnOpen; 871 *EffectiveOnly = Thread->ImpersonationInfo->EffectiveOnly; 872 873 /* Set the token */ 874 Token = Thread->ImpersonationInfo->Token; 875 } 876 877 /* Unlock thread and return impersonation token */ 878 PspUnlockThreadSecurityShared(Thread); 879 return Token; 880 } 881 882 #undef PsDereferenceImpersonationToken 883 /* 884 * @implemented 885 */ 886 VOID 887 NTAPI 888 PsDereferenceImpersonationToken(IN PACCESS_TOKEN ImpersonationToken) 889 { 890 PAGED_CODE(); 891 892 /* If we got a token, dereference it */ 893 if (ImpersonationToken) ObDereferenceObject(ImpersonationToken); 894 } 895 896 #undef PsDereferencePrimaryToken 897 /* 898 * @implemented 899 */ 900 VOID 901 NTAPI 902 PsDereferencePrimaryToken(IN PACCESS_TOKEN PrimaryToken) 903 { 904 PAGED_CODE(); 905 906 /* Dereference the token*/ 907 ObDereferenceObject(PrimaryToken); 908 } 909 910 /* 911 * @implemented 912 */ 913 BOOLEAN 914 NTAPI 915 PsDisableImpersonation(IN PETHREAD Thread, 916 OUT PSE_IMPERSONATION_STATE ImpersonationState) 917 { 918 PPS_IMPERSONATION_INFORMATION Impersonation = NULL; 919 LONG OldFlags; 920 PAGED_CODE(); 921 PSTRACE(PS_SECURITY_DEBUG, 922 "Thread: %p State: %p\n", Thread, ImpersonationState); 923 924 /* Check if we don't have impersonation */ 925 if (Thread->ActiveImpersonationInfo) 926 { 927 /* Lock thread security */ 928 PspLockThreadSecurityExclusive(Thread); 929 930 /* Disable impersonation */ 931 OldFlags = PspClearCrossThreadFlag(Thread, 932 CT_ACTIVE_IMPERSONATION_INFO_BIT); 933 934 /* Make sure nobody disabled it behind our back */ 935 if (OldFlags & CT_ACTIVE_IMPERSONATION_INFO_BIT) 936 { 937 /* Copy the old state */ 938 Impersonation = Thread->ImpersonationInfo; 939 ImpersonationState->Token = Impersonation->Token; 940 ImpersonationState->CopyOnOpen = Impersonation->CopyOnOpen; 941 ImpersonationState->EffectiveOnly = Impersonation->EffectiveOnly; 942 ImpersonationState->Level = Impersonation->ImpersonationLevel; 943 } 944 945 /* Unlock thread security */ 946 PspUnlockThreadSecurityExclusive(Thread); 947 948 /* If we had impersonation info, return true */ 949 if (Impersonation) return TRUE; 950 } 951 952 /* Clear everything */ 953 ImpersonationState->Token = NULL; 954 ImpersonationState->CopyOnOpen = FALSE; 955 ImpersonationState->EffectiveOnly = FALSE; 956 ImpersonationState->Level = SecurityAnonymous; 957 return FALSE; 958 } 959 960 /* 961 * @implemented 962 */ 963 VOID 964 NTAPI 965 PsRestoreImpersonation(IN PETHREAD Thread, 966 IN PSE_IMPERSONATION_STATE ImpersonationState) 967 { 968 PTOKEN Token = NULL; 969 PPS_IMPERSONATION_INFORMATION Impersonation; 970 PAGED_CODE(); 971 PSTRACE(PS_SECURITY_DEBUG, 972 "Thread: %p State: %p\n", Thread, ImpersonationState); 973 974 /* Lock thread security */ 975 PspLockThreadSecurityExclusive(Thread); 976 977 /* Get the impersonation info */ 978 Impersonation = Thread->ImpersonationInfo; 979 980 /* Check if we're impersonating */ 981 if (Thread->ActiveImpersonationInfo) 982 { 983 /* Get the token */ 984 Token = Impersonation->Token; 985 } 986 987 /* Check if we have an impersonation state */ 988 if (ImpersonationState) 989 { 990 /* Fill out the impersonation info */ 991 Impersonation->ImpersonationLevel = ImpersonationState->Level; 992 Impersonation->CopyOnOpen = ImpersonationState->CopyOnOpen; 993 Impersonation->EffectiveOnly = ImpersonationState->EffectiveOnly; 994 Impersonation->Token = ImpersonationState->Token; 995 996 /* Enable impersonation */ 997 PspSetCrossThreadFlag(Thread, CT_ACTIVE_IMPERSONATION_INFO_BIT); 998 } 999 else 1000 { 1001 /* Disable impersonation */ 1002 PspClearCrossThreadFlag(Thread, CT_ACTIVE_IMPERSONATION_INFO_BIT); 1003 } 1004 1005 /* Unlock the thread */ 1006 PspUnlockThreadSecurityExclusive(Thread); 1007 1008 /* Dereference the token */ 1009 if (Token) ObDereferenceObject(Token); 1010 } 1011 1012 NTSTATUS 1013 NTAPI 1014 NtImpersonateThread(IN HANDLE ThreadHandle, 1015 IN HANDLE ThreadToImpersonateHandle, 1016 IN PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService) 1017 { 1018 SECURITY_QUALITY_OF_SERVICE SafeServiceQoS; 1019 SECURITY_CLIENT_CONTEXT ClientContext; 1020 PETHREAD Thread; 1021 PETHREAD ThreadToImpersonate; 1022 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 1023 NTSTATUS Status; 1024 PAGED_CODE(); 1025 PSTRACE(PS_SECURITY_DEBUG, 1026 "Threads: %p %p\n", ThreadHandle, ThreadToImpersonateHandle); 1027 1028 /* Check if call came from user mode */ 1029 if (PreviousMode != KernelMode) 1030 { 1031 /* Enter SEH for probing */ 1032 _SEH2_TRY 1033 { 1034 /* Probe QoS */ 1035 ProbeForRead(SecurityQualityOfService, 1036 sizeof(SECURITY_QUALITY_OF_SERVICE), 1037 sizeof(ULONG)); 1038 1039 /* Capture it */ 1040 SafeServiceQoS = *SecurityQualityOfService; 1041 SecurityQualityOfService = &SafeServiceQoS; 1042 } 1043 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1044 { 1045 /* Return the exception code */ 1046 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 1047 } 1048 _SEH2_END; 1049 } 1050 1051 /* Reference the thread */ 1052 Status = ObReferenceObjectByHandle(ThreadHandle, 1053 THREAD_DIRECT_IMPERSONATION, 1054 PsThreadType, 1055 PreviousMode, 1056 (PVOID*)&Thread, 1057 NULL); 1058 if (NT_SUCCESS(Status)) 1059 { 1060 /* Reference the impersonating thead */ 1061 Status = ObReferenceObjectByHandle(ThreadToImpersonateHandle, 1062 THREAD_IMPERSONATE, 1063 PsThreadType, 1064 PreviousMode, 1065 (PVOID*)&ThreadToImpersonate, 1066 NULL); 1067 if (NT_SUCCESS(Status)) 1068 { 1069 /* Create a client security context */ 1070 Status = SeCreateClientSecurity(ThreadToImpersonate, 1071 SecurityQualityOfService, 1072 0, 1073 &ClientContext); 1074 if (NT_SUCCESS(Status)) 1075 { 1076 /* Do the impersonation */ 1077 SeImpersonateClient(&ClientContext, Thread); 1078 if (ClientContext.ClientToken) 1079 { 1080 /* Dereference the client token if we had one */ 1081 ObDereferenceObject(ClientContext.ClientToken); 1082 } 1083 } 1084 1085 /* Dereference the thread to impersonate */ 1086 ObDereferenceObject(ThreadToImpersonate); 1087 } 1088 1089 /* Dereference the main thread */ 1090 ObDereferenceObject(Thread); 1091 } 1092 1093 /* Return status */ 1094 return Status; 1095 } 1096 /* EOF */ 1097