1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Security access state functions support 5 * COPYRIGHT: Copyright Alex Ionescu <alex@relsoft.net> 6 */ 7 8 /* INCLUDES *******************************************************************/ 9 10 #include <ntoskrnl.h> 11 #define NDEBUG 12 #include <debug.h> 13 14 /* GLOBALS ********************************************************************/ 15 16 ERESOURCE SepSubjectContextLock; 17 18 /* PRIVATE FUNCTIONS **********************************************************/ 19 20 /** 21 * @brief 22 * Checks if a SID is present in a token. 23 * 24 * @param[in] _Token 25 * A valid token object. 26 * 27 * @param[in] PrincipalSelfSid 28 * A principal self SID. 29 * 30 * @param[in] _Sid 31 * A regular SID. 32 * 33 * @param[in] Deny 34 * If set to TRUE, the caller expected that a SID in a token 35 * must be a deny-only SID, that is, access checks are performed 36 * only for deny-only ACEs of the said SID. 37 * 38 * @param[in] Restricted 39 * If set to TRUE, the caller expects that a SID in a token is 40 * restricted. 41 * 42 * @return 43 * Returns TRUE if the specified SID in the call is present in the token, 44 * FALSE otherwise. 45 */ 46 BOOLEAN 47 NTAPI 48 SepSidInTokenEx( 49 _In_ PACCESS_TOKEN _Token, 50 _In_ PSID PrincipalSelfSid, 51 _In_ PSID _Sid, 52 _In_ BOOLEAN Deny, 53 _In_ BOOLEAN Restricted) 54 { 55 ULONG i; 56 PTOKEN Token = (PTOKEN)_Token; 57 PISID TokenSid, Sid = (PISID)_Sid; 58 PSID_AND_ATTRIBUTES SidAndAttributes; 59 ULONG SidCount, SidLength; 60 USHORT SidMetadata; 61 PAGED_CODE(); 62 63 /* Not yet supported */ 64 ASSERT(PrincipalSelfSid == NULL); 65 ASSERT(Restricted == FALSE); 66 67 /* Check if a principal SID was given, and this is our current SID already */ 68 if ((PrincipalSelfSid) && (RtlEqualSid(SePrincipalSelfSid, Sid))) 69 { 70 /* Just use the principal SID in this case */ 71 Sid = PrincipalSelfSid; 72 } 73 74 /* Check if this is a restricted token or not */ 75 if (Restricted) 76 { 77 /* Use the restricted SIDs and count */ 78 SidAndAttributes = Token->RestrictedSids; 79 SidCount = Token->RestrictedSidCount; 80 } 81 else 82 { 83 /* Use the normal SIDs and count */ 84 SidAndAttributes = Token->UserAndGroups; 85 SidCount = Token->UserAndGroupCount; 86 } 87 88 /* Do checks here by hand instead of the usual 4 function calls */ 89 SidLength = FIELD_OFFSET(SID, 90 SubAuthority[Sid->SubAuthorityCount]); 91 SidMetadata = *(PUSHORT)&Sid->Revision; 92 93 /* Loop every SID */ 94 for (i = 0; i < SidCount; i++) 95 { 96 TokenSid = (PISID)SidAndAttributes->Sid; 97 #if SE_SID_DEBUG 98 UNICODE_STRING sidString; 99 RtlConvertSidToUnicodeString(&sidString, TokenSid, TRUE); 100 DPRINT1("SID in Token: %wZ\n", &sidString); 101 RtlFreeUnicodeString(&sidString); 102 #endif 103 /* Check if the SID metadata matches */ 104 if (*(PUSHORT)&TokenSid->Revision == SidMetadata) 105 { 106 /* Check if the SID data matches */ 107 if (RtlEqualMemory(Sid, TokenSid, SidLength)) 108 { 109 /* Check if the group is enabled, or used for deny only */ 110 if ((!(i) && !(SidAndAttributes->Attributes & SE_GROUP_USE_FOR_DENY_ONLY)) || 111 (SidAndAttributes->Attributes & SE_GROUP_ENABLED) || 112 ((Deny) && (SidAndAttributes->Attributes & SE_GROUP_USE_FOR_DENY_ONLY))) 113 { 114 /* SID is present */ 115 return TRUE; 116 } 117 else 118 { 119 /* SID is not present */ 120 return FALSE; 121 } 122 } 123 } 124 125 /* Move to the next SID */ 126 SidAndAttributes++; 127 } 128 129 /* SID is not present */ 130 return FALSE; 131 } 132 133 /** 134 * @brief 135 * Checks if a SID is present in a token. 136 * 137 * @param[in] _Token 138 * A valid token object. 139 * 140 * @param[in] _Sid 141 * A regular SID. 142 * 143 * @return 144 * Returns TRUE if the specified SID in the call is present in the token, 145 * FALSE otherwise. 146 */ 147 BOOLEAN 148 NTAPI 149 SepSidInToken( 150 _In_ PACCESS_TOKEN _Token, 151 _In_ PSID Sid) 152 { 153 /* Call extended API */ 154 return SepSidInTokenEx(_Token, NULL, Sid, FALSE, FALSE); 155 } 156 157 /** 158 * @brief 159 * Checks if a token belongs to the main user, being the owner. 160 * 161 * @param[in] _Token 162 * A valid token object. 163 * 164 * @param[in] SecurityDescriptor 165 * A security descriptor where the owner is to be found. 166 * 167 * @param[in] TokenLocked 168 * If set to TRUE, the token has been already locked and there's 169 * no need to lock it again. Otherwise the function will acquire 170 * the lock. 171 * 172 * @return 173 * Returns TRUE if the token belongs to a owner, FALSE otherwise. 174 */ 175 BOOLEAN 176 NTAPI 177 SepTokenIsOwner( 178 _In_ PACCESS_TOKEN _Token, 179 _In_ PSECURITY_DESCRIPTOR SecurityDescriptor, 180 _In_ BOOLEAN TokenLocked) 181 { 182 PSID Sid; 183 BOOLEAN Result; 184 PTOKEN Token = _Token; 185 186 /* Get the owner SID */ 187 Sid = SepGetOwnerFromDescriptor(SecurityDescriptor); 188 ASSERT(Sid != NULL); 189 190 /* Lock the token if needed */ 191 if (!TokenLocked) SepAcquireTokenLockShared(Token); 192 193 /* Check if the owner SID is found, handling restricted case as well */ 194 Result = SepSidInToken(Token, Sid); 195 if ((Result) && (Token->TokenFlags & TOKEN_IS_RESTRICTED)) 196 { 197 Result = SepSidInTokenEx(Token, NULL, Sid, FALSE, TRUE); 198 } 199 200 /* Release the lock if we had acquired it */ 201 if (!TokenLocked) SepReleaseTokenLock(Token); 202 203 /* Return the result */ 204 return Result; 205 } 206 207 /** 208 * @brief 209 * Retrieves token control information. 210 * 211 * @param[in] _Token 212 * A valid token object. 213 * 214 * @param[out] SecurityDescriptor 215 * The returned token control information. 216 * 217 * @return 218 * Nothing. 219 */ 220 VOID 221 NTAPI 222 SeGetTokenControlInformation( 223 _In_ PACCESS_TOKEN _Token, 224 _Out_ PTOKEN_CONTROL TokenControl) 225 { 226 PTOKEN Token = _Token; 227 PAGED_CODE(); 228 229 /* Capture the main fields */ 230 TokenControl->AuthenticationId = Token->AuthenticationId; 231 TokenControl->TokenId = Token->TokenId; 232 TokenControl->TokenSource = Token->TokenSource; 233 234 /* Lock the token */ 235 SepAcquireTokenLockShared(Token); 236 237 /* Capture the modified ID */ 238 TokenControl->ModifiedId = Token->ModifiedId; 239 240 /* Unlock it */ 241 SepReleaseTokenLock(Token); 242 } 243 244 /** 245 * @brief 246 * Creates a client security context based upon an access token. 247 * 248 * @param[in] Token 249 * A valid token object. 250 * 251 * @param[in] ClientSecurityQos 252 * The Quality of Service (QoS) of a client security context. 253 * 254 * @param[in] ServerIsRemote 255 * If the client is a remote server (TRUE), the function will retrieve the 256 * control information of an access token, that is, we're doing delegation 257 * and that the server isn't local. 258 * 259 * @param[in] TokenType 260 * Type of token. 261 * 262 * @param[in] ThreadEffectiveOnly 263 * If set to TRUE, the client wants that the current thread wants to modify 264 * (enable or disable) privileges and groups. 265 * 266 * @param[in] ImpersonationLevel 267 * Security impersonation level filled in the QoS context. 268 * 269 * @param[out] ClientContext 270 * The returned security client context. 271 * 272 * @return 273 * Returns STATUS_SUCCESS if client security creation has completed successfully. 274 * STATUS_INVALID_PARAMETER is returned if one or more of the parameters are bogus. 275 * STATUS_BAD_IMPERSONATION_LEVEL is returned if the current impersonation level 276 * within QoS context doesn't meet with the conditions required. A failure 277 * NTSTATUS code is returned otherwise. 278 */ 279 NTSTATUS 280 NTAPI 281 SepCreateClientSecurity( 282 _In_ PACCESS_TOKEN Token, 283 _In_ PSECURITY_QUALITY_OF_SERVICE ClientSecurityQos, 284 _In_ BOOLEAN ServerIsRemote, 285 _In_ TOKEN_TYPE TokenType, 286 _In_ BOOLEAN ThreadEffectiveOnly, 287 _In_ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, 288 _Out_ PSECURITY_CLIENT_CONTEXT ClientContext) 289 { 290 NTSTATUS Status; 291 PACCESS_TOKEN NewToken; 292 PAGED_CODE(); 293 294 /* Check for bogus impersonation level */ 295 if (!VALID_IMPERSONATION_LEVEL(ClientSecurityQos->ImpersonationLevel)) 296 { 297 /* Fail the call */ 298 return STATUS_INVALID_PARAMETER; 299 } 300 301 /* Check what kind of token this is */ 302 if (TokenType != TokenImpersonation) 303 { 304 /* On a primary token, if we do direct access, copy the flag from the QOS */ 305 ClientContext->DirectAccessEffectiveOnly = ClientSecurityQos->EffectiveOnly; 306 } 307 else 308 { 309 /* This is an impersonation token, is the level ok? */ 310 if (ClientSecurityQos->ImpersonationLevel > ImpersonationLevel) 311 { 312 /* Nope, fail */ 313 return STATUS_BAD_IMPERSONATION_LEVEL; 314 } 315 316 /* Is the level too low, or are we doing something other than delegation remotely */ 317 if ((ImpersonationLevel == SecurityAnonymous) || 318 (ImpersonationLevel == SecurityIdentification) || 319 ((ServerIsRemote) && (ImpersonationLevel != SecurityDelegation))) 320 { 321 /* Fail the call */ 322 return STATUS_BAD_IMPERSONATION_LEVEL; 323 } 324 325 /* Pick either the thread setting or the QOS setting */ 326 ClientContext->DirectAccessEffectiveOnly = 327 ((ThreadEffectiveOnly) || (ClientSecurityQos->EffectiveOnly)) ? TRUE : FALSE; 328 } 329 330 /* Is this static tracking */ 331 if (ClientSecurityQos->ContextTrackingMode == SECURITY_STATIC_TRACKING) 332 { 333 /* Do not use direct access and make a copy */ 334 ClientContext->DirectlyAccessClientToken = FALSE; 335 Status = SeCopyClientToken(Token, 336 ClientSecurityQos->ImpersonationLevel, 337 KernelMode, 338 &NewToken); 339 if (!NT_SUCCESS(Status)) 340 return Status; 341 } 342 else 343 { 344 /* Use direct access and check if this is local */ 345 ClientContext->DirectlyAccessClientToken = TRUE; 346 if (ServerIsRemote) 347 { 348 /* We are doing delegation, so make a copy of the control data */ 349 SeGetTokenControlInformation(Token, 350 &ClientContext->ClientTokenControl); 351 } 352 353 /* Keep the same token */ 354 NewToken = Token; 355 } 356 357 /* Fill out the context and return success */ 358 ClientContext->SecurityQos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE); 359 ClientContext->SecurityQos.ImpersonationLevel = ClientSecurityQos->ImpersonationLevel; 360 ClientContext->SecurityQos.ContextTrackingMode = ClientSecurityQos->ContextTrackingMode; 361 ClientContext->SecurityQos.EffectiveOnly = ClientSecurityQos->EffectiveOnly; 362 ClientContext->ServerIsRemote = ServerIsRemote; 363 ClientContext->ClientToken = NewToken; 364 return STATUS_SUCCESS; 365 } 366 367 /* PUBLIC FUNCTIONS ***********************************************************/ 368 369 /** 370 * @brief 371 * An extended function that captures the security subject context based upon 372 * the specified thread and process. 373 * 374 * @param[in] Thread 375 * A thread where the calling thread's token is to be referenced for 376 * the security context. 377 * 378 * @param[in] Process 379 * A process where the main process' token is to be referenced for 380 * the security context. 381 * 382 * @param[out] SubjectContext 383 * The returned security subject context. 384 * 385 * @return 386 * Nothing. 387 */ 388 VOID 389 NTAPI 390 SeCaptureSubjectContextEx( 391 _In_ PETHREAD Thread, 392 _In_ PEPROCESS Process, 393 _Out_ PSECURITY_SUBJECT_CONTEXT SubjectContext) 394 { 395 BOOLEAN CopyOnOpen, EffectiveOnly; 396 397 PAGED_CODE(); 398 399 /* Save the unique ID */ 400 SubjectContext->ProcessAuditId = Process->UniqueProcessId; 401 402 /* Check if we have a thread */ 403 if (!Thread) 404 { 405 /* We don't, so no token */ 406 SubjectContext->ClientToken = NULL; 407 } 408 else 409 { 410 /* Get the impersonation token */ 411 SubjectContext->ClientToken = PsReferenceImpersonationToken(Thread, 412 &CopyOnOpen, 413 &EffectiveOnly, 414 &SubjectContext->ImpersonationLevel); 415 } 416 417 /* Get the primary token */ 418 SubjectContext->PrimaryToken = PsReferencePrimaryToken(Process); 419 } 420 421 /** 422 * @brief 423 * Captures the security subject context of the calling thread and calling 424 * process. 425 * 426 * @param[out] SubjectContext 427 * The returned security subject context. 428 * 429 * @return 430 * Nothing. 431 */ 432 VOID 433 NTAPI 434 SeCaptureSubjectContext( 435 _Out_ PSECURITY_SUBJECT_CONTEXT SubjectContext) 436 { 437 /* Call the extended API */ 438 SeCaptureSubjectContextEx(PsGetCurrentThread(), 439 PsGetCurrentProcess(), 440 SubjectContext); 441 } 442 443 /** 444 * @brief 445 * Locks both the referenced primary and client access tokens of a 446 * security subject context. 447 * 448 * @param[in] SubjectContext 449 * A valid security context with both referenced tokens. 450 * 451 * @return 452 * Nothing. 453 */ 454 VOID 455 NTAPI 456 SeLockSubjectContext( 457 _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext) 458 { 459 PTOKEN PrimaryToken, ClientToken; 460 PAGED_CODE(); 461 462 /* Read both tokens */ 463 PrimaryToken = SubjectContext->PrimaryToken; 464 ClientToken = SubjectContext->ClientToken; 465 466 /* Always lock the primary */ 467 SepAcquireTokenLockShared(PrimaryToken); 468 469 /* Lock the impersonation one if it's there */ 470 if (!ClientToken) return; 471 SepAcquireTokenLockShared(ClientToken); 472 } 473 474 /** 475 * @brief 476 * Unlocks both the referenced primary and client access tokens of a 477 * security subject context. 478 * 479 * @param[in] SubjectContext 480 * A valid security context with both referenced tokens. 481 * 482 * @return 483 * Nothing. 484 */ 485 VOID 486 NTAPI 487 SeUnlockSubjectContext( 488 _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext) 489 { 490 PTOKEN PrimaryToken, ClientToken; 491 PAGED_CODE(); 492 493 /* Read both tokens */ 494 PrimaryToken = SubjectContext->PrimaryToken; 495 ClientToken = SubjectContext->ClientToken; 496 497 /* Unlock the impersonation one if it's there */ 498 if (ClientToken) 499 { 500 SepReleaseTokenLock(ClientToken); 501 } 502 503 /* Always unlock the primary one */ 504 SepReleaseTokenLock(PrimaryToken); 505 } 506 507 /** 508 * @brief 509 * Releases both the primary and client tokens of a security 510 * subject context. 511 * 512 * @param[in] SubjectContext 513 * The captured security context. 514 * 515 * @return 516 * Nothing. 517 */ 518 VOID 519 NTAPI 520 SeReleaseSubjectContext( 521 _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext) 522 { 523 PAGED_CODE(); 524 525 /* Drop reference on the primary */ 526 ObFastDereferenceObject(&PsGetCurrentProcess()->Token, SubjectContext->PrimaryToken); 527 SubjectContext->PrimaryToken = NULL; 528 529 /* Drop reference on the impersonation, if there was one */ 530 PsDereferenceImpersonationToken(SubjectContext->ClientToken); 531 SubjectContext->ClientToken = NULL; 532 } 533 534 /** 535 * @brief 536 * An extended function that creates an access state. 537 * 538 * @param[in] Thread 539 * Valid thread object where subject context is to be captured. 540 * 541 * @param[in] Process 542 * Valid process object where subject context is to be captured. 543 * 544 * @param[in,out] AccessState 545 * An initialized returned parameter to an access state. 546 * 547 * @param[in] AuxData 548 * Auxiliary security data for access state. 549 * 550 * @param[in] Access 551 * Type of access mask to assign. 552 * 553 * @param[in] GenericMapping 554 * Generic mapping for the access state to assign. 555 * 556 * @return 557 * Returns STATUS_SUCCESS. 558 */ 559 NTSTATUS 560 NTAPI 561 SeCreateAccessStateEx( 562 _In_ PETHREAD Thread, 563 _In_ PEPROCESS Process, 564 _Inout_ PACCESS_STATE AccessState, 565 _In_ PAUX_ACCESS_DATA AuxData, 566 _In_ ACCESS_MASK Access, 567 _In_ PGENERIC_MAPPING GenericMapping) 568 { 569 ACCESS_MASK AccessMask = Access; 570 PTOKEN Token; 571 PAGED_CODE(); 572 573 /* Map the Generic Acess to Specific Access if we have a Mapping */ 574 if ((Access & GENERIC_ACCESS) && (GenericMapping)) 575 { 576 RtlMapGenericMask(&AccessMask, GenericMapping); 577 } 578 579 /* Initialize the Access State */ 580 RtlZeroMemory(AccessState, sizeof(ACCESS_STATE)); 581 ASSERT(AccessState->SecurityDescriptor == NULL); 582 ASSERT(AccessState->PrivilegesAllocated == FALSE); 583 584 /* Initialize and save aux data */ 585 RtlZeroMemory(AuxData, sizeof(AUX_ACCESS_DATA)); 586 AccessState->AuxData = AuxData; 587 588 /* Capture the Subject Context */ 589 SeCaptureSubjectContextEx(Thread, 590 Process, 591 &AccessState->SubjectSecurityContext); 592 593 /* Set Access State Data */ 594 AccessState->RemainingDesiredAccess = AccessMask; 595 AccessState->OriginalDesiredAccess = AccessMask; 596 ExAllocateLocallyUniqueId(&AccessState->OperationID); 597 598 /* Get the Token to use */ 599 Token = SeQuerySubjectContextToken(&AccessState->SubjectSecurityContext); 600 601 /* Check for Travers Privilege */ 602 if (Token->TokenFlags & TOKEN_HAS_TRAVERSE_PRIVILEGE) 603 { 604 /* Preserve the Traverse Privilege */ 605 AccessState->Flags = TOKEN_HAS_TRAVERSE_PRIVILEGE; 606 } 607 608 /* Set the Auxiliary Data */ 609 AuxData->PrivilegeSet = (PPRIVILEGE_SET)((ULONG_PTR)AccessState + 610 FIELD_OFFSET(ACCESS_STATE, 611 Privileges)); 612 if (GenericMapping) AuxData->GenericMapping = *GenericMapping; 613 614 /* Return Sucess */ 615 return STATUS_SUCCESS; 616 } 617 618 /** 619 * @brief 620 * Creates an access state. 621 * 622 * @param[in,out] AccessState 623 * An initialized returned parameter to an access state. 624 * 625 * @param[in] AuxData 626 * Auxiliary security data for access state. 627 * 628 * @param[in] Access 629 * Type of access mask to assign. 630 * 631 * @param[in] GenericMapping 632 * Generic mapping for the access state to assign. 633 * 634 * @return 635 * See SeCreateAccessStateEx. 636 */ 637 NTSTATUS 638 NTAPI 639 SeCreateAccessState( 640 _Inout_ PACCESS_STATE AccessState, 641 _In_ PAUX_ACCESS_DATA AuxData, 642 _In_ ACCESS_MASK Access, 643 _In_ PGENERIC_MAPPING GenericMapping) 644 { 645 PAGED_CODE(); 646 647 /* Call the extended API */ 648 return SeCreateAccessStateEx(PsGetCurrentThread(), 649 PsGetCurrentProcess(), 650 AccessState, 651 AuxData, 652 Access, 653 GenericMapping); 654 } 655 656 /** 657 * @brief 658 * Deletes an allocated access state from the memory. 659 * 660 * @param[in] AccessState 661 * A valid access state. 662 * 663 * @return 664 * Nothing. 665 */ 666 VOID 667 NTAPI 668 SeDeleteAccessState( 669 _In_ PACCESS_STATE AccessState) 670 { 671 PAUX_ACCESS_DATA AuxData; 672 PAGED_CODE(); 673 674 /* Get the Auxiliary Data */ 675 AuxData = AccessState->AuxData; 676 677 /* Deallocate Privileges */ 678 if (AccessState->PrivilegesAllocated) 679 ExFreePoolWithTag(AuxData->PrivilegeSet, TAG_PRIVILEGE_SET); 680 681 /* Deallocate Name and Type Name */ 682 if (AccessState->ObjectName.Buffer) 683 { 684 ExFreePool(AccessState->ObjectName.Buffer); 685 } 686 687 if (AccessState->ObjectTypeName.Buffer) 688 { 689 ExFreePool(AccessState->ObjectTypeName.Buffer); 690 } 691 692 /* Release the Subject Context */ 693 SeReleaseSubjectContext(&AccessState->SubjectSecurityContext); 694 } 695 696 /** 697 * @brief 698 * Sets a new generic mapping for an allocated access state. 699 * 700 * @param[in] AccessState 701 * A valid access state. 702 * 703 * @param[in] GenericMapping 704 * New generic mapping to assign. 705 * 706 * @return 707 * Nothing. 708 */ 709 VOID 710 NTAPI 711 SeSetAccessStateGenericMapping( 712 _In_ PACCESS_STATE AccessState, 713 _In_ PGENERIC_MAPPING GenericMapping) 714 { 715 PAGED_CODE(); 716 717 /* Set the Generic Mapping */ 718 ((PAUX_ACCESS_DATA)AccessState->AuxData)->GenericMapping = *GenericMapping; 719 } 720 721 /** 722 * @brief 723 * Creates a client security context. 724 * 725 * @param[in] Thread 726 * Thread object of the client where impersonation has to begin. 727 * 728 * @param[in] Qos 729 * Quality of service to specify what kind of impersonation to be done. 730 * 731 * @param[in] RemoteClient 732 * If set to TRUE, the client that we're going to impersonate is remote. 733 * 734 * @param[out] ClientContext 735 * The returned security client context. 736 * 737 * @return 738 * See SepCreateClientSecurity. 739 */ 740 NTSTATUS 741 NTAPI 742 SeCreateClientSecurity( 743 _In_ PETHREAD Thread, 744 _In_ PSECURITY_QUALITY_OF_SERVICE Qos, 745 _In_ BOOLEAN RemoteClient, 746 _Out_ PSECURITY_CLIENT_CONTEXT ClientContext) 747 { 748 TOKEN_TYPE TokenType; 749 BOOLEAN ThreadEffectiveOnly; 750 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; 751 PACCESS_TOKEN Token; 752 NTSTATUS Status; 753 PAGED_CODE(); 754 755 /* Reference the correct token */ 756 Token = PsReferenceEffectiveToken(Thread, 757 &TokenType, 758 &ThreadEffectiveOnly, 759 &ImpersonationLevel); 760 761 /* Create client security from it */ 762 Status = SepCreateClientSecurity(Token, 763 Qos, 764 RemoteClient, 765 TokenType, 766 ThreadEffectiveOnly, 767 ImpersonationLevel, 768 ClientContext); 769 770 /* Check if we failed or static tracking was used */ 771 if (!(NT_SUCCESS(Status)) || (Qos->ContextTrackingMode == SECURITY_STATIC_TRACKING)) 772 { 773 /* Dereference our copy since it's not being used */ 774 ObDereferenceObject(Token); 775 } 776 777 /* Return status */ 778 return Status; 779 } 780 781 /** 782 * @brief 783 * Creates a client security context based upon the captured security 784 * subject context. 785 * 786 * @param[in] SubjectContext 787 * The captured subject context where client security is to be created 788 * from. 789 * 790 * @param[in] ClientSecurityQos 791 * Quality of service to specify what kind of impersonation to be done. 792 * 793 * @param[in] ServerIsRemote 794 * If set to TRUE, the client that we're going to impersonate is remote. 795 * 796 * @param[out] ClientContext 797 * The returned security client context. 798 * 799 * @return 800 * See SepCreateClientSecurity. 801 */ 802 NTSTATUS 803 NTAPI 804 SeCreateClientSecurityFromSubjectContext( 805 _In_ PSECURITY_SUBJECT_CONTEXT SubjectContext, 806 _In_ PSECURITY_QUALITY_OF_SERVICE ClientSecurityQos, 807 _In_ BOOLEAN ServerIsRemote, 808 _Out_ PSECURITY_CLIENT_CONTEXT ClientContext) 809 { 810 PACCESS_TOKEN Token; 811 NTSTATUS Status; 812 PAGED_CODE(); 813 814 /* Get the right token and reference it */ 815 Token = SeQuerySubjectContextToken(SubjectContext); 816 ObReferenceObject(Token); 817 818 /* Create the context */ 819 Status = SepCreateClientSecurity(Token, 820 ClientSecurityQos, 821 ServerIsRemote, 822 SubjectContext->ClientToken ? 823 TokenImpersonation : TokenPrimary, 824 FALSE, 825 SubjectContext->ImpersonationLevel, 826 ClientContext); 827 828 /* Check if we failed or static tracking was used */ 829 if (!(NT_SUCCESS(Status)) || 830 (ClientSecurityQos->ContextTrackingMode == SECURITY_STATIC_TRACKING)) 831 { 832 /* Dereference our copy since it's not being used */ 833 ObDereferenceObject(Token); 834 } 835 836 /* Return status */ 837 return Status; 838 } 839 840 /** 841 * @brief 842 * Extended function that impersonates a client. 843 * 844 * @param[in] ClientContext 845 * A valid client context. 846 * 847 * @param[in] ServerThread 848 * The thread where impersonation is to be done. 849 * 850 * @return 851 * STATUS_SUCCESS is returned if the calling thread successfully impersonates 852 * the client. A failure NTSTATUS code is returned otherwise. 853 */ 854 NTSTATUS 855 NTAPI 856 SeImpersonateClientEx( 857 _In_ PSECURITY_CLIENT_CONTEXT ClientContext, 858 _In_opt_ PETHREAD ServerThread) 859 { 860 BOOLEAN EffectiveOnly; 861 PAGED_CODE(); 862 863 /* Check if direct access is requested */ 864 if (!ClientContext->DirectlyAccessClientToken) 865 { 866 /* No, so get the flag from QOS */ 867 EffectiveOnly = ClientContext->SecurityQos.EffectiveOnly; 868 } 869 else 870 { 871 /* Yes, so see if direct access should be effective only */ 872 EffectiveOnly = ClientContext->DirectAccessEffectiveOnly; 873 } 874 875 /* Use the current thread if one was not passed */ 876 if (!ServerThread) ServerThread = PsGetCurrentThread(); 877 878 /* Call the lower layer routine */ 879 return PsImpersonateClient(ServerThread, 880 ClientContext->ClientToken, 881 TRUE, 882 EffectiveOnly, 883 ClientContext->SecurityQos.ImpersonationLevel); 884 } 885 886 /** 887 * @brief 888 * Impersonates a client user. 889 * 890 * @param[in] ClientContext 891 * A valid client context. 892 * 893 * @param[in] ServerThread 894 * The thread where impersonation is to be done. 895 * * 896 * @return 897 * Nothing. 898 */ 899 VOID 900 NTAPI 901 SeImpersonateClient( 902 _In_ PSECURITY_CLIENT_CONTEXT ClientContext, 903 _In_opt_ PETHREAD ServerThread) 904 { 905 PAGED_CODE(); 906 907 /* Call the new API */ 908 SeImpersonateClientEx(ClientContext, ServerThread); 909 } 910 911 /* EOF */ 912