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