1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Security token implementation support 5 * COPYRIGHT: Copyright David Welch <welch@cwcom.net> 6 * Copyright 2021 George Bișoc <george.bisoc@reactos.org> 7 */ 8 9 /* INCLUDES *******************************************************************/ 10 11 #include <ntoskrnl.h> 12 #define NDEBUG 13 #include <debug.h> 14 15 #include <ntlsa.h> 16 17 /* GLOBALS ********************************************************************/ 18 19 POBJECT_TYPE SeTokenObjectType = NULL; 20 21 TOKEN_SOURCE SeSystemTokenSource = {"*SYSTEM*", {0}}; 22 LUID SeSystemAuthenticationId = SYSTEM_LUID; 23 LUID SeAnonymousAuthenticationId = ANONYMOUS_LOGON_LUID; 24 25 static GENERIC_MAPPING SepTokenMapping = { 26 TOKEN_READ, 27 TOKEN_WRITE, 28 TOKEN_EXECUTE, 29 TOKEN_ALL_ACCESS 30 }; 31 32 static const INFORMATION_CLASS_INFO SeTokenInformationClass[] = { 33 34 /* Class 0 not used, blame MS! */ 35 IQS_NONE, 36 37 /* TokenUser */ 38 IQS_SAME(TOKEN_USER, ULONG, ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE), 39 /* TokenGroups */ 40 IQS_SAME(TOKEN_GROUPS, ULONG, ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE), 41 /* TokenPrivileges */ 42 IQS_SAME(TOKEN_PRIVILEGES, ULONG, ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE), 43 /* TokenOwner */ 44 IQS_SAME(TOKEN_OWNER, ULONG, ICIF_QUERY | ICIF_SET | ICIF_SIZE_VARIABLE), 45 /* TokenPrimaryGroup */ 46 IQS_SAME(TOKEN_PRIMARY_GROUP, ULONG, ICIF_QUERY | ICIF_SET | ICIF_SIZE_VARIABLE), 47 /* TokenDefaultDacl */ 48 IQS_SAME(TOKEN_DEFAULT_DACL, ULONG, ICIF_QUERY | ICIF_SET | ICIF_SIZE_VARIABLE), 49 /* TokenSource */ 50 IQS_SAME(TOKEN_SOURCE, ULONG, ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE), 51 /* TokenType */ 52 IQS_SAME(TOKEN_TYPE, ULONG, ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE), 53 /* TokenImpersonationLevel */ 54 IQS_SAME(SECURITY_IMPERSONATION_LEVEL, ULONG, ICIF_QUERY), 55 /* TokenStatistics */ 56 IQS_SAME(TOKEN_STATISTICS, ULONG, ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE), 57 /* TokenRestrictedSids */ 58 IQS_SAME(TOKEN_GROUPS, ULONG, ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE), 59 /* TokenSessionId */ 60 IQS_SAME(ULONG, ULONG, ICIF_QUERY | ICIF_SET), 61 /* TokenGroupsAndPrivileges */ 62 IQS_SAME(TOKEN_GROUPS_AND_PRIVILEGES, ULONG, ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE), 63 /* TokenSessionReference */ 64 IQS_SAME(ULONG, ULONG, ICIF_SET), 65 /* TokenSandBoxInert */ 66 IQS_SAME(ULONG, ULONG, ICIF_QUERY), 67 /* TokenAuditPolicy */ 68 IQS_SAME(TOKEN_AUDIT_POLICY_INFORMATION, ULONG, ICIF_SET | ICIF_SET_SIZE_VARIABLE), 69 /* TokenOrigin */ 70 IQS_SAME(TOKEN_ORIGIN, ULONG, ICIF_QUERY | ICIF_SET), 71 }; 72 73 /* FUNCTIONS *****************************************************************/ 74 75 /** 76 * @brief 77 * Creates a lock for the token. 78 * 79 * @param[in,out] Token 80 * A token which lock has to be created. 81 * 82 * @return 83 * STATUS_SUCCESS if the pool allocation and resource initialisation have 84 * completed successfully, otherwise STATUS_INSUFFICIENT_RESOURCES on a 85 * pool allocation failure. 86 */ 87 static 88 NTSTATUS 89 SepCreateTokenLock( 90 _Inout_ PTOKEN Token) 91 { 92 PAGED_CODE(); 93 94 Token->TokenLock = ExAllocatePoolWithTag(NonPagedPool, 95 sizeof(ERESOURCE), 96 TAG_SE_TOKEN_LOCK); 97 if (Token->TokenLock == NULL) 98 { 99 DPRINT1("SepCreateTokenLock(): Failed to allocate memory!\n"); 100 return STATUS_INSUFFICIENT_RESOURCES; 101 } 102 103 ExInitializeResourceLite(Token->TokenLock); 104 return STATUS_SUCCESS; 105 } 106 107 /** 108 * @brief 109 * Deletes a lock of a token. 110 * 111 * @param[in,out] Token 112 * A token which contains the lock. 113 * 114 * @return 115 * Nothing. 116 */ 117 static 118 VOID 119 SepDeleteTokenLock( 120 _Inout_ PTOKEN Token) 121 { 122 PAGED_CODE(); 123 124 ExDeleteResourceLite(Token->TokenLock); 125 ExFreePoolWithTag(Token->TokenLock, TAG_SE_TOKEN_LOCK); 126 } 127 128 /** 129 * @brief 130 * Compares the elements of SID arrays provided by tokens. 131 * The elements that are being compared for equality are 132 * the SIDs and their attributes. 133 * 134 * @param[in] SidArrayToken1 135 * SID array from the first token. 136 * 137 * @param[in] CountSidArray1 138 * SID count array from the first token. 139 * 140 * @param[in] SidArrayToken2 141 * SID array from the second token. 142 * 143 * @param[in] CountSidArray2 144 * SID count array from the second token. 145 * 146 * @return 147 * Returns TRUE if the elements match from either arrays, 148 * FALSE otherwise. 149 */ 150 static 151 BOOLEAN 152 SepCompareSidAndAttributesFromTokens( 153 _In_ PSID_AND_ATTRIBUTES SidArrayToken1, 154 _In_ ULONG CountSidArray1, 155 _In_ PSID_AND_ATTRIBUTES SidArrayToken2, 156 _In_ ULONG CountSidArray2) 157 { 158 ULONG FirstCount, SecondCount; 159 PSID_AND_ATTRIBUTES FirstSidArray, SecondSidArray; 160 PAGED_CODE(); 161 162 /* Bail out if index counters provided are not equal */ 163 if (CountSidArray1 != CountSidArray2) 164 { 165 DPRINT("SepCompareSidAndAttributesFromTokens(): Index counters are not the same!\n"); 166 return FALSE; 167 } 168 169 /* Loop over the SID arrays and compare them */ 170 for (FirstCount = 0; FirstCount < CountSidArray1; FirstCount++) 171 { 172 for (SecondCount = 0; SecondCount < CountSidArray2; SecondCount++) 173 { 174 FirstSidArray = &SidArrayToken1[FirstCount]; 175 SecondSidArray = &SidArrayToken2[SecondCount]; 176 177 if (RtlEqualSid(FirstSidArray->Sid, SecondSidArray->Sid) && 178 FirstSidArray->Attributes == SecondSidArray->Attributes) 179 { 180 break; 181 } 182 } 183 184 /* We've exhausted the array of the second token without finding this one */ 185 if (SecondCount == CountSidArray2) 186 { 187 DPRINT("SepCompareSidAndAttributesFromTokens(): No matching elements could be found in either token!\n"); 188 return FALSE; 189 } 190 } 191 192 return TRUE; 193 } 194 195 /** 196 * @brief 197 * Compares the elements of privilege arrays provided by tokens. 198 * The elements that are being compared for equality are 199 * the privileges and their attributes. 200 * 201 * @param[in] PrivArrayToken1 202 * Privilege array from the first token. 203 * 204 * @param[in] CountPrivArray1 205 * Privilege count array from the first token. 206 * 207 * @param[in] PrivArrayToken2 208 * Privilege array from the second token. 209 * 210 * @param[in] CountPrivArray2 211 * Privilege count array from the second token. 212 * 213 * @return 214 * Returns TRUE if the elements match from either arrays, 215 * FALSE otherwise. 216 */ 217 static 218 BOOLEAN 219 SepComparePrivilegeAndAttributesFromTokens( 220 _In_ PLUID_AND_ATTRIBUTES PrivArrayToken1, 221 _In_ ULONG CountPrivArray1, 222 _In_ PLUID_AND_ATTRIBUTES PrivArrayToken2, 223 _In_ ULONG CountPrivArray2) 224 { 225 ULONG FirstCount, SecondCount; 226 PLUID_AND_ATTRIBUTES FirstPrivArray, SecondPrivArray; 227 PAGED_CODE(); 228 229 /* Bail out if index counters provided are not equal */ 230 if (CountPrivArray1 != CountPrivArray2) 231 { 232 DPRINT("SepComparePrivilegeAndAttributesFromTokens(): Index counters are not the same!\n"); 233 return FALSE; 234 } 235 236 /* Loop over the privilege arrays and compare them */ 237 for (FirstCount = 0; FirstCount < CountPrivArray1; FirstCount++) 238 { 239 for (SecondCount = 0; SecondCount < CountPrivArray2; SecondCount++) 240 { 241 FirstPrivArray = &PrivArrayToken1[FirstCount]; 242 SecondPrivArray = &PrivArrayToken2[SecondCount]; 243 244 if (RtlEqualLuid(&FirstPrivArray->Luid, &SecondPrivArray->Luid) && 245 FirstPrivArray->Attributes == SecondPrivArray->Attributes) 246 { 247 break; 248 } 249 } 250 251 /* We've exhausted the array of the second token without finding this one */ 252 if (SecondCount == CountPrivArray2) 253 { 254 DPRINT("SepComparePrivilegeAndAttributesFromTokens(): No matching elements could be found in either token!\n"); 255 return FALSE; 256 } 257 } 258 259 return TRUE; 260 } 261 262 /** 263 * @brief 264 * Compares tokens if they're equal based on all the following properties. If all 265 * of the said conditions are met then the tokens are deemed as equal. 266 * 267 * - Every SID that is present in either token is also present in the other one. 268 * - Both or none of the tokens are restricted. 269 * - If both tokens are restricted, every SID that is restricted in either token is 270 * also restricted in the other one. 271 * - Every privilege present in either token is also present in the other one. 272 * 273 * @param[in] FirstToken 274 * The first token. 275 * 276 * @param[in] SecondToken 277 * The second token. 278 * 279 * @param[out] Equal 280 * The retrieved value which determines if the tokens are 281 * equal or not. 282 * 283 * @return 284 * Returns STATUS_SUCCESS. 285 */ 286 static 287 NTSTATUS 288 SepCompareTokens( 289 _In_ PTOKEN FirstToken, 290 _In_ PTOKEN SecondToken, 291 _Out_ PBOOLEAN Equal) 292 { 293 BOOLEAN Restricted, IsEqual = FALSE; 294 PAGED_CODE(); 295 296 ASSERT(FirstToken != SecondToken); 297 298 /* Lock the tokens */ 299 SepAcquireTokenLockShared(FirstToken); 300 SepAcquireTokenLockShared(SecondToken); 301 302 /* Check if every SID that is present in either token is also present in the other one */ 303 if (!SepCompareSidAndAttributesFromTokens(FirstToken->UserAndGroups, 304 FirstToken->UserAndGroupCount, 305 SecondToken->UserAndGroups, 306 SecondToken->UserAndGroupCount)) 307 { 308 goto Quit; 309 } 310 311 /* Is one token restricted but the other isn't? */ 312 Restricted = SeTokenIsRestricted(FirstToken); 313 if (Restricted != SeTokenIsRestricted(SecondToken)) 314 { 315 /* If that's the case then bail out */ 316 goto Quit; 317 } 318 319 /* 320 * If both tokens are restricted check if every SID 321 * that is restricted in either token is also restricted 322 * in the other one. 323 */ 324 if (Restricted) 325 { 326 if (!SepCompareSidAndAttributesFromTokens(FirstToken->RestrictedSids, 327 FirstToken->RestrictedSidCount, 328 SecondToken->RestrictedSids, 329 SecondToken->RestrictedSidCount)) 330 { 331 goto Quit; 332 } 333 } 334 335 /* Check if every privilege present in either token is also present in the other one */ 336 if (!SepComparePrivilegeAndAttributesFromTokens(FirstToken->Privileges, 337 FirstToken->PrivilegeCount, 338 SecondToken->Privileges, 339 SecondToken->PrivilegeCount)) 340 { 341 goto Quit; 342 } 343 344 /* If we're here then the tokens are equal */ 345 IsEqual = TRUE; 346 DPRINT("SepCompareTokens(): Tokens are equal!\n"); 347 348 Quit: 349 /* Unlock the tokens */ 350 SepReleaseTokenLock(SecondToken); 351 SepReleaseTokenLock(FirstToken); 352 353 *Equal = IsEqual; 354 return STATUS_SUCCESS; 355 } 356 357 /** 358 * @brief 359 * Private function that impersonates the system's anonymous logon token. 360 * The major bulk of the impersonation procedure is done here. 361 * 362 * @param[in] Thread 363 * The executive thread object that is to impersonate the client. 364 * 365 * @param[in] PreviousMode 366 * The access processor mode, indicating if the call is executed 367 * in kernel or user mode. 368 * 369 * @return 370 * Returns STATUS_SUCCESS if the impersonation has succeeded. 371 * STATUS_UNSUCCESSFUL is returned if the primary token couldn't be 372 * obtained from the current process to perform additional tasks. 373 * STATUS_ACCESS_DENIED is returned if the process' primary token is 374 * restricted, which for this matter we cannot impersonate onto a 375 * restricted process. Otherwise a failure NTSTATUS code is returned. 376 */ 377 static 378 NTSTATUS 379 SepImpersonateAnonymousToken( 380 _In_ PETHREAD Thread, 381 _In_ KPROCESSOR_MODE PreviousMode) 382 { 383 NTSTATUS Status; 384 PTOKEN TokenToImpersonate, ProcessToken; 385 ULONG IncludeEveryoneValueData; 386 PAGED_CODE(); 387 388 /* 389 * We must check first which kind of token 390 * shall we assign for the thread to impersonate, 391 * the one with Everyone Group SID or the other 392 * without. Invoke the registry helper to 393 * return the data value for us. 394 */ 395 Status = SepRegQueryHelper(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Lsa", 396 L"EveryoneIncludesAnonymous", 397 REG_DWORD, 398 sizeof(IncludeEveryoneValueData), 399 &IncludeEveryoneValueData); 400 if (!NT_SUCCESS(Status)) 401 { 402 DPRINT1("SepRegQueryHelper(): Failed to query the registry value (Status 0x%lx)\n", Status); 403 return Status; 404 } 405 406 if (IncludeEveryoneValueData == 0) 407 { 408 DPRINT("SepImpersonateAnonymousToken(): Assigning the token not including the Everyone Group SID...\n"); 409 TokenToImpersonate = SeAnonymousLogonTokenNoEveryone; 410 } 411 else 412 { 413 DPRINT("SepImpersonateAnonymousToken(): Assigning the token including the Everyone Group SID...\n"); 414 TokenToImpersonate = SeAnonymousLogonToken; 415 } 416 417 /* 418 * Tell the object manager that we're going to use this token 419 * object now by incrementing the reference count. 420 */ 421 Status = ObReferenceObjectByPointer(TokenToImpersonate, 422 TOKEN_IMPERSONATE, 423 SeTokenObjectType, 424 PreviousMode); 425 if (!NT_SUCCESS(Status)) 426 { 427 DPRINT1("SepImpersonateAnonymousToken(): Couldn't be able to use the token, bail out...\n"); 428 return Status; 429 } 430 431 /* 432 * Reference the primary token of the current process that the anonymous 433 * logon token impersonation procedure is being performed. We'll be going 434 * to use the process' token to figure out if the process is actually 435 * restricted or not. 436 */ 437 ProcessToken = PsReferencePrimaryToken(PsGetCurrentProcess()); 438 if (!ProcessToken) 439 { 440 DPRINT1("SepImpersonateAnonymousToken(): Couldn't be able to get the process' primary token, bail out...\n"); 441 ObDereferenceObject(TokenToImpersonate); 442 return STATUS_UNSUCCESSFUL; 443 } 444 445 /* Now, is the token from the current process restricted? */ 446 if (SeTokenIsRestricted(ProcessToken)) 447 { 448 DPRINT1("SepImpersonateAnonymousToken(): The process is restricted, can't do anything. Bail out...\n"); 449 PsDereferencePrimaryToken(ProcessToken); 450 ObDereferenceObject(TokenToImpersonate); 451 return STATUS_ACCESS_DENIED; 452 } 453 454 /* 455 * Finally it's time to impersonate! But first, fast dereference the 456 * process' primary token as we no longer need it. 457 */ 458 ObFastDereferenceObject(&PsGetCurrentProcess()->Token, ProcessToken); 459 Status = PsImpersonateClient(Thread, TokenToImpersonate, TRUE, FALSE, SecurityImpersonation); 460 if (!NT_SUCCESS(Status)) 461 { 462 DPRINT1("SepImpersonateAnonymousToken(): Failed to impersonate, bail out...\n"); 463 ObDereferenceObject(TokenToImpersonate); 464 return Status; 465 } 466 467 return Status; 468 } 469 470 /** 471 * @brief 472 * Updates the token's flags based upon the privilege that the token 473 * has been granted. The flag can either be taken out or given to the token 474 * if the attributes of the specified privilege is enabled or not. 475 * 476 * @param[in,out] Token 477 * The token where the flags are to be changed. 478 * 479 * @param[in] Index 480 * The index count which represents the total sum of privileges. The count in question 481 * MUST NOT exceed the expected privileges count of the token. 482 * 483 * @return 484 * Nothing. 485 */ 486 static 487 VOID 488 SepUpdateSinglePrivilegeFlagToken( 489 _Inout_ PTOKEN Token, 490 _In_ ULONG Index) 491 { 492 ULONG TokenFlag; 493 ASSERT(Index < Token->PrivilegeCount); 494 495 /* The high part of all values we are interested in is 0 */ 496 if (Token->Privileges[Index].Luid.HighPart != 0) 497 { 498 return; 499 } 500 501 /* Check for certain privileges to update flags */ 502 if (Token->Privileges[Index].Luid.LowPart == SE_CHANGE_NOTIFY_PRIVILEGE) 503 { 504 TokenFlag = TOKEN_HAS_TRAVERSE_PRIVILEGE; 505 } 506 else if (Token->Privileges[Index].Luid.LowPart == SE_BACKUP_PRIVILEGE) 507 { 508 TokenFlag = TOKEN_HAS_BACKUP_PRIVILEGE; 509 } 510 else if (Token->Privileges[Index].Luid.LowPart == SE_RESTORE_PRIVILEGE) 511 { 512 TokenFlag = TOKEN_HAS_RESTORE_PRIVILEGE; 513 } 514 else if (Token->Privileges[Index].Luid.LowPart == SE_IMPERSONATE_PRIVILEGE) 515 { 516 TokenFlag = TOKEN_HAS_IMPERSONATE_PRIVILEGE; 517 } 518 else 519 { 520 /* Nothing to do */ 521 return; 522 } 523 524 /* Check if the specified privilege is enabled */ 525 if (Token->Privileges[Index].Attributes & SE_PRIVILEGE_ENABLED) 526 { 527 /* It is enabled, so set the flag */ 528 Token->TokenFlags |= TokenFlag; 529 } 530 else 531 { 532 /* Is is disabled, so remove the flag */ 533 Token->TokenFlags &= ~TokenFlag; 534 } 535 } 536 537 /** 538 * @brief 539 * Updates the token's flags based upon the privilege that the token 540 * has been granted. The function uses the private helper, SepUpdateSinglePrivilegeFlagToken, 541 * in order to update the flags of a token. 542 * 543 * @param[in,out] Token 544 * The token where the flags are to be changed. 545 * 546 * @return 547 * Nothing. 548 */ 549 static 550 VOID 551 SepUpdatePrivilegeFlagsToken( 552 _Inout_ PTOKEN Token) 553 { 554 ULONG i; 555 556 /* Loop all privileges */ 557 for (i = 0; i < Token->PrivilegeCount; i++) 558 { 559 /* Updates the flags for this privilege */ 560 SepUpdateSinglePrivilegeFlagToken(Token, i); 561 } 562 } 563 564 /** 565 * @brief 566 * Removes a privilege from the token. 567 * 568 * @param[in,out] Token 569 * The token where the privilege is to be removed. 570 * 571 * @param[in] Index 572 * The index count which represents the number position of the privilege 573 * we want to remove. 574 * 575 * @return 576 * Nothing. 577 */ 578 static 579 VOID 580 SepRemovePrivilegeToken( 581 _Inout_ PTOKEN Token, 582 _In_ ULONG Index) 583 { 584 ULONG MoveCount; 585 ASSERT(Index < Token->PrivilegeCount); 586 587 /* Calculate the number of trailing privileges */ 588 MoveCount = Token->PrivilegeCount - Index - 1; 589 if (MoveCount != 0) 590 { 591 /* Move them one location ahead */ 592 RtlMoveMemory(&Token->Privileges[Index], 593 &Token->Privileges[Index + 1], 594 MoveCount * sizeof(LUID_AND_ATTRIBUTES)); 595 } 596 597 /* Update privilege count */ 598 Token->PrivilegeCount--; 599 } 600 601 /** 602 * @brief 603 * Removes a group from the token. 604 * 605 * @param[in,out] Token 606 * The token where the group is to be removed. 607 * 608 * @param[in] Index 609 * The index count which represents the number position of the group 610 * we want to remove. 611 * 612 * @return 613 * Nothing. 614 */ 615 static 616 VOID 617 SepRemoveUserGroupToken( 618 _Inout_ PTOKEN Token, 619 _In_ ULONG Index) 620 { 621 ULONG MoveCount; 622 ASSERT(Index < Token->UserAndGroupCount); 623 624 /* Calculate the number of trailing groups */ 625 MoveCount = Token->UserAndGroupCount - Index - 1; 626 if (MoveCount != 0) 627 { 628 /* Time to remove the group by moving one location ahead */ 629 RtlMoveMemory(&Token->UserAndGroups[Index], 630 &Token->UserAndGroups[Index + 1], 631 MoveCount * sizeof(SID_AND_ATTRIBUTES)); 632 } 633 634 /* Remove one group count */ 635 Token->UserAndGroupCount--; 636 } 637 638 /** 639 * @unimplemented 640 * @brief 641 * Frees (de-allocates) the proxy data memory block of a token. 642 * 643 * @param[in,out] ProxyData 644 * The proxy data to be freed. 645 * 646 * @return 647 * Nothing. 648 */ 649 VOID 650 NTAPI 651 SepFreeProxyData( 652 _Inout_ PVOID ProxyData) 653 { 654 UNIMPLEMENTED; 655 } 656 657 /** 658 * @unimplemented 659 * @brief 660 * Copies the proxy data from the source into the destination of a token. 661 * 662 * @param[out] Dest 663 * The destination path where the proxy data is to be copied to. 664 * 665 * @param[in] Src 666 * The source path where the proxy data is be copied from. 667 * 668 * @return 669 * To be added... 670 */ 671 NTSTATUS 672 NTAPI 673 SepCopyProxyData( 674 _Out_ PVOID* Dest, 675 _In_ PVOID Src) 676 { 677 UNIMPLEMENTED; 678 return STATUS_NOT_IMPLEMENTED; 679 } 680 681 /** 682 * @brief 683 * Replaces the old access token of a process (pointed by the EPROCESS kernel structure) with a 684 * new access token. The new access token must be a primary token for use. 685 * 686 * @param[in] Process 687 * The process instance where its access token is about to be replaced. 688 * 689 * @param[in] NewAccessToken 690 * The new token that it's going to replace the old one. 691 * 692 * @param[out] OldAccessToken 693 * The returned old token that's been replaced, which the caller can do anything. 694 * 695 * @return 696 * Returns STATUS_SUCCESS if the exchange operation between tokens has completed successfully. 697 * STATUS_BAD_TOKEN_TYPE is returned if the new token is not a primary one so that we cannot 698 * exchange it with the old one from the process. STATUS_TOKEN_ALREADY_IN_USE is returned if 699 * both tokens aren't equal which means one of them has different properties (groups, privileges, etc.) 700 * and as such one of them is currently in use. A failure NTSTATUS code is returned otherwise. 701 */ 702 NTSTATUS 703 NTAPI 704 SeExchangePrimaryToken( 705 _In_ PEPROCESS Process, 706 _In_ PACCESS_TOKEN NewAccessToken, 707 _Out_ PACCESS_TOKEN* OldAccessToken) 708 { 709 PTOKEN OldToken; 710 PTOKEN NewToken = (PTOKEN)NewAccessToken; 711 712 PAGED_CODE(); 713 714 if (NewToken->TokenType != TokenPrimary) 715 return STATUS_BAD_TOKEN_TYPE; 716 717 if (NewToken->TokenInUse) 718 { 719 BOOLEAN IsEqual; 720 NTSTATUS Status; 721 722 /* Maybe we're trying to set the same token */ 723 OldToken = PsReferencePrimaryToken(Process); 724 if (OldToken == NewToken) 725 { 726 /* So it's a nop. */ 727 *OldAccessToken = OldToken; 728 return STATUS_SUCCESS; 729 } 730 731 Status = SepCompareTokens(OldToken, NewToken, &IsEqual); 732 if (!NT_SUCCESS(Status)) 733 { 734 PsDereferencePrimaryToken(OldToken); 735 *OldAccessToken = NULL; 736 return Status; 737 } 738 739 if (!IsEqual) 740 { 741 PsDereferencePrimaryToken(OldToken); 742 *OldAccessToken = NULL; 743 return STATUS_TOKEN_ALREADY_IN_USE; 744 } 745 /* Silently return STATUS_SUCCESS but do not set the new token, 746 * as it's already in use elsewhere. */ 747 *OldAccessToken = OldToken; 748 return STATUS_SUCCESS; 749 } 750 751 /* Lock the new token */ 752 SepAcquireTokenLockExclusive(NewToken); 753 754 /* Mark new token in use */ 755 NewToken->TokenInUse = TRUE; 756 757 /* Set the session ID for the new token */ 758 NewToken->SessionId = MmGetSessionId(Process); 759 760 /* Unlock the new token */ 761 SepReleaseTokenLock(NewToken); 762 763 /* Reference the new token */ 764 ObReferenceObject(NewToken); 765 766 /* Replace the old with the new */ 767 OldToken = ObFastReplaceObject(&Process->Token, NewToken); 768 769 /* Lock the old token */ 770 SepAcquireTokenLockExclusive(OldToken); 771 772 /* Mark the old token as free */ 773 OldToken->TokenInUse = FALSE; 774 775 /* Unlock the old token */ 776 SepReleaseTokenLock(OldToken); 777 778 *OldAccessToken = (PACCESS_TOKEN)OldToken; 779 return STATUS_SUCCESS; 780 } 781 782 /** 783 * @brief 784 * Removes the primary token of a process. 785 * 786 * @param[in,out] Process 787 * The process instance with the access token to be removed. 788 * 789 * @return 790 * Nothing. 791 */ 792 VOID 793 NTAPI 794 SeDeassignPrimaryToken( 795 _Inout_ PEPROCESS Process) 796 { 797 PTOKEN OldToken; 798 799 /* Remove the Token */ 800 OldToken = ObFastReplaceObject(&Process->Token, NULL); 801 802 /* Mark the Old Token as free */ 803 OldToken->TokenInUse = FALSE; 804 805 /* Dereference the Token */ 806 ObDereferenceObject(OldToken); 807 } 808 809 /** 810 * @brief 811 * Computes the length size of a SID. 812 * 813 * @param[in] Count 814 * Total count of entries that have SIDs in them (that being PSID_AND_ATTRIBUTES in this context). 815 * 816 * @param[in] Src 817 * Source that points to the attributes and SID entry structure. 818 * 819 * @return 820 * Returns the total length of a SID size. 821 */ 822 static ULONG 823 RtlLengthSidAndAttributes( 824 _In_ ULONG Count, 825 _In_ PSID_AND_ATTRIBUTES Src) 826 { 827 ULONG i; 828 ULONG uLength; 829 830 PAGED_CODE(); 831 832 uLength = Count * sizeof(SID_AND_ATTRIBUTES); 833 for (i = 0; i < Count; i++) 834 uLength += RtlLengthSid(Src[i].Sid); 835 836 return uLength; 837 } 838 839 /** 840 * @brief 841 * Finds the primary group and default owner entity based on the submitted primary group instance 842 * and an access token. 843 * 844 * @param[in] Token 845 * Access token to begin the search query of primary group and default owner. 846 * 847 * @param[in] PrimaryGroup 848 * A primary group SID to be used for search query, determining if user & groups of a token 849 * and the submitted primary group do match. 850 * 851 * @param[in] DefaultOwner 852 * The default owner. If specified, it's used to determine if the token belongs to the actual user, 853 * that is, being the owner himself. 854 * 855 * @param[out] PrimaryGroupIndex 856 * Returns the primary group index. 857 * 858 * @param[out] DefaultOwnerIndex 859 * Returns the default owner index. 860 * 861 * @return 862 * Returns STATUS_SUCCESS if the find query operation has completed successfully and that at least one 863 * search result is requested by the caller. STATUS_INVALID_PARAMETER is returned if the caller hasn't requested 864 * any search result. STATUS_INVALID_OWNER is returned if the specified default user owner does not match with the other 865 * user from the token. STATUS_INVALID_PRIMARY_GROUP is returned if the specified default primary group does not match with the 866 * other group from the token. 867 */ 868 static NTSTATUS 869 SepFindPrimaryGroupAndDefaultOwner( 870 _In_ PTOKEN Token, 871 _In_ PSID PrimaryGroup, 872 _In_opt_ PSID DefaultOwner, 873 _Out_opt_ PULONG PrimaryGroupIndex, 874 _Out_opt_ PULONG DefaultOwnerIndex) 875 { 876 ULONG i; 877 878 /* We should return at least a search result */ 879 if (!PrimaryGroupIndex && !DefaultOwnerIndex) 880 return STATUS_INVALID_PARAMETER; 881 882 if (PrimaryGroupIndex) 883 { 884 /* Initialize with an invalid index */ 885 // Token->PrimaryGroup = NULL; 886 *PrimaryGroupIndex = Token->UserAndGroupCount; 887 } 888 889 if (DefaultOwnerIndex) 890 { 891 if (DefaultOwner) 892 { 893 /* An owner is specified: check whether this is actually the user */ 894 if (RtlEqualSid(Token->UserAndGroups[0].Sid, DefaultOwner)) 895 { 896 /* 897 * It's the user (first element in array): set it 898 * as the owner and stop the search for it. 899 */ 900 *DefaultOwnerIndex = 0; 901 DefaultOwnerIndex = NULL; 902 } 903 else 904 { 905 /* An owner is specified: initialize with an invalid index */ 906 *DefaultOwnerIndex = Token->UserAndGroupCount; 907 } 908 } 909 else 910 { 911 /* 912 * No owner specified: set the user (first element in array) 913 * as the owner and stop the search for it. 914 */ 915 *DefaultOwnerIndex = 0; 916 DefaultOwnerIndex = NULL; 917 } 918 } 919 920 /* Validate and set the primary group and default owner indices */ 921 for (i = 0; i < Token->UserAndGroupCount; i++) 922 { 923 /* Stop the search if we have found what we searched for */ 924 if (!PrimaryGroupIndex && !DefaultOwnerIndex) 925 break; 926 927 if (DefaultOwnerIndex && DefaultOwner && 928 RtlEqualSid(Token->UserAndGroups[i].Sid, DefaultOwner) && 929 (Token->UserAndGroups[i].Attributes & SE_GROUP_OWNER)) 930 { 931 /* Owner is found, stop the search for it */ 932 *DefaultOwnerIndex = i; 933 DefaultOwnerIndex = NULL; 934 } 935 936 if (PrimaryGroupIndex && 937 RtlEqualSid(Token->UserAndGroups[i].Sid, PrimaryGroup)) 938 { 939 /* Primary group is found, stop the search for it */ 940 // Token->PrimaryGroup = Token->UserAndGroups[i].Sid; 941 *PrimaryGroupIndex = i; 942 PrimaryGroupIndex = NULL; 943 } 944 } 945 946 if (DefaultOwnerIndex) 947 { 948 if (*DefaultOwnerIndex == Token->UserAndGroupCount) 949 return STATUS_INVALID_OWNER; 950 } 951 952 if (PrimaryGroupIndex) 953 { 954 if (*PrimaryGroupIndex == Token->UserAndGroupCount) 955 // if (Token->PrimaryGroup == NULL) 956 return STATUS_INVALID_PRIMARY_GROUP; 957 } 958 959 return STATUS_SUCCESS; 960 } 961 962 /** 963 * @brief 964 * Duplicates an access token, from an existing valid token. 965 * 966 * @param[in] Token 967 * Access token to duplicate. 968 * 969 * @param[in] ObjectAttributes 970 * Object attributes for the new token. 971 * 972 * @param[in] EffectiveOnly 973 * If set to TRUE, the function removes all the disabled privileges and groups of the token 974 * to duplicate. 975 * 976 * @param[in] TokenType 977 * Type of token. 978 * 979 * @param[in] Level 980 * Security impersonation level of a token. 981 * 982 * @param[in] PreviousMode 983 * The processor request level mode. 984 * 985 * @param[out] NewAccessToken 986 * The duplicated token. 987 * 988 * @return 989 * Returns STATUS_SUCCESS if the token has been duplicated. STATUS_INSUFFICIENT_RESOURCES is returned 990 * if memory pool allocation of the dynamic part of the token for duplication has failed due to the lack 991 * of memory resources. A failure NTSTATUS code is returned otherwise. 992 */ 993 NTSTATUS 994 NTAPI 995 SepDuplicateToken( 996 _In_ PTOKEN Token, 997 _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, 998 _In_ BOOLEAN EffectiveOnly, 999 _In_ TOKEN_TYPE TokenType, 1000 _In_ SECURITY_IMPERSONATION_LEVEL Level, 1001 _In_ KPROCESSOR_MODE PreviousMode, 1002 _Out_ PTOKEN* NewAccessToken) 1003 { 1004 NTSTATUS Status; 1005 PTOKEN AccessToken; 1006 PVOID EndMem; 1007 ULONG VariableLength; 1008 ULONG TotalSize; 1009 ULONG PrivilegesIndex, GroupsIndex; 1010 1011 PAGED_CODE(); 1012 1013 /* Compute how much size we need to allocate for the token */ 1014 VariableLength = Token->VariableLength; 1015 TotalSize = FIELD_OFFSET(TOKEN, VariablePart) + VariableLength; 1016 1017 Status = ObCreateObject(PreviousMode, 1018 SeTokenObjectType, 1019 ObjectAttributes, 1020 PreviousMode, 1021 NULL, 1022 TotalSize, 1023 0, 1024 0, 1025 (PVOID*)&AccessToken); 1026 if (!NT_SUCCESS(Status)) 1027 { 1028 DPRINT1("ObCreateObject() failed (Status 0x%lx)\n", Status); 1029 return Status; 1030 } 1031 1032 /* Zero out the buffer and initialize the token */ 1033 RtlZeroMemory(AccessToken, TotalSize); 1034 1035 ExAllocateLocallyUniqueId(&AccessToken->TokenId); 1036 1037 AccessToken->TokenType = TokenType; 1038 AccessToken->ImpersonationLevel = Level; 1039 1040 /* Initialise the lock for the access token */ 1041 Status = SepCreateTokenLock(AccessToken); 1042 if (!NT_SUCCESS(Status)) 1043 { 1044 ObDereferenceObject(AccessToken); 1045 return Status; 1046 } 1047 1048 /* Copy the immutable fields */ 1049 RtlCopyLuid(&AccessToken->TokenSource.SourceIdentifier, 1050 &Token->TokenSource.SourceIdentifier); 1051 RtlCopyMemory(AccessToken->TokenSource.SourceName, 1052 Token->TokenSource.SourceName, 1053 sizeof(Token->TokenSource.SourceName)); 1054 1055 AccessToken->AuthenticationId = Token->AuthenticationId; 1056 AccessToken->ParentTokenId = Token->ParentTokenId; 1057 AccessToken->ExpirationTime = Token->ExpirationTime; 1058 AccessToken->OriginatingLogonSession = Token->OriginatingLogonSession; 1059 1060 /* Lock the source token and copy the mutable fields */ 1061 SepAcquireTokenLockExclusive(Token); 1062 1063 AccessToken->SessionId = Token->SessionId; 1064 RtlCopyLuid(&AccessToken->ModifiedId, &Token->ModifiedId); 1065 1066 AccessToken->TokenFlags = Token->TokenFlags & ~TOKEN_SESSION_NOT_REFERENCED; 1067 1068 /* Reference the logon session */ 1069 Status = SepRmReferenceLogonSession(&AccessToken->AuthenticationId); 1070 if (!NT_SUCCESS(Status)) 1071 { 1072 /* No logon session could be found, bail out */ 1073 DPRINT1("SepRmReferenceLogonSession() failed (Status 0x%lx)\n", Status); 1074 /* Set the flag for proper cleanup by the delete procedure */ 1075 AccessToken->TokenFlags |= TOKEN_SESSION_NOT_REFERENCED; 1076 goto Quit; 1077 } 1078 1079 /* Insert the referenced logon session into the token */ 1080 Status = SepRmInsertLogonSessionIntoToken(AccessToken); 1081 if (!NT_SUCCESS(Status)) 1082 { 1083 /* Failed to insert the logon session into the token, bail out */ 1084 DPRINT1("SepRmInsertLogonSessionIntoToken() failed (Status 0x%lx)\n", Status); 1085 goto Quit; 1086 } 1087 1088 /* Assign the data that reside in the TOKEN's variable information area */ 1089 AccessToken->VariableLength = VariableLength; 1090 EndMem = (PVOID)&AccessToken->VariablePart; 1091 1092 /* Copy the privileges */ 1093 AccessToken->PrivilegeCount = 0; 1094 AccessToken->Privileges = NULL; 1095 if (Token->Privileges && (Token->PrivilegeCount > 0)) 1096 { 1097 ULONG PrivilegesLength = Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES); 1098 PrivilegesLength = ALIGN_UP_BY(PrivilegesLength, sizeof(PVOID)); 1099 1100 ASSERT(VariableLength >= PrivilegesLength); 1101 1102 AccessToken->PrivilegeCount = Token->PrivilegeCount; 1103 AccessToken->Privileges = EndMem; 1104 EndMem = (PVOID)((ULONG_PTR)EndMem + PrivilegesLength); 1105 VariableLength -= PrivilegesLength; 1106 1107 RtlCopyMemory(AccessToken->Privileges, 1108 Token->Privileges, 1109 AccessToken->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES)); 1110 } 1111 1112 /* Copy the user and groups */ 1113 AccessToken->UserAndGroupCount = 0; 1114 AccessToken->UserAndGroups = NULL; 1115 if (Token->UserAndGroups && (Token->UserAndGroupCount > 0)) 1116 { 1117 AccessToken->UserAndGroupCount = Token->UserAndGroupCount; 1118 AccessToken->UserAndGroups = EndMem; 1119 EndMem = &AccessToken->UserAndGroups[AccessToken->UserAndGroupCount]; 1120 VariableLength -= ((ULONG_PTR)EndMem - (ULONG_PTR)AccessToken->UserAndGroups); 1121 1122 Status = RtlCopySidAndAttributesArray(AccessToken->UserAndGroupCount, 1123 Token->UserAndGroups, 1124 VariableLength, 1125 AccessToken->UserAndGroups, 1126 EndMem, 1127 &EndMem, 1128 &VariableLength); 1129 if (!NT_SUCCESS(Status)) 1130 { 1131 DPRINT1("RtlCopySidAndAttributesArray(UserAndGroups) failed (Status 0x%lx)\n", Status); 1132 goto Quit; 1133 } 1134 } 1135 1136 #if 1 1137 { 1138 ULONG PrimaryGroupIndex; 1139 1140 /* Find the token primary group */ 1141 Status = SepFindPrimaryGroupAndDefaultOwner(AccessToken, 1142 Token->PrimaryGroup, 1143 NULL, 1144 &PrimaryGroupIndex, 1145 NULL); 1146 if (!NT_SUCCESS(Status)) 1147 { 1148 DPRINT1("SepFindPrimaryGroupAndDefaultOwner failed (Status 0x%lx)\n", Status); 1149 goto Quit; 1150 } 1151 AccessToken->PrimaryGroup = AccessToken->UserAndGroups[PrimaryGroupIndex].Sid; 1152 } 1153 #else 1154 AccessToken->PrimaryGroup = (PVOID)((ULONG_PTR)AccessToken + (ULONG_PTR)Token->PrimaryGroup - (ULONG_PTR)Token->UserAndGroups); 1155 #endif 1156 AccessToken->DefaultOwnerIndex = Token->DefaultOwnerIndex; 1157 1158 /* Copy the restricted SIDs */ 1159 AccessToken->RestrictedSidCount = 0; 1160 AccessToken->RestrictedSids = NULL; 1161 if (Token->RestrictedSids && (Token->RestrictedSidCount > 0)) 1162 { 1163 AccessToken->RestrictedSidCount = Token->RestrictedSidCount; 1164 AccessToken->RestrictedSids = EndMem; 1165 EndMem = &AccessToken->RestrictedSids[AccessToken->RestrictedSidCount]; 1166 VariableLength -= ((ULONG_PTR)EndMem - (ULONG_PTR)AccessToken->RestrictedSids); 1167 1168 Status = RtlCopySidAndAttributesArray(AccessToken->RestrictedSidCount, 1169 Token->RestrictedSids, 1170 VariableLength, 1171 AccessToken->RestrictedSids, 1172 EndMem, 1173 &EndMem, 1174 &VariableLength); 1175 if (!NT_SUCCESS(Status)) 1176 { 1177 DPRINT1("RtlCopySidAndAttributesArray(RestrictedSids) failed (Status 0x%lx)\n", Status); 1178 goto Quit; 1179 } 1180 } 1181 1182 /* 1183 * Filter the token by removing the disabled privileges 1184 * and groups if the caller wants to duplicate an access 1185 * token as effective only. 1186 */ 1187 if (EffectiveOnly) 1188 { 1189 /* Begin querying the groups and search for disabled ones */ 1190 for (GroupsIndex = 0; GroupsIndex < AccessToken->UserAndGroupCount; GroupsIndex++) 1191 { 1192 /* 1193 * A group or user is considered disabled if its attributes is either 1194 * 0 or SE_GROUP_ENABLED is not included in the attributes flags list. 1195 * That is because a certain user and/or group can have several attributes 1196 * that bear no influence on whether a user/group is enabled or not 1197 * (SE_GROUP_ENABLED_BY_DEFAULT for example which is a mere indicator 1198 * that the group has just been enabled by default). A mandatory 1199 * group (that is, the group has SE_GROUP_MANDATORY attribute) 1200 * by standards it's always enabled and no one can disable it. 1201 */ 1202 if (AccessToken->UserAndGroups[GroupsIndex].Attributes == 0 || 1203 (AccessToken->UserAndGroups[GroupsIndex].Attributes & SE_GROUP_ENABLED) == 0) 1204 { 1205 /* 1206 * A group is not enabled, it's time to remove 1207 * from the token and update the groups index 1208 * accordingly and continue with the next group. 1209 */ 1210 SepRemoveUserGroupToken(AccessToken, GroupsIndex); 1211 GroupsIndex--; 1212 } 1213 } 1214 1215 /* Begin querying the privileges and search for disabled ones */ 1216 for (PrivilegesIndex = 0; PrivilegesIndex < AccessToken->PrivilegeCount; PrivilegesIndex++) 1217 { 1218 /* 1219 * A privilege is considered disabled if its attributes is either 1220 * 0 or SE_PRIVILEGE_ENABLED is not included in the attributes flags list. 1221 * That is because a certain privilege can have several attributes 1222 * that bear no influence on whether a privilege is enabled or not 1223 * (SE_PRIVILEGE_ENABLED_BY_DEFAULT for example which is a mere indicator 1224 * that the privilege has just been enabled by default). 1225 */ 1226 if (AccessToken->Privileges[PrivilegesIndex].Attributes == 0 || 1227 (AccessToken->Privileges[PrivilegesIndex].Attributes & SE_PRIVILEGE_ENABLED) == 0) 1228 { 1229 /* 1230 * A privilege is not enabled, therefor it's time 1231 * to strip it from the token and continue with the next 1232 * privilege. Of course we must also want to update the 1233 * privileges index accordingly. 1234 */ 1235 SepRemovePrivilegeToken(AccessToken, PrivilegesIndex); 1236 PrivilegesIndex--; 1237 } 1238 } 1239 } 1240 1241 // 1242 // NOTE: So far our dynamic area only contains 1243 // the default dacl, so this makes the following 1244 // code pretty simple. The day where it stores 1245 // other data, the code will require adaptations. 1246 // 1247 1248 /* Now allocate the TOKEN's dynamic information area and set the data */ 1249 AccessToken->DynamicAvailable = 0; // Unused memory in the dynamic area. 1250 AccessToken->DynamicPart = NULL; 1251 if (Token->DynamicPart && Token->DefaultDacl) 1252 { 1253 AccessToken->DynamicPart = ExAllocatePoolWithTag(PagedPool, 1254 Token->DefaultDacl->AclSize, 1255 TAG_TOKEN_DYNAMIC); 1256 if (AccessToken->DynamicPart == NULL) 1257 { 1258 Status = STATUS_INSUFFICIENT_RESOURCES; 1259 goto Quit; 1260 } 1261 EndMem = (PVOID)AccessToken->DynamicPart; 1262 1263 AccessToken->DefaultDacl = EndMem; 1264 1265 RtlCopyMemory(AccessToken->DefaultDacl, 1266 Token->DefaultDacl, 1267 Token->DefaultDacl->AclSize); 1268 } 1269 1270 /* Unlock the source token */ 1271 SepReleaseTokenLock(Token); 1272 1273 /* Return the token */ 1274 *NewAccessToken = AccessToken; 1275 Status = STATUS_SUCCESS; 1276 1277 Quit: 1278 if (!NT_SUCCESS(Status)) 1279 { 1280 /* Unlock the source token */ 1281 SepReleaseTokenLock(Token); 1282 1283 /* Dereference the token, the delete procedure will clean it up */ 1284 ObDereferenceObject(AccessToken); 1285 } 1286 1287 return Status; 1288 } 1289 1290 /** 1291 * @brief 1292 * Subtracts a token in exchange of duplicating a new one. 1293 * 1294 * @param[in] ParentToken 1295 * The parent access token for duplication. 1296 * 1297 * @param[out] Token 1298 * The new duplicated token. 1299 * 1300 * @param[in] InUse 1301 * Set this to TRUE if the token is about to be used immediately after the call execution 1302 * of this function, FALSE otherwise. 1303 * 1304 * @param[in] SessionId 1305 * Session ID for the token to be assigned. 1306 * 1307 * @return 1308 * Returns STATUS_SUCCESS if token subtracting and duplication have completed successfully. 1309 * A failure NTSTATUS code is returned otherwise. 1310 */ 1311 NTSTATUS 1312 NTAPI 1313 SeSubProcessToken( 1314 _In_ PTOKEN ParentToken, 1315 _Out_ PTOKEN *Token, 1316 _In_ BOOLEAN InUse, 1317 _In_ ULONG SessionId) 1318 { 1319 PTOKEN NewToken; 1320 OBJECT_ATTRIBUTES ObjectAttributes; 1321 NTSTATUS Status; 1322 1323 /* Initialize the attributes and duplicate it */ 1324 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL); 1325 Status = SepDuplicateToken(ParentToken, 1326 &ObjectAttributes, 1327 FALSE, 1328 TokenPrimary, 1329 ParentToken->ImpersonationLevel, 1330 KernelMode, 1331 &NewToken); 1332 if (NT_SUCCESS(Status)) 1333 { 1334 /* Insert it */ 1335 Status = ObInsertObject(NewToken, 1336 NULL, 1337 0, 1338 0, 1339 NULL, 1340 NULL); 1341 if (NT_SUCCESS(Status)) 1342 { 1343 /* Set the session ID */ 1344 NewToken->SessionId = SessionId; 1345 NewToken->TokenInUse = InUse; 1346 1347 /* Return the token */ 1348 *Token = NewToken; 1349 } 1350 } 1351 1352 /* Return status */ 1353 return Status; 1354 } 1355 1356 /** 1357 * @brief 1358 * Checks if the token is a child of the other token 1359 * of the current process that the calling thread is invoking this function. 1360 * 1361 * @param[in] Token 1362 * An access token to determine if it's a child or not. 1363 * 1364 * @param[out] IsChild 1365 * The returned boolean result. 1366 * 1367 * @return 1368 * Returns STATUS_SUCCESS when the function finishes its operation. STATUS_UNSUCCESSFUL is 1369 * returned if primary token of the current calling process couldn't be referenced otherwise. 1370 */ 1371 NTSTATUS 1372 NTAPI 1373 SeIsTokenChild( 1374 _In_ PTOKEN Token, 1375 _Out_ PBOOLEAN IsChild) 1376 { 1377 PTOKEN ProcessToken; 1378 LUID ProcessTokenId, CallerParentId; 1379 1380 /* Assume failure */ 1381 *IsChild = FALSE; 1382 1383 /* Reference the process token */ 1384 ProcessToken = PsReferencePrimaryToken(PsGetCurrentProcess()); 1385 if (!ProcessToken) 1386 return STATUS_UNSUCCESSFUL; 1387 1388 /* Get its token ID */ 1389 ProcessTokenId = ProcessToken->TokenId; 1390 1391 /* Dereference the token */ 1392 ObFastDereferenceObject(&PsGetCurrentProcess()->Token, ProcessToken); 1393 1394 /* Get our parent token ID */ 1395 CallerParentId = Token->ParentTokenId; 1396 1397 /* Compare the token IDs */ 1398 if (RtlEqualLuid(&CallerParentId, &ProcessTokenId)) 1399 *IsChild = TRUE; 1400 1401 /* Return success */ 1402 return STATUS_SUCCESS; 1403 } 1404 1405 /** 1406 * @brief 1407 * Checks if the token is a sibling of the other token of 1408 * the current process that the calling thread is invoking this function. 1409 * 1410 * @param[in] Token 1411 * An access token to determine if it's a sibling or not. 1412 * 1413 * @param[out] IsSibling 1414 * The returned boolean result. 1415 * 1416 * @return 1417 * Returns STATUS_SUCCESS when the function finishes its operation. STATUS_UNSUCCESSFUL is 1418 * returned if primary token of the current calling process couldn't be referenced otherwise. 1419 */ 1420 NTSTATUS 1421 NTAPI 1422 SeIsTokenSibling( 1423 _In_ PTOKEN Token, 1424 _Out_ PBOOLEAN IsSibling) 1425 { 1426 PTOKEN ProcessToken; 1427 LUID ProcessParentId, ProcessAuthId; 1428 LUID CallerParentId, CallerAuthId; 1429 1430 /* Assume failure */ 1431 *IsSibling = FALSE; 1432 1433 /* Reference the process token */ 1434 ProcessToken = PsReferencePrimaryToken(PsGetCurrentProcess()); 1435 if (!ProcessToken) 1436 return STATUS_UNSUCCESSFUL; 1437 1438 /* Get its parent and authentication IDs */ 1439 ProcessParentId = ProcessToken->ParentTokenId; 1440 ProcessAuthId = ProcessToken->AuthenticationId; 1441 1442 /* Dereference the token */ 1443 ObFastDereferenceObject(&PsGetCurrentProcess()->Token, ProcessToken); 1444 1445 /* Get our parent and authentication IDs */ 1446 CallerParentId = Token->ParentTokenId; 1447 CallerAuthId = Token->AuthenticationId; 1448 1449 /* Compare the token IDs */ 1450 if (RtlEqualLuid(&CallerParentId, &ProcessParentId) && 1451 RtlEqualLuid(&CallerAuthId, &ProcessAuthId)) 1452 { 1453 *IsSibling = TRUE; 1454 } 1455 1456 /* Return success */ 1457 return STATUS_SUCCESS; 1458 } 1459 1460 /** 1461 * @brief 1462 * Copies an existing access token (technically duplicating a new one). 1463 * 1464 * @param[in] Token 1465 * Token to copy. 1466 * 1467 * @param[in] Level 1468 * Impersonation security level to assign to the newly copied token. 1469 * 1470 * @param[in] PreviousMode 1471 * Processor request level mode. 1472 * 1473 * @param[out] NewToken 1474 * The newly copied token. 1475 * 1476 * @return 1477 * Returns STATUS_SUCCESS when token copying has finished successfully. A failure 1478 * NTSTATUS code is returned otherwise. 1479 */ 1480 NTSTATUS 1481 NTAPI 1482 SeCopyClientToken( 1483 _In_ PACCESS_TOKEN Token, 1484 _In_ SECURITY_IMPERSONATION_LEVEL Level, 1485 _In_ KPROCESSOR_MODE PreviousMode, 1486 _Out_ PACCESS_TOKEN* NewToken) 1487 { 1488 NTSTATUS Status; 1489 OBJECT_ATTRIBUTES ObjectAttributes; 1490 1491 PAGED_CODE(); 1492 1493 InitializeObjectAttributes(&ObjectAttributes, 1494 NULL, 1495 0, 1496 NULL, 1497 NULL); 1498 1499 Status = SepDuplicateToken(Token, 1500 &ObjectAttributes, 1501 FALSE, 1502 TokenImpersonation, 1503 Level, 1504 PreviousMode, 1505 (PTOKEN*)NewToken); 1506 1507 return Status; 1508 } 1509 1510 /** 1511 * @brief 1512 * Internal function that deals with access token object destruction and deletion. 1513 * The function is used solely by the object manager mechanism that handles the life 1514 * management of a token object. 1515 * 1516 * @param[in] ObjectBody 1517 * The object body that represents an access token object. 1518 * 1519 * @return 1520 * Nothing. 1521 */ 1522 VOID 1523 NTAPI 1524 SepDeleteToken( 1525 _In_ PVOID ObjectBody) 1526 { 1527 NTSTATUS Status; 1528 PTOKEN AccessToken = (PTOKEN)ObjectBody; 1529 1530 DPRINT("SepDeleteToken()\n"); 1531 1532 /* Remove the referenced logon session from token */ 1533 if (AccessToken->LogonSession) 1534 { 1535 Status = SepRmRemoveLogonSessionFromToken(AccessToken); 1536 if (!NT_SUCCESS(Status)) 1537 { 1538 /* Something seriously went wrong */ 1539 DPRINT1("SepDeleteToken(): Failed to remove the logon session from token (Status: 0x%lx)\n", Status); 1540 return; 1541 } 1542 } 1543 1544 /* Dereference the logon session */ 1545 if ((AccessToken->TokenFlags & TOKEN_SESSION_NOT_REFERENCED) == 0) 1546 SepRmDereferenceLogonSession(&AccessToken->AuthenticationId); 1547 1548 /* Delete the token lock */ 1549 if (AccessToken->TokenLock) 1550 SepDeleteTokenLock(AccessToken); 1551 1552 /* Delete the dynamic information area */ 1553 if (AccessToken->DynamicPart) 1554 ExFreePoolWithTag(AccessToken->DynamicPart, TAG_TOKEN_DYNAMIC); 1555 } 1556 1557 /** 1558 * @brief 1559 * Internal function that initializes critical kernel data for access 1560 * token implementation in SRM. 1561 * 1562 * @return 1563 * Nothing. 1564 */ 1565 CODE_SEG("INIT") 1566 VOID 1567 NTAPI 1568 SepInitializeTokenImplementation(VOID) 1569 { 1570 UNICODE_STRING Name; 1571 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; 1572 1573 DPRINT("Creating Token Object Type\n"); 1574 1575 /* Initialize the Token type */ 1576 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); 1577 RtlInitUnicodeString(&Name, L"Token"); 1578 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); 1579 ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK; 1580 ObjectTypeInitializer.SecurityRequired = TRUE; 1581 ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(TOKEN); 1582 ObjectTypeInitializer.GenericMapping = SepTokenMapping; 1583 ObjectTypeInitializer.PoolType = PagedPool; 1584 ObjectTypeInitializer.ValidAccessMask = TOKEN_ALL_ACCESS; 1585 ObjectTypeInitializer.UseDefaultObject = TRUE; 1586 ObjectTypeInitializer.DeleteProcedure = SepDeleteToken; 1587 ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &SeTokenObjectType); 1588 } 1589 1590 /** 1591 * @brief 1592 * Assigns a primary access token to a given process. 1593 * 1594 * @param[in] Process 1595 * Process where the token is about to be assigned. 1596 * 1597 * @param[in] Token 1598 * The token to be assigned. 1599 * 1600 * @return 1601 * Nothing. 1602 */ 1603 VOID 1604 NTAPI 1605 SeAssignPrimaryToken( 1606 _In_ PEPROCESS Process, 1607 _In_ PTOKEN Token) 1608 { 1609 PAGED_CODE(); 1610 1611 /* Sanity checks */ 1612 ASSERT(Token->TokenType == TokenPrimary); 1613 ASSERT(!Token->TokenInUse); 1614 1615 /* Clean any previous token */ 1616 if (Process->Token.Object) SeDeassignPrimaryToken(Process); 1617 1618 /* Set the new token */ 1619 ObReferenceObject(Token); 1620 Token->TokenInUse = TRUE; 1621 ObInitializeFastReference(&Process->Token, Token); 1622 } 1623 1624 /** 1625 * @brief 1626 * Internal function responsible for access token object creation in the kernel. 1627 * A fully created token objected is inserted into the token handle, thus the handle 1628 * becoming a valid handle to an access token object and ready for use. 1629 * 1630 * @param[out] TokenHandle 1631 * Valid token handle that's ready for use after token creation and object insertion. 1632 * 1633 * @param[in] PreviousMode 1634 * Processor request level mode. 1635 * 1636 * @param[in] DesiredAccess 1637 * Desired access right for the token object to be granted. This kind of access right 1638 * impacts how the token can be used and who. 1639 * 1640 * @param[in] ObjectAttributes 1641 * Object attributes for the token to be created. 1642 * 1643 * @param[in] TokenType 1644 * Type of token to assign upon creation. 1645 * 1646 * @param[in] ImpersonationLevel 1647 * Security impersonation level of token to assign upon creation. 1648 * 1649 * @param[in] AuthenticationId 1650 * Authentication ID that represents the authentication information of the token. 1651 * 1652 * @param[in] ExpirationTime 1653 * Expiration time of the token to assign. A value of -1 means that the token never 1654 * expires and its life depends upon the amount of references this token object has. 1655 * 1656 * @param[in] User 1657 * User entry to assign to the token. 1658 * 1659 * @param[in] GroupCount 1660 * The total number of groups count for the token. 1661 * 1662 * @param[in] Groups 1663 * The group entries for the token. 1664 * 1665 * @param[in] GroupsLength 1666 * The length size of the groups array, pointed by the Groups parameter. 1667 * 1668 * @param[in] PrivilegeCount 1669 * The total number of priivleges that the newly created token has. 1670 * 1671 * @param[in] Privileges 1672 * The privileges for the token. 1673 * 1674 * @param[in] Owner 1675 * The main user (or also owner) that represents the token that we create. 1676 * 1677 * @param[in] PrimaryGroup 1678 * The main group that represents the token that we create. 1679 * 1680 * @param[in] DefaultDacl 1681 * A discretionary access control list for the token. 1682 * 1683 * @param[in] TokenSource 1684 * Source (or the origin) of the access token that creates it. 1685 * 1686 * @param[in] SystemToken 1687 * If set to TRUE, the newly created token is a system token and only in charge 1688 * by the internal system. The function directly returns a pointer to the 1689 * created token object for system kernel use. Otherwise if set to FALSE, the 1690 * function inserts the object to a handle making it a regular access token. 1691 * 1692 * @return 1693 * Returns STATUS_SUCCESS if token creation has completed successfully. 1694 * STATUS_INSUFFICIENT_RESOURCES is returned if the dynamic area of memory of the 1695 * token hasn't been allocated because of lack of memory resources. A failure 1696 * NTSTATUS code is returned otherwise. 1697 */ 1698 NTSTATUS 1699 NTAPI 1700 SepCreateToken( 1701 _Out_ PHANDLE TokenHandle, 1702 _In_ KPROCESSOR_MODE PreviousMode, 1703 _In_ ACCESS_MASK DesiredAccess, 1704 _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, 1705 _In_ TOKEN_TYPE TokenType, 1706 _In_ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, 1707 _In_ PLUID AuthenticationId, 1708 _In_ PLARGE_INTEGER ExpirationTime, 1709 _In_ PSID_AND_ATTRIBUTES User, 1710 _In_ ULONG GroupCount, 1711 _In_ PSID_AND_ATTRIBUTES Groups, 1712 _In_ ULONG GroupsLength, 1713 _In_ ULONG PrivilegeCount, 1714 _In_ PLUID_AND_ATTRIBUTES Privileges, 1715 _In_opt_ PSID Owner, 1716 _In_ PSID PrimaryGroup, 1717 _In_opt_ PACL DefaultDacl, 1718 _In_ PTOKEN_SOURCE TokenSource, 1719 _In_ BOOLEAN SystemToken) 1720 { 1721 NTSTATUS Status; 1722 PTOKEN AccessToken; 1723 ULONG TokenFlags = 0; 1724 ULONG PrimaryGroupIndex, DefaultOwnerIndex; 1725 LUID TokenId; 1726 LUID ModifiedId; 1727 PVOID EndMem; 1728 ULONG PrivilegesLength; 1729 ULONG UserGroupsLength; 1730 ULONG VariableLength; 1731 ULONG TotalSize; 1732 ULONG i; 1733 1734 PAGED_CODE(); 1735 1736 /* Loop all groups */ 1737 for (i = 0; i < GroupCount; i++) 1738 { 1739 /* Check for mandatory groups */ 1740 if (Groups[i].Attributes & SE_GROUP_MANDATORY) 1741 { 1742 /* Force them to be enabled */ 1743 Groups[i].Attributes |= (SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT); 1744 } 1745 1746 /* Check of the group is an admin group */ 1747 if (RtlEqualSid(SeAliasAdminsSid, Groups[i].Sid)) 1748 { 1749 /* Remember this so we can optimize queries later */ 1750 TokenFlags |= TOKEN_HAS_ADMIN_GROUP; 1751 } 1752 } 1753 1754 /* Allocate unique IDs for the token */ 1755 ExAllocateLocallyUniqueId(&TokenId); 1756 ExAllocateLocallyUniqueId(&ModifiedId); 1757 1758 /* Compute how much size we need to allocate for the token */ 1759 1760 /* Privileges size */ 1761 PrivilegesLength = PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES); 1762 PrivilegesLength = ALIGN_UP_BY(PrivilegesLength, sizeof(PVOID)); 1763 1764 /* User and groups size */ 1765 UserGroupsLength = (1 + GroupCount) * sizeof(SID_AND_ATTRIBUTES); 1766 UserGroupsLength += RtlLengthSid(User->Sid); 1767 for (i = 0; i < GroupCount; i++) 1768 { 1769 UserGroupsLength += RtlLengthSid(Groups[i].Sid); 1770 } 1771 UserGroupsLength = ALIGN_UP_BY(UserGroupsLength, sizeof(PVOID)); 1772 1773 /* Add the additional groups array length */ 1774 UserGroupsLength += ALIGN_UP_BY(GroupsLength, sizeof(PVOID)); 1775 1776 VariableLength = PrivilegesLength + UserGroupsLength; 1777 TotalSize = FIELD_OFFSET(TOKEN, VariablePart) + VariableLength; 1778 1779 Status = ObCreateObject(PreviousMode, 1780 SeTokenObjectType, 1781 ObjectAttributes, 1782 PreviousMode, 1783 NULL, 1784 TotalSize, 1785 0, 1786 0, 1787 (PVOID*)&AccessToken); 1788 if (!NT_SUCCESS(Status)) 1789 { 1790 DPRINT1("ObCreateObject() failed (Status 0x%lx)\n", Status); 1791 return Status; 1792 } 1793 1794 /* Zero out the buffer and initialize the token */ 1795 RtlZeroMemory(AccessToken, TotalSize); 1796 1797 RtlCopyLuid(&AccessToken->TokenId, &TokenId); 1798 1799 AccessToken->TokenType = TokenType; 1800 AccessToken->ImpersonationLevel = ImpersonationLevel; 1801 1802 /* Initialise the lock for the access token */ 1803 Status = SepCreateTokenLock(AccessToken); 1804 if (!NT_SUCCESS(Status)) 1805 goto Quit; 1806 1807 RtlCopyLuid(&AccessToken->TokenSource.SourceIdentifier, 1808 &TokenSource->SourceIdentifier); 1809 RtlCopyMemory(AccessToken->TokenSource.SourceName, 1810 TokenSource->SourceName, 1811 sizeof(TokenSource->SourceName)); 1812 1813 AccessToken->ExpirationTime = *ExpirationTime; 1814 RtlCopyLuid(&AccessToken->ModifiedId, &ModifiedId); 1815 1816 AccessToken->TokenFlags = TokenFlags & ~TOKEN_SESSION_NOT_REFERENCED; 1817 1818 /* Copy and reference the logon session */ 1819 RtlCopyLuid(&AccessToken->AuthenticationId, AuthenticationId); 1820 Status = SepRmReferenceLogonSession(&AccessToken->AuthenticationId); 1821 if (!NT_SUCCESS(Status)) 1822 { 1823 /* No logon session could be found, bail out */ 1824 DPRINT1("SepRmReferenceLogonSession() failed (Status 0x%lx)\n", Status); 1825 /* Set the flag for proper cleanup by the delete procedure */ 1826 AccessToken->TokenFlags |= TOKEN_SESSION_NOT_REFERENCED; 1827 goto Quit; 1828 } 1829 1830 /* Insert the referenced logon session into the token */ 1831 Status = SepRmInsertLogonSessionIntoToken(AccessToken); 1832 if (!NT_SUCCESS(Status)) 1833 { 1834 /* Failed to insert the logon session into the token, bail out */ 1835 DPRINT1("SepRmInsertLogonSessionIntoToken() failed (Status 0x%lx)\n", Status); 1836 goto Quit; 1837 } 1838 1839 /* Assign the data that reside in the TOKEN's variable information area */ 1840 AccessToken->VariableLength = VariableLength; 1841 EndMem = (PVOID)&AccessToken->VariablePart; 1842 1843 /* Copy the privileges */ 1844 AccessToken->PrivilegeCount = PrivilegeCount; 1845 AccessToken->Privileges = NULL; 1846 if (PrivilegeCount > 0) 1847 { 1848 AccessToken->Privileges = EndMem; 1849 EndMem = (PVOID)((ULONG_PTR)EndMem + PrivilegesLength); 1850 VariableLength -= PrivilegesLength; 1851 1852 if (PreviousMode != KernelMode) 1853 { 1854 _SEH2_TRY 1855 { 1856 RtlCopyMemory(AccessToken->Privileges, 1857 Privileges, 1858 PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES)); 1859 } 1860 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1861 { 1862 Status = _SEH2_GetExceptionCode(); 1863 } 1864 _SEH2_END; 1865 } 1866 else 1867 { 1868 RtlCopyMemory(AccessToken->Privileges, 1869 Privileges, 1870 PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES)); 1871 } 1872 1873 if (!NT_SUCCESS(Status)) 1874 goto Quit; 1875 } 1876 1877 /* Update the privilege flags */ 1878 SepUpdatePrivilegeFlagsToken(AccessToken); 1879 1880 /* Copy the user and groups */ 1881 AccessToken->UserAndGroupCount = 1 + GroupCount; 1882 AccessToken->UserAndGroups = EndMem; 1883 EndMem = &AccessToken->UserAndGroups[AccessToken->UserAndGroupCount]; 1884 VariableLength -= ((ULONG_PTR)EndMem - (ULONG_PTR)AccessToken->UserAndGroups); 1885 1886 Status = RtlCopySidAndAttributesArray(1, 1887 User, 1888 VariableLength, 1889 &AccessToken->UserAndGroups[0], 1890 EndMem, 1891 &EndMem, 1892 &VariableLength); 1893 if (!NT_SUCCESS(Status)) 1894 goto Quit; 1895 1896 Status = RtlCopySidAndAttributesArray(GroupCount, 1897 Groups, 1898 VariableLength, 1899 &AccessToken->UserAndGroups[1], 1900 EndMem, 1901 &EndMem, 1902 &VariableLength); 1903 if (!NT_SUCCESS(Status)) 1904 goto Quit; 1905 1906 /* Find the token primary group and default owner */ 1907 Status = SepFindPrimaryGroupAndDefaultOwner(AccessToken, 1908 PrimaryGroup, 1909 Owner, 1910 &PrimaryGroupIndex, 1911 &DefaultOwnerIndex); 1912 if (!NT_SUCCESS(Status)) 1913 { 1914 DPRINT1("SepFindPrimaryGroupAndDefaultOwner failed (Status 0x%lx)\n", Status); 1915 goto Quit; 1916 } 1917 1918 AccessToken->PrimaryGroup = AccessToken->UserAndGroups[PrimaryGroupIndex].Sid; 1919 AccessToken->DefaultOwnerIndex = DefaultOwnerIndex; 1920 1921 /* Now allocate the TOKEN's dynamic information area and set the data */ 1922 AccessToken->DynamicAvailable = 0; // Unused memory in the dynamic area. 1923 AccessToken->DynamicPart = NULL; 1924 if (DefaultDacl != NULL) 1925 { 1926 AccessToken->DynamicPart = ExAllocatePoolWithTag(PagedPool, 1927 DefaultDacl->AclSize, 1928 TAG_TOKEN_DYNAMIC); 1929 if (AccessToken->DynamicPart == NULL) 1930 { 1931 Status = STATUS_INSUFFICIENT_RESOURCES; 1932 goto Quit; 1933 } 1934 EndMem = (PVOID)AccessToken->DynamicPart; 1935 1936 AccessToken->DefaultDacl = EndMem; 1937 1938 RtlCopyMemory(AccessToken->DefaultDacl, 1939 DefaultDacl, 1940 DefaultDacl->AclSize); 1941 } 1942 1943 /* Insert the token only if it's not the system token, otherwise return it directly */ 1944 if (!SystemToken) 1945 { 1946 Status = ObInsertObject(AccessToken, 1947 NULL, 1948 DesiredAccess, 1949 0, 1950 NULL, 1951 TokenHandle); 1952 if (!NT_SUCCESS(Status)) 1953 { 1954 DPRINT1("ObInsertObject() failed (Status 0x%lx)\n", Status); 1955 } 1956 } 1957 else 1958 { 1959 /* Return pointer instead of handle */ 1960 *TokenHandle = (HANDLE)AccessToken; 1961 } 1962 1963 Quit: 1964 if (!NT_SUCCESS(Status)) 1965 { 1966 /* Dereference the token, the delete procedure will clean it up */ 1967 ObDereferenceObject(AccessToken); 1968 } 1969 1970 return Status; 1971 } 1972 1973 /** 1974 * @brief 1975 * Creates the system process token. 1976 * 1977 * @return 1978 * Returns the system process token if the operations have 1979 * completed successfully. 1980 */ 1981 CODE_SEG("INIT") 1982 PTOKEN 1983 NTAPI 1984 SepCreateSystemProcessToken(VOID) 1985 { 1986 LUID_AND_ATTRIBUTES Privileges[25]; 1987 ULONG GroupAttributes, OwnerAttributes; 1988 SID_AND_ATTRIBUTES Groups[32]; 1989 LARGE_INTEGER Expiration; 1990 SID_AND_ATTRIBUTES UserSid; 1991 ULONG GroupsLength; 1992 PSID PrimaryGroup; 1993 OBJECT_ATTRIBUTES ObjectAttributes; 1994 PSID Owner; 1995 ULONG i; 1996 PTOKEN Token; 1997 NTSTATUS Status; 1998 1999 /* Don't ever expire */ 2000 Expiration.QuadPart = -1; 2001 2002 /* All groups mandatory and enabled */ 2003 GroupAttributes = SE_GROUP_ENABLED | SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT; 2004 OwnerAttributes = SE_GROUP_ENABLED | SE_GROUP_OWNER | SE_GROUP_ENABLED_BY_DEFAULT; 2005 2006 /* User is Local System */ 2007 UserSid.Sid = SeLocalSystemSid; 2008 UserSid.Attributes = 0; 2009 2010 /* Primary group is Local System */ 2011 PrimaryGroup = SeLocalSystemSid; 2012 2013 /* Owner is Administrators */ 2014 Owner = SeAliasAdminsSid; 2015 2016 /* Groups are Administrators, World, and Authenticated Users */ 2017 Groups[0].Sid = SeAliasAdminsSid; 2018 Groups[0].Attributes = OwnerAttributes; 2019 Groups[1].Sid = SeWorldSid; 2020 Groups[1].Attributes = GroupAttributes; 2021 Groups[2].Sid = SeAuthenticatedUsersSid; 2022 Groups[2].Attributes = GroupAttributes; 2023 GroupsLength = sizeof(SID_AND_ATTRIBUTES) + 2024 SeLengthSid(Groups[0].Sid) + 2025 SeLengthSid(Groups[1].Sid) + 2026 SeLengthSid(Groups[2].Sid); 2027 ASSERT(GroupsLength <= sizeof(Groups)); 2028 2029 /* Setup the privileges */ 2030 i = 0; 2031 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED; 2032 Privileges[i++].Luid = SeTcbPrivilege; 2033 2034 Privileges[i].Attributes = 0; 2035 Privileges[i++].Luid = SeCreateTokenPrivilege; 2036 2037 Privileges[i].Attributes = 0; 2038 Privileges[i++].Luid = SeTakeOwnershipPrivilege; 2039 2040 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED; 2041 Privileges[i++].Luid = SeCreatePagefilePrivilege; 2042 2043 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED; 2044 Privileges[i++].Luid = SeLockMemoryPrivilege; 2045 2046 Privileges[i].Attributes = 0; 2047 Privileges[i++].Luid = SeAssignPrimaryTokenPrivilege; 2048 2049 Privileges[i].Attributes = 0; 2050 Privileges[i++].Luid = SeIncreaseQuotaPrivilege; 2051 2052 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED; 2053 Privileges[i++].Luid = SeIncreaseBasePriorityPrivilege; 2054 2055 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED; 2056 Privileges[i++].Luid = SeCreatePermanentPrivilege; 2057 2058 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED; 2059 Privileges[i++].Luid = SeDebugPrivilege; 2060 2061 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED; 2062 Privileges[i++].Luid = SeAuditPrivilege; 2063 2064 Privileges[i].Attributes = 0; 2065 Privileges[i++].Luid = SeSecurityPrivilege; 2066 2067 Privileges[i].Attributes = 0; 2068 Privileges[i++].Luid = SeSystemEnvironmentPrivilege; 2069 2070 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED; 2071 Privileges[i++].Luid = SeChangeNotifyPrivilege; 2072 2073 Privileges[i].Attributes = 0; 2074 Privileges[i++].Luid = SeBackupPrivilege; 2075 2076 Privileges[i].Attributes = 0; 2077 Privileges[i++].Luid = SeRestorePrivilege; 2078 2079 Privileges[i].Attributes = 0; 2080 Privileges[i++].Luid = SeShutdownPrivilege; 2081 2082 Privileges[i].Attributes = 0; 2083 Privileges[i++].Luid = SeLoadDriverPrivilege; 2084 2085 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED; 2086 Privileges[i++].Luid = SeProfileSingleProcessPrivilege; 2087 2088 Privileges[i].Attributes = 0; 2089 Privileges[i++].Luid = SeSystemtimePrivilege; 2090 ASSERT(i == 20); 2091 2092 /* Setup the object attributes */ 2093 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL); 2094 ASSERT(SeSystemDefaultDacl != NULL); 2095 2096 /* Create the token */ 2097 Status = SepCreateToken((PHANDLE)&Token, 2098 KernelMode, 2099 0, 2100 &ObjectAttributes, 2101 TokenPrimary, 2102 SecurityAnonymous, 2103 &SeSystemAuthenticationId, 2104 &Expiration, 2105 &UserSid, 2106 3, 2107 Groups, 2108 GroupsLength, 2109 20, 2110 Privileges, 2111 Owner, 2112 PrimaryGroup, 2113 SeSystemDefaultDacl, 2114 &SeSystemTokenSource, 2115 TRUE); 2116 ASSERT(Status == STATUS_SUCCESS); 2117 2118 /* Return the token */ 2119 return Token; 2120 } 2121 2122 /** 2123 * @brief 2124 * Creates the anonymous logon token for the system. The difference between this 2125 * token and the other one is the inclusion of everyone SID group (being SeWorldSid). 2126 * The other token lacks such group. 2127 * 2128 * @return 2129 * Returns the system's anonymous logon token if the operations have 2130 * completed successfully. 2131 */ 2132 CODE_SEG("INIT") 2133 PTOKEN 2134 SepCreateSystemAnonymousLogonToken(VOID) 2135 { 2136 SID_AND_ATTRIBUTES Groups[32], UserSid; 2137 PSID PrimaryGroup; 2138 PTOKEN Token; 2139 ULONG GroupsLength; 2140 LARGE_INTEGER Expiration; 2141 OBJECT_ATTRIBUTES ObjectAttributes; 2142 NTSTATUS Status; 2143 2144 /* The token never expires */ 2145 Expiration.QuadPart = -1; 2146 2147 /* The user is the anonymous logon */ 2148 UserSid.Sid = SeAnonymousLogonSid; 2149 UserSid.Attributes = 0; 2150 2151 /* The primary group is also the anonymous logon */ 2152 PrimaryGroup = SeAnonymousLogonSid; 2153 2154 /* The only group for the token is the World */ 2155 Groups[0].Sid = SeWorldSid; 2156 Groups[0].Attributes = SE_GROUP_ENABLED | SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT; 2157 GroupsLength = sizeof(SID_AND_ATTRIBUTES) + 2158 SeLengthSid(Groups[0].Sid); 2159 ASSERT(GroupsLength <= sizeof(Groups)); 2160 2161 /* Initialise the object attributes for the token */ 2162 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL); 2163 ASSERT(SeSystemAnonymousLogonDacl != NULL); 2164 2165 /* Create token */ 2166 Status = SepCreateToken((PHANDLE)&Token, 2167 KernelMode, 2168 0, 2169 &ObjectAttributes, 2170 TokenPrimary, 2171 SecurityAnonymous, 2172 &SeAnonymousAuthenticationId, 2173 &Expiration, 2174 &UserSid, 2175 1, 2176 Groups, 2177 GroupsLength, 2178 0, 2179 NULL, 2180 NULL, 2181 PrimaryGroup, 2182 SeSystemAnonymousLogonDacl, 2183 &SeSystemTokenSource, 2184 TRUE); 2185 ASSERT(Status == STATUS_SUCCESS); 2186 2187 /* Return the anonymous logon token */ 2188 return Token; 2189 } 2190 2191 /** 2192 * @brief 2193 * Creates the anonymous logon token for the system. This kind of token 2194 * doesn't include the everyone SID group (being SeWorldSid). 2195 * 2196 * @return 2197 * Returns the system's anonymous logon token if the operations have 2198 * completed successfully. 2199 */ 2200 CODE_SEG("INIT") 2201 PTOKEN 2202 SepCreateSystemAnonymousLogonTokenNoEveryone(VOID) 2203 { 2204 SID_AND_ATTRIBUTES UserSid; 2205 PSID PrimaryGroup; 2206 PTOKEN Token; 2207 LARGE_INTEGER Expiration; 2208 OBJECT_ATTRIBUTES ObjectAttributes; 2209 NTSTATUS Status; 2210 2211 /* The token never expires */ 2212 Expiration.QuadPart = -1; 2213 2214 /* The user is the anonymous logon */ 2215 UserSid.Sid = SeAnonymousLogonSid; 2216 UserSid.Attributes = 0; 2217 2218 /* The primary group is also the anonymous logon */ 2219 PrimaryGroup = SeAnonymousLogonSid; 2220 2221 /* Initialise the object attributes for the token */ 2222 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL); 2223 ASSERT(SeSystemAnonymousLogonDacl != NULL); 2224 2225 /* Create token */ 2226 Status = SepCreateToken((PHANDLE)&Token, 2227 KernelMode, 2228 0, 2229 &ObjectAttributes, 2230 TokenPrimary, 2231 SecurityAnonymous, 2232 &SeAnonymousAuthenticationId, 2233 &Expiration, 2234 &UserSid, 2235 0, 2236 NULL, 2237 0, 2238 0, 2239 NULL, 2240 NULL, 2241 PrimaryGroup, 2242 SeSystemAnonymousLogonDacl, 2243 &SeSystemTokenSource, 2244 TRUE); 2245 ASSERT(Status == STATUS_SUCCESS); 2246 2247 /* Return the anonymous (not including everyone) logon token */ 2248 return Token; 2249 } 2250 2251 /* PUBLIC FUNCTIONS ***********************************************************/ 2252 2253 /** 2254 * @unimplemented 2255 * @brief 2256 * Filters an access token from an existing token, making it more restricted 2257 * than the previous one. 2258 * 2259 * @param[in] ExistingToken 2260 * An existing token for filtering. 2261 * 2262 * @param[in] Flags 2263 * Privilege flag options. This parameter argument influences how the token 2264 * is filtered. Such parameter can be 0. 2265 * 2266 * @param[in] SidsToDisable 2267 * Array of SIDs to disable. 2268 * 2269 * @param[in] PrivilegesToDelete 2270 * Array of privileges to delete. 2271 * 2272 * @param[in] RestrictedSids 2273 * An array of restricted SIDs for the new filtered token. 2274 * 2275 * @param[out] FilteredToken 2276 * The newly filtered token, returned to the caller. 2277 * 2278 * @return 2279 * To be added... 2280 */ 2281 NTSTATUS 2282 NTAPI 2283 SeFilterToken( 2284 _In_ PACCESS_TOKEN ExistingToken, 2285 _In_ ULONG Flags, 2286 _In_opt_ PTOKEN_GROUPS SidsToDisable, 2287 _In_opt_ PTOKEN_PRIVILEGES PrivilegesToDelete, 2288 _In_opt_ PTOKEN_GROUPS RestrictedSids, 2289 _Out_ PACCESS_TOKEN * FilteredToken) 2290 { 2291 UNIMPLEMENTED; 2292 return STATUS_NOT_IMPLEMENTED; 2293 } 2294 2295 /** 2296 * @brief 2297 * Queries information details about the given token to the call. The difference 2298 * between NtQueryInformationToken and this routine is that the system call has 2299 * user mode buffer data probing and additional protection checks whereas this 2300 * routine doesn't have any of these. The routine is used exclusively in kernel 2301 * mode. 2302 * 2303 * @param[in] AccessToken 2304 * An access token to be given. 2305 * 2306 * @param[in] TokenInformationClass 2307 * Token information class. 2308 * 2309 * @param[out] TokenInformation 2310 * Buffer with retrieved information. Such information is arbitrary, depending 2311 * on the requested information class. 2312 * 2313 * @return 2314 * Returns STATUS_SUCCESS if the operation to query the desired information 2315 * has completed successfully. STATUS_INSUFFICIENT_RESOURCES is returned if 2316 * pool memory allocation has failed to satisfy an operation. Otherwise 2317 * STATUS_INVALID_INFO_CLASS is returned indicating that the information 2318 * class provided is not supported by the routine. 2319 * 2320 * @remarks 2321 * Only certain information classes are not implemented in this function and 2322 * these are TokenOrigin, TokenGroupsAndPrivileges, TokenRestrictedSids and 2323 * TokenSandBoxInert. The following classes are implemented in NtQueryInformationToken 2324 * only. 2325 */ 2326 NTSTATUS 2327 NTAPI 2328 SeQueryInformationToken( 2329 _In_ PACCESS_TOKEN AccessToken, 2330 _In_ TOKEN_INFORMATION_CLASS TokenInformationClass, 2331 _Outptr_result_buffer_(_Inexpressible_(token-dependent)) PVOID *TokenInformation) 2332 { 2333 NTSTATUS Status; 2334 PTOKEN Token = (PTOKEN)AccessToken; 2335 ULONG RequiredLength; 2336 union 2337 { 2338 PSID PSid; 2339 ULONG Ulong; 2340 } Unused; 2341 2342 PAGED_CODE(); 2343 2344 /* Lock the token */ 2345 SepAcquireTokenLockShared(Token); 2346 2347 switch (TokenInformationClass) 2348 { 2349 case TokenUser: 2350 { 2351 PTOKEN_USER tu; 2352 2353 DPRINT("SeQueryInformationToken(TokenUser)\n"); 2354 RequiredLength = sizeof(TOKEN_USER) + 2355 RtlLengthSid(Token->UserAndGroups[0].Sid); 2356 2357 /* Allocate the output buffer */ 2358 tu = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE); 2359 if (tu == NULL) 2360 { 2361 Status = STATUS_INSUFFICIENT_RESOURCES; 2362 break; 2363 } 2364 2365 Status = RtlCopySidAndAttributesArray(1, 2366 &Token->UserAndGroups[0], 2367 RequiredLength - sizeof(TOKEN_USER), 2368 &tu->User, 2369 (PSID)(tu + 1), 2370 &Unused.PSid, 2371 &Unused.Ulong); 2372 2373 /* Return the structure */ 2374 *TokenInformation = tu; 2375 Status = STATUS_SUCCESS; 2376 break; 2377 } 2378 2379 case TokenGroups: 2380 { 2381 PTOKEN_GROUPS tg; 2382 ULONG SidLen; 2383 PSID Sid; 2384 2385 DPRINT("SeQueryInformationToken(TokenGroups)\n"); 2386 RequiredLength = sizeof(tg->GroupCount) + 2387 RtlLengthSidAndAttributes(Token->UserAndGroupCount - 1, &Token->UserAndGroups[1]); 2388 2389 SidLen = RequiredLength - sizeof(tg->GroupCount) - 2390 ((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES)); 2391 2392 /* Allocate the output buffer */ 2393 tg = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE); 2394 if (tg == NULL) 2395 { 2396 Status = STATUS_INSUFFICIENT_RESOURCES; 2397 break; 2398 } 2399 2400 Sid = (PSID)((ULONG_PTR)tg + sizeof(tg->GroupCount) + 2401 ((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES))); 2402 2403 tg->GroupCount = Token->UserAndGroupCount - 1; 2404 Status = RtlCopySidAndAttributesArray(Token->UserAndGroupCount - 1, 2405 &Token->UserAndGroups[1], 2406 SidLen, 2407 &tg->Groups[0], 2408 Sid, 2409 &Unused.PSid, 2410 &Unused.Ulong); 2411 2412 /* Return the structure */ 2413 *TokenInformation = tg; 2414 Status = STATUS_SUCCESS; 2415 break; 2416 } 2417 2418 case TokenPrivileges: 2419 { 2420 PTOKEN_PRIVILEGES tp; 2421 2422 DPRINT("SeQueryInformationToken(TokenPrivileges)\n"); 2423 RequiredLength = sizeof(tp->PrivilegeCount) + 2424 (Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES)); 2425 2426 /* Allocate the output buffer */ 2427 tp = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE); 2428 if (tp == NULL) 2429 { 2430 Status = STATUS_INSUFFICIENT_RESOURCES; 2431 break; 2432 } 2433 2434 tp->PrivilegeCount = Token->PrivilegeCount; 2435 RtlCopyLuidAndAttributesArray(Token->PrivilegeCount, 2436 Token->Privileges, 2437 &tp->Privileges[0]); 2438 2439 /* Return the structure */ 2440 *TokenInformation = tp; 2441 Status = STATUS_SUCCESS; 2442 break; 2443 } 2444 2445 case TokenOwner: 2446 { 2447 PTOKEN_OWNER to; 2448 ULONG SidLen; 2449 2450 DPRINT("SeQueryInformationToken(TokenOwner)\n"); 2451 SidLen = RtlLengthSid(Token->UserAndGroups[Token->DefaultOwnerIndex].Sid); 2452 RequiredLength = sizeof(TOKEN_OWNER) + SidLen; 2453 2454 /* Allocate the output buffer */ 2455 to = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE); 2456 if (to == NULL) 2457 { 2458 Status = STATUS_INSUFFICIENT_RESOURCES; 2459 break; 2460 } 2461 2462 to->Owner = (PSID)(to + 1); 2463 Status = RtlCopySid(SidLen, 2464 to->Owner, 2465 Token->UserAndGroups[Token->DefaultOwnerIndex].Sid); 2466 2467 /* Return the structure */ 2468 *TokenInformation = to; 2469 Status = STATUS_SUCCESS; 2470 break; 2471 } 2472 2473 case TokenPrimaryGroup: 2474 { 2475 PTOKEN_PRIMARY_GROUP tpg; 2476 ULONG SidLen; 2477 2478 DPRINT("SeQueryInformationToken(TokenPrimaryGroup)\n"); 2479 SidLen = RtlLengthSid(Token->PrimaryGroup); 2480 RequiredLength = sizeof(TOKEN_PRIMARY_GROUP) + SidLen; 2481 2482 /* Allocate the output buffer */ 2483 tpg = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE); 2484 if (tpg == NULL) 2485 { 2486 Status = STATUS_INSUFFICIENT_RESOURCES; 2487 break; 2488 } 2489 2490 tpg->PrimaryGroup = (PSID)(tpg + 1); 2491 Status = RtlCopySid(SidLen, 2492 tpg->PrimaryGroup, 2493 Token->PrimaryGroup); 2494 2495 /* Return the structure */ 2496 *TokenInformation = tpg; 2497 Status = STATUS_SUCCESS; 2498 break; 2499 } 2500 2501 case TokenDefaultDacl: 2502 { 2503 PTOKEN_DEFAULT_DACL tdd; 2504 2505 DPRINT("SeQueryInformationToken(TokenDefaultDacl)\n"); 2506 RequiredLength = sizeof(TOKEN_DEFAULT_DACL); 2507 2508 if (Token->DefaultDacl != NULL) 2509 RequiredLength += Token->DefaultDacl->AclSize; 2510 2511 /* Allocate the output buffer */ 2512 tdd = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE); 2513 if (tdd == NULL) 2514 { 2515 Status = STATUS_INSUFFICIENT_RESOURCES; 2516 break; 2517 } 2518 2519 if (Token->DefaultDacl != NULL) 2520 { 2521 tdd->DefaultDacl = (PACL)(tdd + 1); 2522 RtlCopyMemory(tdd->DefaultDacl, 2523 Token->DefaultDacl, 2524 Token->DefaultDacl->AclSize); 2525 } 2526 else 2527 { 2528 tdd->DefaultDacl = NULL; 2529 } 2530 2531 /* Return the structure */ 2532 *TokenInformation = tdd; 2533 Status = STATUS_SUCCESS; 2534 break; 2535 } 2536 2537 case TokenSource: 2538 { 2539 PTOKEN_SOURCE ts; 2540 2541 DPRINT("SeQueryInformationToken(TokenSource)\n"); 2542 RequiredLength = sizeof(TOKEN_SOURCE); 2543 2544 /* Allocate the output buffer */ 2545 ts = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE); 2546 if (ts == NULL) 2547 { 2548 Status = STATUS_INSUFFICIENT_RESOURCES; 2549 break; 2550 } 2551 2552 *ts = Token->TokenSource; 2553 2554 /* Return the structure */ 2555 *TokenInformation = ts; 2556 Status = STATUS_SUCCESS; 2557 break; 2558 } 2559 2560 case TokenType: 2561 { 2562 PTOKEN_TYPE tt; 2563 2564 DPRINT("SeQueryInformationToken(TokenType)\n"); 2565 RequiredLength = sizeof(TOKEN_TYPE); 2566 2567 /* Allocate the output buffer */ 2568 tt = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE); 2569 if (tt == NULL) 2570 { 2571 Status = STATUS_INSUFFICIENT_RESOURCES; 2572 break; 2573 } 2574 2575 *tt = Token->TokenType; 2576 2577 /* Return the structure */ 2578 *TokenInformation = tt; 2579 Status = STATUS_SUCCESS; 2580 break; 2581 } 2582 2583 case TokenImpersonationLevel: 2584 { 2585 PSECURITY_IMPERSONATION_LEVEL sil; 2586 2587 DPRINT("SeQueryInformationToken(TokenImpersonationLevel)\n"); 2588 RequiredLength = sizeof(SECURITY_IMPERSONATION_LEVEL); 2589 2590 /* Fail if the token is not an impersonation token */ 2591 if (Token->TokenType != TokenImpersonation) 2592 { 2593 Status = STATUS_INVALID_INFO_CLASS; 2594 break; 2595 } 2596 2597 /* Allocate the output buffer */ 2598 sil = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE); 2599 if (sil == NULL) 2600 { 2601 Status = STATUS_INSUFFICIENT_RESOURCES; 2602 break; 2603 } 2604 2605 *sil = Token->ImpersonationLevel; 2606 2607 /* Return the structure */ 2608 *TokenInformation = sil; 2609 Status = STATUS_SUCCESS; 2610 break; 2611 } 2612 2613 case TokenStatistics: 2614 { 2615 PTOKEN_STATISTICS ts; 2616 2617 DPRINT("SeQueryInformationToken(TokenStatistics)\n"); 2618 RequiredLength = sizeof(TOKEN_STATISTICS); 2619 2620 /* Allocate the output buffer */ 2621 ts = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE); 2622 if (ts == NULL) 2623 { 2624 Status = STATUS_INSUFFICIENT_RESOURCES; 2625 break; 2626 } 2627 2628 ts->TokenId = Token->TokenId; 2629 ts->AuthenticationId = Token->AuthenticationId; 2630 ts->ExpirationTime = Token->ExpirationTime; 2631 ts->TokenType = Token->TokenType; 2632 ts->ImpersonationLevel = Token->ImpersonationLevel; 2633 ts->DynamicCharged = Token->DynamicCharged; 2634 ts->DynamicAvailable = Token->DynamicAvailable; 2635 ts->GroupCount = Token->UserAndGroupCount - 1; 2636 ts->PrivilegeCount = Token->PrivilegeCount; 2637 ts->ModifiedId = Token->ModifiedId; 2638 2639 /* Return the structure */ 2640 *TokenInformation = ts; 2641 Status = STATUS_SUCCESS; 2642 break; 2643 } 2644 2645 case TokenSessionId: 2646 { 2647 DPRINT("SeQueryInformationToken(TokenSessionId)\n"); 2648 Status = SeQuerySessionIdToken(Token, (PULONG)TokenInformation); 2649 break; 2650 } 2651 2652 default: 2653 DPRINT1("SeQueryInformationToken(%d) invalid information class\n", TokenInformationClass); 2654 Status = STATUS_INVALID_INFO_CLASS; 2655 break; 2656 } 2657 2658 /* Release the lock of the token */ 2659 SepReleaseTokenLock(Token); 2660 2661 return Status; 2662 } 2663 2664 /** 2665 * @brief 2666 * Queries the session ID of an access token. 2667 * 2668 * @param[in] Token 2669 * A valid access token where the session ID has to be gathered. 2670 * 2671 * @param[out] pSessionId 2672 * The returned pointer to a session ID to the caller. 2673 * 2674 * @return 2675 * Returns STATUS_SUCCESS. 2676 */ 2677 NTSTATUS 2678 NTAPI 2679 SeQuerySessionIdToken( 2680 _In_ PACCESS_TOKEN Token, 2681 _Out_ PULONG pSessionId) 2682 { 2683 PAGED_CODE(); 2684 2685 /* Lock the token */ 2686 SepAcquireTokenLockShared(Token); 2687 2688 *pSessionId = ((PTOKEN)Token)->SessionId; 2689 2690 /* Unlock the token */ 2691 SepReleaseTokenLock(Token); 2692 2693 return STATUS_SUCCESS; 2694 } 2695 2696 /** 2697 * @brief 2698 * Queries the authentication ID of an access token. 2699 * 2700 * @param[in] Token 2701 * A valid access token where the authentication ID has to be gathered. 2702 * 2703 * @param[out] pSessionId 2704 * The returned pointer to an authentication ID to the caller. 2705 * 2706 * @return 2707 * Returns STATUS_SUCCESS. 2708 */ 2709 NTSTATUS 2710 NTAPI 2711 SeQueryAuthenticationIdToken( 2712 _In_ PACCESS_TOKEN Token, 2713 _Out_ PLUID LogonId) 2714 { 2715 PAGED_CODE(); 2716 2717 *LogonId = ((PTOKEN)Token)->AuthenticationId; 2718 2719 return STATUS_SUCCESS; 2720 } 2721 2722 /** 2723 * @brief 2724 * Gathers the security impersonation level of an access token. 2725 * 2726 * @param[in] Token 2727 * A valid access token where the impersonation level has to be gathered. 2728 * 2729 * @return 2730 * Returns the security impersonation level from a valid token. 2731 */ 2732 SECURITY_IMPERSONATION_LEVEL 2733 NTAPI 2734 SeTokenImpersonationLevel( 2735 _In_ PACCESS_TOKEN Token) 2736 { 2737 PAGED_CODE(); 2738 2739 return ((PTOKEN)Token)->ImpersonationLevel; 2740 } 2741 2742 /** 2743 * @brief 2744 * Gathers the token type of an access token. A token ca be either 2745 * a primary token or impersonation token. 2746 * 2747 * @param[in] Token 2748 * A valid access token where the token type has to be gathered. 2749 * 2750 * @return 2751 * Returns the token type from a valid token. 2752 */ 2753 TOKEN_TYPE 2754 NTAPI 2755 SeTokenType( 2756 _In_ PACCESS_TOKEN Token) 2757 { 2758 PAGED_CODE(); 2759 2760 return ((PTOKEN)Token)->TokenType; 2761 } 2762 2763 /** 2764 * @brief 2765 * Determines if a token is either an admin token or not. Such 2766 * condition is checked based upon TOKEN_HAS_ADMIN_GROUP flag, 2767 * which means if the respective access token belongs to an 2768 * administrator group or not. 2769 * 2770 * @param[in] Token 2771 * A valid access token to determine if such token is admin or not. 2772 * 2773 * @return 2774 * Returns TRUE if the token is an admin one, FALSE otherwise. 2775 */ 2776 BOOLEAN 2777 NTAPI 2778 SeTokenIsAdmin( 2779 _In_ PACCESS_TOKEN Token) 2780 { 2781 PAGED_CODE(); 2782 2783 // NOTE: Win7+ instead really checks the list of groups in the token 2784 // (since TOKEN_HAS_ADMIN_GROUP == TOKEN_WRITE_RESTRICTED ...) 2785 return (((PTOKEN)Token)->TokenFlags & TOKEN_HAS_ADMIN_GROUP) != 0; 2786 } 2787 2788 /** 2789 * @brief 2790 * Determines if a token is restricted or not, based upon the token 2791 * flags. 2792 * 2793 * @param[in] Token 2794 * A valid access token to determine if such token is restricted. 2795 * 2796 * @return 2797 * Returns TRUE if the token is restricted, FALSE otherwise. 2798 */ 2799 BOOLEAN 2800 NTAPI 2801 SeTokenIsRestricted( 2802 _In_ PACCESS_TOKEN Token) 2803 { 2804 PAGED_CODE(); 2805 2806 return (((PTOKEN)Token)->TokenFlags & TOKEN_IS_RESTRICTED) != 0; 2807 } 2808 2809 /** 2810 * @brief 2811 * Determines if a token is write restricted, that is, nobody can write anything 2812 * to it. 2813 * 2814 * @param[in] Token 2815 * A valid access token to determine if such token is write restricted. 2816 * 2817 * @return 2818 * Returns TRUE if the token is write restricted, FALSE otherwise. 2819 * 2820 * @remarks 2821 * First introduced in NT 5.1 SP2 x86 (5.1.2600.2622), absent in NT 5.2, 2822 * then finally re-introduced in Vista+. 2823 */ 2824 BOOLEAN 2825 NTAPI 2826 SeTokenIsWriteRestricted( 2827 _In_ PACCESS_TOKEN Token) 2828 { 2829 PAGED_CODE(); 2830 2831 // NOTE: NT 5.1 SP2 x86 checks the SE_BACKUP_PRIVILEGES_CHECKED flag 2832 // while Vista+ checks the TOKEN_WRITE_RESTRICTED flag as one expects. 2833 return (((PTOKEN)Token)->TokenFlags & SE_BACKUP_PRIVILEGES_CHECKED) != 0; 2834 } 2835 2836 /** 2837 * @brief 2838 * Ensures that client impersonation can occur by checking if the token 2839 * we're going to assign as the impersonation token can be actually impersonated 2840 * in the first place. The routine is used primarily by PsImpersonateClient. 2841 * 2842 * @param[in] ProcessToken 2843 * Token from a process. 2844 * 2845 * @param[in] TokenToImpersonate 2846 * Token that we are going to impersonate. 2847 * 2848 * @param[in] ImpersonationLevel 2849 * Security impersonation level grade. 2850 * 2851 * @return 2852 * Returns TRUE if the conditions checked are met for token impersonation, 2853 * FALSE otherwise. 2854 */ 2855 BOOLEAN 2856 NTAPI 2857 SeTokenCanImpersonate( 2858 _In_ PTOKEN ProcessToken, 2859 _In_ PTOKEN TokenToImpersonate, 2860 _In_ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel) 2861 { 2862 BOOLEAN CanImpersonate; 2863 PAGED_CODE(); 2864 2865 /* 2866 * SecurityAnonymous and SecurityIdentification levels do not 2867 * allow impersonation. If we get such levels from the call 2868 * then something's seriously wrong. 2869 */ 2870 ASSERT(ImpersonationLevel != SecurityAnonymous || 2871 ImpersonationLevel != SecurityIdentification); 2872 2873 /* Time to lock our tokens */ 2874 SepAcquireTokenLockShared(ProcessToken); 2875 SepAcquireTokenLockShared(TokenToImpersonate); 2876 2877 /* What kind of authentication ID does the token have? */ 2878 if (RtlEqualLuid(&TokenToImpersonate->AuthenticationId, 2879 &SeAnonymousAuthenticationId)) 2880 { 2881 /* 2882 * OK, it looks like the token has an anonymous 2883 * authentication. Is that token created by the system? 2884 */ 2885 if (TokenToImpersonate->TokenSource.SourceName != SeSystemTokenSource.SourceName && 2886 !RtlEqualLuid(&TokenToImpersonate->TokenSource.SourceIdentifier, &SeSystemTokenSource.SourceIdentifier)) 2887 { 2888 /* It isn't, we can't impersonate regular tokens */ 2889 DPRINT("SeTokenCanImpersonate(): Token has an anonymous authentication ID, can't impersonate!\n"); 2890 CanImpersonate = FALSE; 2891 goto Quit; 2892 } 2893 } 2894 2895 /* Are the SID values from both tokens equal? */ 2896 if (!RtlEqualSid(ProcessToken->UserAndGroups->Sid, 2897 TokenToImpersonate->UserAndGroups->Sid)) 2898 { 2899 /* They aren't, bail out */ 2900 DPRINT("SeTokenCanImpersonate(): Tokens SIDs are not equal!\n"); 2901 CanImpersonate = FALSE; 2902 goto Quit; 2903 } 2904 2905 /* 2906 * Make sure the tokens aren't diverged in terms of 2907 * restrictions, that is, one token is restricted 2908 * but the other one isn't. 2909 */ 2910 if (SeTokenIsRestricted(ProcessToken) != 2911 SeTokenIsRestricted(TokenToImpersonate)) 2912 { 2913 /* 2914 * One token is restricted so we cannot 2915 * continue further at this point, bail out. 2916 */ 2917 DPRINT("SeTokenCanImpersonate(): One token is restricted, can't continue!\n"); 2918 CanImpersonate = FALSE; 2919 goto Quit; 2920 } 2921 2922 /* If we've reached that far then we can impersonate! */ 2923 DPRINT("SeTokenCanImpersonate(): We can impersonate.\n"); 2924 CanImpersonate = TRUE; 2925 2926 Quit: 2927 /* We're done, unlock the tokens now */ 2928 SepReleaseTokenLock(ProcessToken); 2929 SepReleaseTokenLock(TokenToImpersonate); 2930 2931 return CanImpersonate; 2932 } 2933 2934 /* SYSTEM CALLS ***************************************************************/ 2935 2936 /** 2937 * @brief 2938 * Queries a specific type of information in regard of an access token based upon 2939 * the information class. The calling thread must have specific access rights in order 2940 * to obtain specific information about the token. 2941 * 2942 * @param[in] TokenHandle 2943 * A handle of a token where information is to be gathered. 2944 * 2945 * @param[in] TokenInformationClass 2946 * Token information class. 2947 * 2948 * @param[out] TokenInformation 2949 * A returned output buffer with token information, which information is arbitrarily upon 2950 * the information class chosen. 2951 * 2952 * @param[in] TokenInformationLength 2953 * Length of the token information buffer, in bytes. 2954 * 2955 * @param[out] ReturnLength 2956 * If specified in the call, the function returns the total length size of the token 2957 * information buffer.. 2958 * 2959 * @return 2960 * Returns STATUS_SUCCESS if information querying has completed successfully. 2961 * STATUS_BUFFER_TOO_SMALL is returned if the information length that represents 2962 * the token information buffer is not greater than the required length. 2963 * STATUS_INVALID_HANDLE is returned if the token handle is not a valid one. 2964 * STATUS_INVALID_INFO_CLASS is returned if the information class is not a valid 2965 * one (that is, the class doesn't belong to TOKEN_INFORMATION_CLASS). A failure 2966 * NTSTATUS code is returned otherwise. 2967 */ 2968 _Must_inspect_result_ 2969 __kernel_entry 2970 NTSTATUS 2971 NTAPI 2972 NtQueryInformationToken( 2973 _In_ HANDLE TokenHandle, 2974 _In_ TOKEN_INFORMATION_CLASS TokenInformationClass, 2975 _Out_writes_bytes_to_opt_(TokenInformationLength, *ReturnLength) 2976 PVOID TokenInformation, 2977 _In_ ULONG TokenInformationLength, 2978 _Out_ PULONG ReturnLength) 2979 { 2980 NTSTATUS Status; 2981 KPROCESSOR_MODE PreviousMode; 2982 PTOKEN Token; 2983 ULONG RequiredLength; 2984 union 2985 { 2986 PSID PSid; 2987 ULONG Ulong; 2988 } Unused; 2989 2990 PAGED_CODE(); 2991 2992 PreviousMode = ExGetPreviousMode(); 2993 2994 /* Check buffers and class validity */ 2995 Status = DefaultQueryInfoBufferCheck(TokenInformationClass, 2996 SeTokenInformationClass, 2997 RTL_NUMBER_OF(SeTokenInformationClass), 2998 TokenInformation, 2999 TokenInformationLength, 3000 ReturnLength, 3001 NULL, 3002 PreviousMode, 3003 TRUE); 3004 if (!NT_SUCCESS(Status)) 3005 { 3006 DPRINT("NtQueryInformationToken() failed, Status: 0x%x\n", Status); 3007 return Status; 3008 } 3009 3010 Status = ObReferenceObjectByHandle(TokenHandle, 3011 (TokenInformationClass == TokenSource) ? TOKEN_QUERY_SOURCE : TOKEN_QUERY, 3012 SeTokenObjectType, 3013 PreviousMode, 3014 (PVOID*)&Token, 3015 NULL); 3016 if (NT_SUCCESS(Status)) 3017 { 3018 /* Lock the token */ 3019 SepAcquireTokenLockShared(Token); 3020 3021 switch (TokenInformationClass) 3022 { 3023 case TokenUser: 3024 { 3025 PTOKEN_USER tu = (PTOKEN_USER)TokenInformation; 3026 3027 DPRINT("NtQueryInformationToken(TokenUser)\n"); 3028 RequiredLength = sizeof(TOKEN_USER) + 3029 RtlLengthSid(Token->UserAndGroups[0].Sid); 3030 3031 _SEH2_TRY 3032 { 3033 if (TokenInformationLength >= RequiredLength) 3034 { 3035 Status = RtlCopySidAndAttributesArray(1, 3036 &Token->UserAndGroups[0], 3037 RequiredLength - sizeof(TOKEN_USER), 3038 &tu->User, 3039 (PSID)(tu + 1), 3040 &Unused.PSid, 3041 &Unused.Ulong); 3042 } 3043 else 3044 { 3045 Status = STATUS_BUFFER_TOO_SMALL; 3046 } 3047 3048 if (ReturnLength != NULL) 3049 { 3050 *ReturnLength = RequiredLength; 3051 } 3052 } 3053 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3054 { 3055 Status = _SEH2_GetExceptionCode(); 3056 } 3057 _SEH2_END; 3058 3059 break; 3060 } 3061 3062 case TokenGroups: 3063 { 3064 PTOKEN_GROUPS tg = (PTOKEN_GROUPS)TokenInformation; 3065 3066 DPRINT("NtQueryInformationToken(TokenGroups)\n"); 3067 RequiredLength = sizeof(tg->GroupCount) + 3068 RtlLengthSidAndAttributes(Token->UserAndGroupCount - 1, &Token->UserAndGroups[1]); 3069 3070 _SEH2_TRY 3071 { 3072 if (TokenInformationLength >= RequiredLength) 3073 { 3074 ULONG SidLen = RequiredLength - sizeof(tg->GroupCount) - 3075 ((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES)); 3076 PSID Sid = (PSID_AND_ATTRIBUTES)((ULONG_PTR)tg + sizeof(tg->GroupCount) + 3077 ((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES))); 3078 3079 tg->GroupCount = Token->UserAndGroupCount - 1; 3080 Status = RtlCopySidAndAttributesArray(Token->UserAndGroupCount - 1, 3081 &Token->UserAndGroups[1], 3082 SidLen, 3083 &tg->Groups[0], 3084 Sid, 3085 &Unused.PSid, 3086 &Unused.Ulong); 3087 } 3088 else 3089 { 3090 Status = STATUS_BUFFER_TOO_SMALL; 3091 } 3092 3093 if (ReturnLength != NULL) 3094 { 3095 *ReturnLength = RequiredLength; 3096 } 3097 } 3098 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3099 { 3100 Status = _SEH2_GetExceptionCode(); 3101 } 3102 _SEH2_END; 3103 3104 break; 3105 } 3106 3107 case TokenPrivileges: 3108 { 3109 PTOKEN_PRIVILEGES tp = (PTOKEN_PRIVILEGES)TokenInformation; 3110 3111 DPRINT("NtQueryInformationToken(TokenPrivileges)\n"); 3112 RequiredLength = sizeof(tp->PrivilegeCount) + 3113 (Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES)); 3114 3115 _SEH2_TRY 3116 { 3117 if (TokenInformationLength >= RequiredLength) 3118 { 3119 tp->PrivilegeCount = Token->PrivilegeCount; 3120 RtlCopyLuidAndAttributesArray(Token->PrivilegeCount, 3121 Token->Privileges, 3122 &tp->Privileges[0]); 3123 } 3124 else 3125 { 3126 Status = STATUS_BUFFER_TOO_SMALL; 3127 } 3128 3129 if (ReturnLength != NULL) 3130 { 3131 *ReturnLength = RequiredLength; 3132 } 3133 } 3134 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3135 { 3136 Status = _SEH2_GetExceptionCode(); 3137 } 3138 _SEH2_END; 3139 3140 break; 3141 } 3142 3143 case TokenOwner: 3144 { 3145 PTOKEN_OWNER to = (PTOKEN_OWNER)TokenInformation; 3146 ULONG SidLen; 3147 3148 DPRINT("NtQueryInformationToken(TokenOwner)\n"); 3149 SidLen = RtlLengthSid(Token->UserAndGroups[Token->DefaultOwnerIndex].Sid); 3150 RequiredLength = sizeof(TOKEN_OWNER) + SidLen; 3151 3152 _SEH2_TRY 3153 { 3154 if (TokenInformationLength >= RequiredLength) 3155 { 3156 to->Owner = (PSID)(to + 1); 3157 Status = RtlCopySid(SidLen, 3158 to->Owner, 3159 Token->UserAndGroups[Token->DefaultOwnerIndex].Sid); 3160 } 3161 else 3162 { 3163 Status = STATUS_BUFFER_TOO_SMALL; 3164 } 3165 3166 if (ReturnLength != NULL) 3167 { 3168 *ReturnLength = RequiredLength; 3169 } 3170 } 3171 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3172 { 3173 Status = _SEH2_GetExceptionCode(); 3174 } 3175 _SEH2_END; 3176 3177 break; 3178 } 3179 3180 case TokenPrimaryGroup: 3181 { 3182 PTOKEN_PRIMARY_GROUP tpg = (PTOKEN_PRIMARY_GROUP)TokenInformation; 3183 ULONG SidLen; 3184 3185 DPRINT("NtQueryInformationToken(TokenPrimaryGroup)\n"); 3186 SidLen = RtlLengthSid(Token->PrimaryGroup); 3187 RequiredLength = sizeof(TOKEN_PRIMARY_GROUP) + SidLen; 3188 3189 _SEH2_TRY 3190 { 3191 if (TokenInformationLength >= RequiredLength) 3192 { 3193 tpg->PrimaryGroup = (PSID)(tpg + 1); 3194 Status = RtlCopySid(SidLen, 3195 tpg->PrimaryGroup, 3196 Token->PrimaryGroup); 3197 } 3198 else 3199 { 3200 Status = STATUS_BUFFER_TOO_SMALL; 3201 } 3202 3203 if (ReturnLength != NULL) 3204 { 3205 *ReturnLength = RequiredLength; 3206 } 3207 } 3208 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3209 { 3210 Status = _SEH2_GetExceptionCode(); 3211 } 3212 _SEH2_END; 3213 3214 break; 3215 } 3216 3217 case TokenDefaultDacl: 3218 { 3219 PTOKEN_DEFAULT_DACL tdd = (PTOKEN_DEFAULT_DACL)TokenInformation; 3220 3221 DPRINT("NtQueryInformationToken(TokenDefaultDacl)\n"); 3222 RequiredLength = sizeof(TOKEN_DEFAULT_DACL); 3223 3224 if (Token->DefaultDacl != NULL) 3225 RequiredLength += Token->DefaultDacl->AclSize; 3226 3227 _SEH2_TRY 3228 { 3229 if (TokenInformationLength >= RequiredLength) 3230 { 3231 if (Token->DefaultDacl != NULL) 3232 { 3233 tdd->DefaultDacl = (PACL)(tdd + 1); 3234 RtlCopyMemory(tdd->DefaultDacl, 3235 Token->DefaultDacl, 3236 Token->DefaultDacl->AclSize); 3237 } 3238 else 3239 { 3240 tdd->DefaultDacl = NULL; 3241 } 3242 } 3243 else 3244 { 3245 Status = STATUS_BUFFER_TOO_SMALL; 3246 } 3247 3248 if (ReturnLength != NULL) 3249 { 3250 *ReturnLength = RequiredLength; 3251 } 3252 } 3253 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3254 { 3255 Status = _SEH2_GetExceptionCode(); 3256 } 3257 _SEH2_END; 3258 3259 break; 3260 } 3261 3262 case TokenSource: 3263 { 3264 PTOKEN_SOURCE ts = (PTOKEN_SOURCE)TokenInformation; 3265 3266 DPRINT("NtQueryInformationToken(TokenSource)\n"); 3267 RequiredLength = sizeof(TOKEN_SOURCE); 3268 3269 _SEH2_TRY 3270 { 3271 if (TokenInformationLength >= RequiredLength) 3272 { 3273 *ts = Token->TokenSource; 3274 } 3275 else 3276 { 3277 Status = STATUS_BUFFER_TOO_SMALL; 3278 } 3279 3280 if (ReturnLength != NULL) 3281 { 3282 *ReturnLength = RequiredLength; 3283 } 3284 } 3285 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3286 { 3287 Status = _SEH2_GetExceptionCode(); 3288 } 3289 _SEH2_END; 3290 3291 break; 3292 } 3293 3294 case TokenType: 3295 { 3296 PTOKEN_TYPE tt = (PTOKEN_TYPE)TokenInformation; 3297 3298 DPRINT("NtQueryInformationToken(TokenType)\n"); 3299 RequiredLength = sizeof(TOKEN_TYPE); 3300 3301 _SEH2_TRY 3302 { 3303 if (TokenInformationLength >= RequiredLength) 3304 { 3305 *tt = Token->TokenType; 3306 } 3307 else 3308 { 3309 Status = STATUS_BUFFER_TOO_SMALL; 3310 } 3311 3312 if (ReturnLength != NULL) 3313 { 3314 *ReturnLength = RequiredLength; 3315 } 3316 } 3317 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3318 { 3319 Status = _SEH2_GetExceptionCode(); 3320 } 3321 _SEH2_END; 3322 3323 break; 3324 } 3325 3326 case TokenImpersonationLevel: 3327 { 3328 PSECURITY_IMPERSONATION_LEVEL sil = (PSECURITY_IMPERSONATION_LEVEL)TokenInformation; 3329 3330 DPRINT("NtQueryInformationToken(TokenImpersonationLevel)\n"); 3331 3332 /* Fail if the token is not an impersonation token */ 3333 if (Token->TokenType != TokenImpersonation) 3334 { 3335 Status = STATUS_INVALID_INFO_CLASS; 3336 break; 3337 } 3338 3339 RequiredLength = sizeof(SECURITY_IMPERSONATION_LEVEL); 3340 3341 _SEH2_TRY 3342 { 3343 if (TokenInformationLength >= RequiredLength) 3344 { 3345 *sil = Token->ImpersonationLevel; 3346 } 3347 else 3348 { 3349 Status = STATUS_BUFFER_TOO_SMALL; 3350 } 3351 3352 if (ReturnLength != NULL) 3353 { 3354 *ReturnLength = RequiredLength; 3355 } 3356 } 3357 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3358 { 3359 Status = _SEH2_GetExceptionCode(); 3360 } 3361 _SEH2_END; 3362 3363 break; 3364 } 3365 3366 case TokenStatistics: 3367 { 3368 PTOKEN_STATISTICS ts = (PTOKEN_STATISTICS)TokenInformation; 3369 3370 DPRINT("NtQueryInformationToken(TokenStatistics)\n"); 3371 RequiredLength = sizeof(TOKEN_STATISTICS); 3372 3373 _SEH2_TRY 3374 { 3375 if (TokenInformationLength >= RequiredLength) 3376 { 3377 ts->TokenId = Token->TokenId; 3378 ts->AuthenticationId = Token->AuthenticationId; 3379 ts->ExpirationTime = Token->ExpirationTime; 3380 ts->TokenType = Token->TokenType; 3381 ts->ImpersonationLevel = Token->ImpersonationLevel; 3382 ts->DynamicCharged = Token->DynamicCharged; 3383 ts->DynamicAvailable = Token->DynamicAvailable; 3384 ts->GroupCount = Token->UserAndGroupCount - 1; 3385 ts->PrivilegeCount = Token->PrivilegeCount; 3386 ts->ModifiedId = Token->ModifiedId; 3387 } 3388 else 3389 { 3390 Status = STATUS_BUFFER_TOO_SMALL; 3391 } 3392 3393 if (ReturnLength != NULL) 3394 { 3395 *ReturnLength = RequiredLength; 3396 } 3397 } 3398 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3399 { 3400 Status = _SEH2_GetExceptionCode(); 3401 } 3402 _SEH2_END; 3403 3404 break; 3405 } 3406 3407 case TokenOrigin: 3408 { 3409 PTOKEN_ORIGIN to = (PTOKEN_ORIGIN)TokenInformation; 3410 3411 DPRINT("NtQueryInformationToken(TokenOrigin)\n"); 3412 RequiredLength = sizeof(TOKEN_ORIGIN); 3413 3414 _SEH2_TRY 3415 { 3416 if (TokenInformationLength >= RequiredLength) 3417 { 3418 RtlCopyLuid(&to->OriginatingLogonSession, 3419 &Token->AuthenticationId); 3420 } 3421 else 3422 { 3423 Status = STATUS_BUFFER_TOO_SMALL; 3424 } 3425 3426 if (ReturnLength != NULL) 3427 { 3428 *ReturnLength = RequiredLength; 3429 } 3430 } 3431 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3432 { 3433 Status = _SEH2_GetExceptionCode(); 3434 } 3435 _SEH2_END; 3436 3437 break; 3438 } 3439 3440 case TokenGroupsAndPrivileges: 3441 DPRINT1("NtQueryInformationToken(TokenGroupsAndPrivileges) not implemented\n"); 3442 Status = STATUS_NOT_IMPLEMENTED; 3443 break; 3444 3445 case TokenRestrictedSids: 3446 { 3447 PTOKEN_GROUPS tg = (PTOKEN_GROUPS)TokenInformation; 3448 3449 DPRINT("NtQueryInformationToken(TokenRestrictedSids)\n"); 3450 RequiredLength = sizeof(tg->GroupCount) + 3451 RtlLengthSidAndAttributes(Token->RestrictedSidCount, Token->RestrictedSids); 3452 3453 _SEH2_TRY 3454 { 3455 if (TokenInformationLength >= RequiredLength) 3456 { 3457 ULONG SidLen = RequiredLength - sizeof(tg->GroupCount) - 3458 (Token->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES)); 3459 PSID Sid = (PSID)((ULONG_PTR)tg + sizeof(tg->GroupCount) + 3460 (Token->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES))); 3461 3462 tg->GroupCount = Token->RestrictedSidCount; 3463 Status = RtlCopySidAndAttributesArray(Token->RestrictedSidCount, 3464 Token->RestrictedSids, 3465 SidLen, 3466 &tg->Groups[0], 3467 Sid, 3468 &Unused.PSid, 3469 &Unused.Ulong); 3470 } 3471 else 3472 { 3473 Status = STATUS_BUFFER_TOO_SMALL; 3474 } 3475 3476 if (ReturnLength != NULL) 3477 { 3478 *ReturnLength = RequiredLength; 3479 } 3480 } 3481 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3482 { 3483 Status = _SEH2_GetExceptionCode(); 3484 } 3485 _SEH2_END; 3486 3487 break; 3488 } 3489 3490 case TokenSandBoxInert: 3491 DPRINT1("NtQueryInformationToken(TokenSandboxInert) not implemented\n"); 3492 Status = STATUS_NOT_IMPLEMENTED; 3493 break; 3494 3495 case TokenSessionId: 3496 { 3497 ULONG SessionId = 0; 3498 3499 DPRINT("NtQueryInformationToken(TokenSessionId)\n"); 3500 3501 Status = SeQuerySessionIdToken(Token, &SessionId); 3502 if (NT_SUCCESS(Status)) 3503 { 3504 _SEH2_TRY 3505 { 3506 /* Buffer size was already verified, no need to check here again */ 3507 *(PULONG)TokenInformation = SessionId; 3508 3509 if (ReturnLength != NULL) 3510 { 3511 *ReturnLength = sizeof(ULONG); 3512 } 3513 } 3514 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3515 { 3516 Status = _SEH2_GetExceptionCode(); 3517 } 3518 _SEH2_END; 3519 } 3520 3521 break; 3522 } 3523 3524 default: 3525 DPRINT1("NtQueryInformationToken(%d) invalid information class\n", TokenInformationClass); 3526 Status = STATUS_INVALID_INFO_CLASS; 3527 break; 3528 } 3529 3530 /* Unlock and dereference the token */ 3531 SepReleaseTokenLock(Token); 3532 ObDereferenceObject(Token); 3533 } 3534 3535 return Status; 3536 } 3537 3538 /** 3539 * @unimplemented 3540 * @brief 3541 * Sets (modifies) some specific information in regard of an access token. The 3542 * calling thread must have specific access rights in order to modify token's 3543 * information data. 3544 * 3545 * @param[in] TokenHandle 3546 * A handle of a token where information is to be modified. 3547 * 3548 * @param[in] TokenInformationClass 3549 * Token information class. 3550 * 3551 * @param[in] TokenInformation 3552 * An arbitrary pointer to a buffer with token information to set. Such 3553 * arbitrary buffer depends on the information class chosen that the caller 3554 * wants to modify such information data of a token. 3555 * 3556 * @param[in] TokenInformationLength 3557 * Length of the token information buffer, in bytes. 3558 * 3559 * @return 3560 * Returns STATUS_SUCCESS if information setting has completed successfully. 3561 * STATUS_INFO_LENGTH_MISMATCH is returned if the information length of the 3562 * buffer is less than the required length. STATUS_INSUFFICIENT_RESOURCES is 3563 * returned if memory pool allocation has failed. STATUS_PRIVILEGE_NOT_HELD 3564 * is returned if the calling thread hasn't the required privileges to perform 3565 * the operation in question. A failure NTSTATUS code is returned otherwise. 3566 * 3567 * @remarks 3568 * The function is partly implemented, mainly TokenOrigin and TokenDefaultDacl. 3569 */ 3570 _Must_inspect_result_ 3571 __kernel_entry 3572 NTSTATUS 3573 NTAPI 3574 NtSetInformationToken( 3575 _In_ HANDLE TokenHandle, 3576 _In_ TOKEN_INFORMATION_CLASS TokenInformationClass, 3577 _In_reads_bytes_(TokenInformationLength) PVOID TokenInformation, 3578 _In_ ULONG TokenInformationLength) 3579 { 3580 NTSTATUS Status; 3581 PTOKEN Token; 3582 KPROCESSOR_MODE PreviousMode; 3583 ULONG NeededAccess = TOKEN_ADJUST_DEFAULT; 3584 3585 PAGED_CODE(); 3586 3587 PreviousMode = ExGetPreviousMode(); 3588 3589 Status = DefaultSetInfoBufferCheck(TokenInformationClass, 3590 SeTokenInformationClass, 3591 RTL_NUMBER_OF(SeTokenInformationClass), 3592 TokenInformation, 3593 TokenInformationLength, 3594 PreviousMode); 3595 if (!NT_SUCCESS(Status)) 3596 { 3597 /* Invalid buffers */ 3598 DPRINT("NtSetInformationToken() failed, Status: 0x%x\n", Status); 3599 return Status; 3600 } 3601 3602 if (TokenInformationClass == TokenSessionId) 3603 { 3604 NeededAccess |= TOKEN_ADJUST_SESSIONID; 3605 } 3606 3607 Status = ObReferenceObjectByHandle(TokenHandle, 3608 NeededAccess, 3609 SeTokenObjectType, 3610 PreviousMode, 3611 (PVOID*)&Token, 3612 NULL); 3613 if (NT_SUCCESS(Status)) 3614 { 3615 switch (TokenInformationClass) 3616 { 3617 case TokenOwner: 3618 { 3619 if (TokenInformationLength >= sizeof(TOKEN_OWNER)) 3620 { 3621 PTOKEN_OWNER to = (PTOKEN_OWNER)TokenInformation; 3622 PSID InputSid = NULL, CapturedSid; 3623 ULONG DefaultOwnerIndex; 3624 3625 _SEH2_TRY 3626 { 3627 InputSid = to->Owner; 3628 } 3629 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3630 { 3631 Status = _SEH2_GetExceptionCode(); 3632 _SEH2_YIELD(goto Cleanup); 3633 } 3634 _SEH2_END; 3635 3636 Status = SepCaptureSid(InputSid, 3637 PreviousMode, 3638 PagedPool, 3639 FALSE, 3640 &CapturedSid); 3641 if (NT_SUCCESS(Status)) 3642 { 3643 /* Lock the token */ 3644 SepAcquireTokenLockExclusive(Token); 3645 3646 /* Find the owner amongst the existing token user and groups */ 3647 Status = SepFindPrimaryGroupAndDefaultOwner(Token, 3648 NULL, 3649 CapturedSid, 3650 NULL, 3651 &DefaultOwnerIndex); 3652 if (NT_SUCCESS(Status)) 3653 { 3654 /* Found it */ 3655 Token->DefaultOwnerIndex = DefaultOwnerIndex; 3656 ExAllocateLocallyUniqueId(&Token->ModifiedId); 3657 } 3658 3659 /* Unlock the token */ 3660 SepReleaseTokenLock(Token); 3661 3662 SepReleaseSid(CapturedSid, 3663 PreviousMode, 3664 FALSE); 3665 } 3666 } 3667 else 3668 { 3669 Status = STATUS_INFO_LENGTH_MISMATCH; 3670 } 3671 break; 3672 } 3673 3674 case TokenPrimaryGroup: 3675 { 3676 if (TokenInformationLength >= sizeof(TOKEN_PRIMARY_GROUP)) 3677 { 3678 PTOKEN_PRIMARY_GROUP tpg = (PTOKEN_PRIMARY_GROUP)TokenInformation; 3679 PSID InputSid = NULL, CapturedSid; 3680 ULONG PrimaryGroupIndex; 3681 3682 _SEH2_TRY 3683 { 3684 InputSid = tpg->PrimaryGroup; 3685 } 3686 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3687 { 3688 Status = _SEH2_GetExceptionCode(); 3689 _SEH2_YIELD(goto Cleanup); 3690 } 3691 _SEH2_END; 3692 3693 Status = SepCaptureSid(InputSid, 3694 PreviousMode, 3695 PagedPool, 3696 FALSE, 3697 &CapturedSid); 3698 if (NT_SUCCESS(Status)) 3699 { 3700 /* Lock the token */ 3701 SepAcquireTokenLockExclusive(Token); 3702 3703 /* Find the primary group amongst the existing token user and groups */ 3704 Status = SepFindPrimaryGroupAndDefaultOwner(Token, 3705 CapturedSid, 3706 NULL, 3707 &PrimaryGroupIndex, 3708 NULL); 3709 if (NT_SUCCESS(Status)) 3710 { 3711 /* Found it */ 3712 Token->PrimaryGroup = Token->UserAndGroups[PrimaryGroupIndex].Sid; 3713 ExAllocateLocallyUniqueId(&Token->ModifiedId); 3714 } 3715 3716 /* Unlock the token */ 3717 SepReleaseTokenLock(Token); 3718 3719 SepReleaseSid(CapturedSid, 3720 PreviousMode, 3721 FALSE); 3722 } 3723 } 3724 else 3725 { 3726 Status = STATUS_INFO_LENGTH_MISMATCH; 3727 } 3728 break; 3729 } 3730 3731 case TokenDefaultDacl: 3732 { 3733 if (TokenInformationLength >= sizeof(TOKEN_DEFAULT_DACL)) 3734 { 3735 PTOKEN_DEFAULT_DACL tdd = (PTOKEN_DEFAULT_DACL)TokenInformation; 3736 PACL InputAcl = NULL; 3737 3738 _SEH2_TRY 3739 { 3740 InputAcl = tdd->DefaultDacl; 3741 } 3742 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3743 { 3744 Status = _SEH2_GetExceptionCode(); 3745 _SEH2_YIELD(goto Cleanup); 3746 } 3747 _SEH2_END; 3748 3749 if (InputAcl != NULL) 3750 { 3751 PACL CapturedAcl; 3752 3753 /* Capture and copy the dacl */ 3754 Status = SepCaptureAcl(InputAcl, 3755 PreviousMode, 3756 PagedPool, 3757 TRUE, 3758 &CapturedAcl); 3759 if (NT_SUCCESS(Status)) 3760 { 3761 ULONG DynamicLength; 3762 3763 /* Lock the token */ 3764 SepAcquireTokenLockExclusive(Token); 3765 3766 // 3767 // NOTE: So far our dynamic area only contains 3768 // the default dacl, so this makes the following 3769 // code pretty simple. The day where it stores 3770 // other data, the code will require adaptations. 3771 // 3772 3773 DynamicLength = Token->DynamicAvailable; 3774 // Add here any other data length present in the dynamic area... 3775 if (Token->DefaultDacl) 3776 DynamicLength += Token->DefaultDacl->AclSize; 3777 3778 /* Reallocate the dynamic area if it is too small */ 3779 Status = STATUS_SUCCESS; 3780 if ((DynamicLength < CapturedAcl->AclSize) || 3781 (Token->DynamicPart == NULL)) 3782 { 3783 PVOID NewDynamicPart; 3784 3785 NewDynamicPart = ExAllocatePoolWithTag(PagedPool, 3786 CapturedAcl->AclSize, 3787 TAG_TOKEN_DYNAMIC); 3788 if (NewDynamicPart == NULL) 3789 { 3790 Status = STATUS_INSUFFICIENT_RESOURCES; 3791 } 3792 else 3793 { 3794 if (Token->DynamicPart != NULL) 3795 { 3796 // RtlCopyMemory(NewDynamicPart, Token->DynamicPart, DynamicLength); 3797 ExFreePoolWithTag(Token->DynamicPart, TAG_TOKEN_DYNAMIC); 3798 } 3799 Token->DynamicPart = NewDynamicPart; 3800 Token->DynamicAvailable = 0; 3801 } 3802 } 3803 else 3804 { 3805 Token->DynamicAvailable = DynamicLength - CapturedAcl->AclSize; 3806 } 3807 3808 if (NT_SUCCESS(Status)) 3809 { 3810 /* Set the new dacl */ 3811 Token->DefaultDacl = (PVOID)Token->DynamicPart; 3812 RtlCopyMemory(Token->DefaultDacl, 3813 CapturedAcl, 3814 CapturedAcl->AclSize); 3815 3816 ExAllocateLocallyUniqueId(&Token->ModifiedId); 3817 } 3818 3819 /* Unlock the token */ 3820 SepReleaseTokenLock(Token); 3821 3822 ExFreePoolWithTag(CapturedAcl, TAG_ACL); 3823 } 3824 } 3825 else 3826 { 3827 /* Lock the token */ 3828 SepAcquireTokenLockExclusive(Token); 3829 3830 /* Clear the default dacl if present */ 3831 if (Token->DefaultDacl != NULL) 3832 { 3833 Token->DynamicAvailable += Token->DefaultDacl->AclSize; 3834 RtlZeroMemory(Token->DefaultDacl, Token->DefaultDacl->AclSize); 3835 Token->DefaultDacl = NULL; 3836 3837 ExAllocateLocallyUniqueId(&Token->ModifiedId); 3838 } 3839 3840 /* Unlock the token */ 3841 SepReleaseTokenLock(Token); 3842 } 3843 } 3844 else 3845 { 3846 Status = STATUS_INFO_LENGTH_MISMATCH; 3847 } 3848 break; 3849 } 3850 3851 case TokenSessionId: 3852 { 3853 ULONG SessionId = 0; 3854 3855 _SEH2_TRY 3856 { 3857 /* Buffer size was already verified, no need to check here again */ 3858 SessionId = *(PULONG)TokenInformation; 3859 } 3860 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3861 { 3862 Status = _SEH2_GetExceptionCode(); 3863 _SEH2_YIELD(goto Cleanup); 3864 } 3865 _SEH2_END; 3866 3867 /* Check for TCB privilege */ 3868 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode)) 3869 { 3870 Status = STATUS_PRIVILEGE_NOT_HELD; 3871 break; 3872 } 3873 3874 /* Lock the token */ 3875 SepAcquireTokenLockExclusive(Token); 3876 3877 Token->SessionId = SessionId; 3878 ExAllocateLocallyUniqueId(&Token->ModifiedId); 3879 3880 /* Unlock the token */ 3881 SepReleaseTokenLock(Token); 3882 3883 break; 3884 } 3885 3886 case TokenSessionReference: 3887 { 3888 ULONG SessionReference; 3889 3890 _SEH2_TRY 3891 { 3892 /* Buffer size was already verified, no need to check here again */ 3893 SessionReference = *(PULONG)TokenInformation; 3894 } 3895 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3896 { 3897 Status = _SEH2_GetExceptionCode(); 3898 _SEH2_YIELD(goto Cleanup); 3899 } 3900 _SEH2_END; 3901 3902 /* Check for TCB privilege */ 3903 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode)) 3904 { 3905 Status = STATUS_PRIVILEGE_NOT_HELD; 3906 goto Cleanup; 3907 } 3908 3909 /* Check if it is 0 */ 3910 if (SessionReference == 0) 3911 { 3912 ULONG OldTokenFlags; 3913 3914 /* Lock the token */ 3915 SepAcquireTokenLockExclusive(Token); 3916 3917 /* Atomically set the flag in the token */ 3918 OldTokenFlags = RtlInterlockedSetBits(&Token->TokenFlags, 3919 TOKEN_SESSION_NOT_REFERENCED); 3920 /* 3921 * If the flag was already set, do not dereference again 3922 * the logon session. Use SessionReference as an indicator 3923 * to know whether to really dereference the session. 3924 */ 3925 if (OldTokenFlags == Token->TokenFlags) 3926 SessionReference = ULONG_MAX; 3927 3928 /* 3929 * Otherwise if the flag was never set but just for this first time then 3930 * remove the referenced logon session data from the token and dereference 3931 * the logon session when needed. 3932 */ 3933 if (SessionReference == 0) 3934 { 3935 SepRmRemoveLogonSessionFromToken(Token); 3936 SepRmDereferenceLogonSession(&Token->AuthenticationId); 3937 } 3938 3939 /* Unlock the token */ 3940 SepReleaseTokenLock(Token); 3941 } 3942 break; 3943 } 3944 3945 case TokenAuditPolicy: 3946 { 3947 PTOKEN_AUDIT_POLICY_INFORMATION PolicyInformation = 3948 (PTOKEN_AUDIT_POLICY_INFORMATION)TokenInformation; 3949 SEP_AUDIT_POLICY AuditPolicy; 3950 ULONG i; 3951 3952 _SEH2_TRY 3953 { 3954 ProbeForRead(PolicyInformation, 3955 FIELD_OFFSET(TOKEN_AUDIT_POLICY_INFORMATION, 3956 Policies[PolicyInformation->PolicyCount]), 3957 sizeof(ULONG)); 3958 3959 /* Loop all policies in the structure */ 3960 for (i = 0; i < PolicyInformation->PolicyCount; i++) 3961 { 3962 /* Set the corresponding bits in the packed structure */ 3963 switch (PolicyInformation->Policies[i].Category) 3964 { 3965 case AuditCategorySystem: 3966 AuditPolicy.PolicyElements.System = PolicyInformation->Policies[i].Value; 3967 break; 3968 3969 case AuditCategoryLogon: 3970 AuditPolicy.PolicyElements.Logon = PolicyInformation->Policies[i].Value; 3971 break; 3972 3973 case AuditCategoryObjectAccess: 3974 AuditPolicy.PolicyElements.ObjectAccess = PolicyInformation->Policies[i].Value; 3975 break; 3976 3977 case AuditCategoryPrivilegeUse: 3978 AuditPolicy.PolicyElements.PrivilegeUse = PolicyInformation->Policies[i].Value; 3979 break; 3980 3981 case AuditCategoryDetailedTracking: 3982 AuditPolicy.PolicyElements.DetailedTracking = PolicyInformation->Policies[i].Value; 3983 break; 3984 3985 case AuditCategoryPolicyChange: 3986 AuditPolicy.PolicyElements.PolicyChange = PolicyInformation->Policies[i].Value; 3987 break; 3988 3989 case AuditCategoryAccountManagement: 3990 AuditPolicy.PolicyElements.AccountManagement = PolicyInformation->Policies[i].Value; 3991 break; 3992 3993 case AuditCategoryDirectoryServiceAccess: 3994 AuditPolicy.PolicyElements.DirectoryServiceAccess = PolicyInformation->Policies[i].Value; 3995 break; 3996 3997 case AuditCategoryAccountLogon: 3998 AuditPolicy.PolicyElements.AccountLogon = PolicyInformation->Policies[i].Value; 3999 break; 4000 } 4001 } 4002 } 4003 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4004 { 4005 Status = _SEH2_GetExceptionCode(); 4006 _SEH2_YIELD(goto Cleanup); 4007 } 4008 _SEH2_END; 4009 4010 /* Check for TCB privilege */ 4011 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode)) 4012 { 4013 Status = STATUS_PRIVILEGE_NOT_HELD; 4014 break; 4015 } 4016 4017 /* Lock the token */ 4018 SepAcquireTokenLockExclusive(Token); 4019 4020 /* Set the new audit policy */ 4021 Token->AuditPolicy = AuditPolicy; 4022 ExAllocateLocallyUniqueId(&Token->ModifiedId); 4023 4024 /* Unlock the token */ 4025 SepReleaseTokenLock(Token); 4026 4027 break; 4028 } 4029 4030 case TokenOrigin: 4031 { 4032 TOKEN_ORIGIN TokenOrigin; 4033 4034 _SEH2_TRY 4035 { 4036 /* Copy the token origin */ 4037 TokenOrigin = *(PTOKEN_ORIGIN)TokenInformation; 4038 } 4039 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4040 { 4041 Status = _SEH2_GetExceptionCode(); 4042 _SEH2_YIELD(goto Cleanup); 4043 } 4044 _SEH2_END; 4045 4046 /* Check for TCB privilege */ 4047 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode)) 4048 { 4049 Status = STATUS_PRIVILEGE_NOT_HELD; 4050 break; 4051 } 4052 4053 /* Lock the token */ 4054 SepAcquireTokenLockExclusive(Token); 4055 4056 /* Check if there is no token origin set yet */ 4057 if (RtlIsZeroLuid(&Token->OriginatingLogonSession)) 4058 { 4059 /* Set the token origin */ 4060 Token->OriginatingLogonSession = 4061 TokenOrigin.OriginatingLogonSession; 4062 4063 ExAllocateLocallyUniqueId(&Token->ModifiedId); 4064 } 4065 4066 /* Unlock the token */ 4067 SepReleaseTokenLock(Token); 4068 4069 break; 4070 } 4071 4072 default: 4073 { 4074 DPRINT1("Invalid TokenInformationClass: 0x%lx\n", 4075 TokenInformationClass); 4076 Status = STATUS_INVALID_INFO_CLASS; 4077 break; 4078 } 4079 } 4080 Cleanup: 4081 ObDereferenceObject(Token); 4082 } 4083 4084 if (!NT_SUCCESS(Status)) 4085 { 4086 DPRINT1("NtSetInformationToken failed with Status 0x%lx\n", Status); 4087 } 4088 4089 return Status; 4090 } 4091 4092 /** 4093 * @brief 4094 * Duplicates a token. 4095 * 4096 * @param[in] ExistingTokenHandle 4097 * An existing token to duplicate. 4098 * 4099 * @param[in] DesiredAccess 4100 * The desired access rights for the new duplicated token. 4101 * 4102 * @param[in] ObjectAttributes 4103 * Object attributes for the new duplicated token. 4104 * 4105 * @param[in] EffectiveOnly 4106 * If set to TRUE, the function removes all the disabled privileges and groups 4107 * of the token to duplicate. 4108 * 4109 * @param[in] TokenType 4110 * Type of token to assign to the duplicated token. 4111 * 4112 * @param[out] NewTokenHandle 4113 * The returned duplicated token handle. 4114 * 4115 * @return 4116 * STATUS_SUCCESS is returned if token duplication has completed successfully. 4117 * STATUS_BAD_IMPERSONATION_LEVEL is returned if the caller erroneously wants 4118 * to raise the impersonation level even though the conditions do not permit 4119 * it. A failure NTSTATUS code is returned otherwise. 4120 * 4121 * @remarks 4122 * Some sources claim 4th param is ImpersonationLevel, but on W2K 4123 * this is certainly NOT true, although I can't say for sure that EffectiveOnly 4124 * is correct either. -Gunnar 4125 * This is true. EffectiveOnly overrides SQOS.EffectiveOnly. - IAI 4126 * NOTE for readers: http://hex.pp.ua/nt/NtDuplicateToken.php is therefore 4127 * wrong in that regard, while MSDN documentation is correct. 4128 */ 4129 _Must_inspect_result_ 4130 __kernel_entry 4131 NTSTATUS 4132 NTAPI 4133 NtDuplicateToken( 4134 _In_ HANDLE ExistingTokenHandle, 4135 _In_ ACCESS_MASK DesiredAccess, 4136 _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, 4137 _In_ BOOLEAN EffectiveOnly, 4138 _In_ TOKEN_TYPE TokenType, 4139 _Out_ PHANDLE NewTokenHandle) 4140 { 4141 KPROCESSOR_MODE PreviousMode; 4142 HANDLE hToken; 4143 PTOKEN Token; 4144 PTOKEN NewToken; 4145 PSECURITY_QUALITY_OF_SERVICE CapturedSecurityQualityOfService; 4146 BOOLEAN QoSPresent; 4147 OBJECT_HANDLE_INFORMATION HandleInformation; 4148 NTSTATUS Status; 4149 4150 PAGED_CODE(); 4151 4152 if (TokenType != TokenImpersonation && 4153 TokenType != TokenPrimary) 4154 { 4155 return STATUS_INVALID_PARAMETER; 4156 } 4157 4158 PreviousMode = KeGetPreviousMode(); 4159 4160 if (PreviousMode != KernelMode) 4161 { 4162 _SEH2_TRY 4163 { 4164 ProbeForWriteHandle(NewTokenHandle); 4165 } 4166 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4167 { 4168 /* Return the exception code */ 4169 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 4170 } 4171 _SEH2_END; 4172 } 4173 4174 Status = SepCaptureSecurityQualityOfService(ObjectAttributes, 4175 PreviousMode, 4176 PagedPool, 4177 FALSE, 4178 &CapturedSecurityQualityOfService, 4179 &QoSPresent); 4180 if (!NT_SUCCESS(Status)) 4181 { 4182 DPRINT1("NtDuplicateToken() failed to capture QoS! Status: 0x%x\n", Status); 4183 return Status; 4184 } 4185 4186 Status = ObReferenceObjectByHandle(ExistingTokenHandle, 4187 TOKEN_DUPLICATE, 4188 SeTokenObjectType, 4189 PreviousMode, 4190 (PVOID*)&Token, 4191 &HandleInformation); 4192 if (!NT_SUCCESS(Status)) 4193 { 4194 DPRINT1("Failed to reference token (Status 0x%lx)\n", Status); 4195 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService, 4196 PreviousMode, 4197 FALSE); 4198 return Status; 4199 } 4200 4201 /* 4202 * Fail, if the original token is an impersonation token and the caller 4203 * tries to raise the impersonation level of the new token above the 4204 * impersonation level of the original token. 4205 */ 4206 if (Token->TokenType == TokenImpersonation) 4207 { 4208 if (QoSPresent && 4209 CapturedSecurityQualityOfService->ImpersonationLevel >Token->ImpersonationLevel) 4210 { 4211 ObDereferenceObject(Token); 4212 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService, 4213 PreviousMode, 4214 FALSE); 4215 return STATUS_BAD_IMPERSONATION_LEVEL; 4216 } 4217 } 4218 4219 /* 4220 * Fail, if a primary token is to be created from an impersonation token 4221 * and and the impersonation level of the impersonation token is below SecurityImpersonation. 4222 */ 4223 if (Token->TokenType == TokenImpersonation && 4224 TokenType == TokenPrimary && 4225 Token->ImpersonationLevel < SecurityImpersonation) 4226 { 4227 ObDereferenceObject(Token); 4228 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService, 4229 PreviousMode, 4230 FALSE); 4231 return STATUS_BAD_IMPERSONATION_LEVEL; 4232 } 4233 4234 Status = SepDuplicateToken(Token, 4235 ObjectAttributes, 4236 EffectiveOnly, 4237 TokenType, 4238 (QoSPresent ? CapturedSecurityQualityOfService->ImpersonationLevel : SecurityAnonymous), 4239 PreviousMode, 4240 &NewToken); 4241 4242 ObDereferenceObject(Token); 4243 4244 if (NT_SUCCESS(Status)) 4245 { 4246 Status = ObInsertObject(NewToken, 4247 NULL, 4248 (DesiredAccess ? DesiredAccess : HandleInformation.GrantedAccess), 4249 0, 4250 NULL, 4251 &hToken); 4252 if (NT_SUCCESS(Status)) 4253 { 4254 _SEH2_TRY 4255 { 4256 *NewTokenHandle = hToken; 4257 } 4258 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4259 { 4260 Status = _SEH2_GetExceptionCode(); 4261 } 4262 _SEH2_END; 4263 } 4264 } 4265 4266 /* Free the captured structure */ 4267 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService, 4268 PreviousMode, 4269 FALSE); 4270 4271 return Status; 4272 } 4273 4274 /** 4275 * @brief 4276 * Changes the groups list of SIDs of a token. 4277 * 4278 * @param[in] TokenHandle 4279 * Token handle where the list of groups SIDs are to be adjusted. 4280 * 4281 * @param[in] ResetToDefault 4282 * If set to TRUE, the function resets the list of groups SIDs to default. 4283 * All the rest of parameters are ignored. 4284 * 4285 * @param[in] NewState 4286 * A new list of groups SIDs that the function will use it accordingly to 4287 * modify the current list of groups SIDs of a token. 4288 * 4289 * @param[in] BufferLength 4290 * The length size of the buffer that is pointed by the NewState parameter 4291 * argument, in bytes. 4292 * 4293 * @param[out] PreviousState 4294 * If specified, the function will return to the caller the old list of groups 4295 * SIDs. 4296 * 4297 * @param[out] ReturnLength 4298 * If specified, the function will return the total size length of the old list 4299 * of groups SIDs, in bytes. 4300 * 4301 * @return 4302 * To be added... 4303 */ 4304 NTSTATUS 4305 NTAPI 4306 NtAdjustGroupsToken( 4307 _In_ HANDLE TokenHandle, 4308 _In_ BOOLEAN ResetToDefault, 4309 _In_ PTOKEN_GROUPS NewState, 4310 _In_ ULONG BufferLength, 4311 _Out_opt_ PTOKEN_GROUPS PreviousState, 4312 _Out_ PULONG ReturnLength) 4313 { 4314 UNIMPLEMENTED; 4315 return STATUS_NOT_IMPLEMENTED; 4316 } 4317 4318 /** 4319 * @brief 4320 * Removes a certain amount of privileges of a token based upon the request 4321 * by the caller. 4322 * 4323 * @param[in,out] Token 4324 * Token handle where the privileges are about to be modified. 4325 * 4326 * @param[in] DisableAllPrivileges 4327 * If set to TRUE, the function disables all the privileges. 4328 * 4329 * @param[in] NewState 4330 * A new list of privileges that the function will use it accordingly to 4331 * either disable or enable the said privileges and change them. 4332 * 4333 * @param[in] NewStateCount 4334 * The new total number count of privileges. 4335 * 4336 * @param[out] PreviousState 4337 * If specified, the function will return the previous state list of privileges. 4338 * 4339 * @param[in] ApplyChanges 4340 * If set to TRUE, the function will immediatelly apply the changes onto the 4341 * token's privileges. 4342 * 4343 * @param[out] ChangedPrivileges 4344 * The returned count number of changed privileges. 4345 * 4346 * @param[out] ChangesMade 4347 * If TRUE, the function has made changes to the token's privileges. FALSE 4348 * otherwise. 4349 * 4350 * @return 4351 * Returns STATUS_SUCCESS if the function has successfully changed the list 4352 * of privileges. STATUS_NOT_ALL_ASSIGNED is returned if not every privilege 4353 * has been changed. 4354 */ 4355 static 4356 NTSTATUS 4357 SepAdjustPrivileges( 4358 _Inout_ PTOKEN Token, 4359 _In_ BOOLEAN DisableAllPrivileges, 4360 _In_opt_ PLUID_AND_ATTRIBUTES NewState, 4361 _In_ ULONG NewStateCount, 4362 _Out_opt_ PTOKEN_PRIVILEGES PreviousState, 4363 _In_ BOOLEAN ApplyChanges, 4364 _Out_ PULONG ChangedPrivileges, 4365 _Out_ PBOOLEAN ChangesMade) 4366 { 4367 ULONG i, j, PrivilegeCount, ChangeCount, NewAttributes; 4368 4369 /* Count the found privileges and those that need to be changed */ 4370 PrivilegeCount = 0; 4371 ChangeCount = 0; 4372 *ChangesMade = FALSE; 4373 4374 /* Loop all privileges in the token */ 4375 for (i = 0; i < Token->PrivilegeCount; i++) 4376 { 4377 /* Shall all of them be disabled? */ 4378 if (DisableAllPrivileges) 4379 { 4380 /* The new attributes are the old ones, but disabled */ 4381 NewAttributes = Token->Privileges[i].Attributes & ~SE_PRIVILEGE_ENABLED; 4382 } 4383 else 4384 { 4385 /* Otherwise loop all provided privileges */ 4386 for (j = 0; j < NewStateCount; j++) 4387 { 4388 /* Check if this is the LUID we are looking for */ 4389 if (RtlEqualLuid(&Token->Privileges[i].Luid, &NewState[j].Luid)) 4390 { 4391 DPRINT("Found privilege\n"); 4392 4393 /* Copy SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_REMOVED */ 4394 NewAttributes = NewState[j].Attributes; 4395 NewAttributes &= (SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_REMOVED); 4396 NewAttributes |= Token->Privileges[i].Attributes & ~SE_PRIVILEGE_ENABLED; 4397 4398 /* Stop looking */ 4399 break; 4400 } 4401 } 4402 4403 /* Check if we didn't find the privilege */ 4404 if (j == NewStateCount) 4405 { 4406 /* Continue with the token's next privilege */ 4407 continue; 4408 } 4409 } 4410 4411 /* We found a privilege, count it */ 4412 PrivilegeCount++; 4413 4414 /* Does the privilege need to be changed? */ 4415 if (Token->Privileges[i].Attributes != NewAttributes) 4416 { 4417 /* Does the caller want the old privileges? */ 4418 if (PreviousState != NULL) 4419 { 4420 /* Copy the old privilege */ 4421 PreviousState->Privileges[ChangeCount] = Token->Privileges[i]; 4422 } 4423 4424 /* Does the caller want to apply the changes? */ 4425 if (ApplyChanges) 4426 { 4427 /* Shall we remove the privilege? */ 4428 if (NewAttributes & SE_PRIVILEGE_REMOVED) 4429 { 4430 /* Set the token as disabled and update flags for it */ 4431 Token->Privileges[i].Attributes &= ~SE_PRIVILEGE_ENABLED; 4432 SepUpdateSinglePrivilegeFlagToken(Token, i); 4433 4434 /* Remove the privilege */ 4435 SepRemovePrivilegeToken(Token, i); 4436 4437 *ChangesMade = TRUE; 4438 4439 /* Fix the running index and continue with next one */ 4440 i--; 4441 continue; 4442 } 4443 4444 /* Set the new attributes and update flags */ 4445 Token->Privileges[i].Attributes = NewAttributes; 4446 SepUpdateSinglePrivilegeFlagToken(Token, i); 4447 *ChangesMade = TRUE; 4448 } 4449 4450 /* Increment the change count */ 4451 ChangeCount++; 4452 } 4453 } 4454 4455 /* Set the number of saved privileges */ 4456 if (PreviousState != NULL) 4457 PreviousState->PrivilegeCount = ChangeCount; 4458 4459 /* Return the number of changed privileges */ 4460 *ChangedPrivileges = ChangeCount; 4461 4462 /* Check if we missed some */ 4463 if (!DisableAllPrivileges && (PrivilegeCount < NewStateCount)) 4464 { 4465 return STATUS_NOT_ALL_ASSIGNED; 4466 } 4467 4468 return STATUS_SUCCESS; 4469 } 4470 4471 /** 4472 * @brief 4473 * Removes a certain amount of privileges of a token based upon the request 4474 * by the caller. 4475 * 4476 * @param[in,out] Token 4477 * Token handle where the privileges are about to be modified. 4478 * 4479 * @param[in] DisableAllPrivileges 4480 * If set to TRUE, the function disables all the privileges. 4481 * 4482 * @param[in] NewState 4483 * A new list of privileges that the function will use it accordingly to 4484 * either disable or enable the said privileges and change them. 4485 * 4486 * @param[in] NewStateCount 4487 * The new total number count of privileges. 4488 * 4489 * @param[out] PreviousState 4490 * If specified, the function will return the previous state list of privileges. 4491 * 4492 * @param[in] ApplyChanges 4493 * If set to TRUE, the function will immediatelly apply the changes onto the 4494 * token's privileges. 4495 * 4496 * @param[out] ChangedPrivileges 4497 * The returned count number of changed privileges. 4498 * 4499 * @param[out] ChangesMade 4500 * If TRUE, the function has made changes to the token's privileges. FALSE 4501 * otherwise. 4502 * 4503 * @return 4504 * Returns STATUS_SUCCESS if the function has successfully changed the list 4505 * of privileges. STATUS_NOT_ALL_ASSIGNED is returned if not every privilege 4506 * has been changed. 4507 */ 4508 _Must_inspect_result_ 4509 __kernel_entry 4510 NTSTATUS 4511 NTAPI 4512 NtAdjustPrivilegesToken( 4513 _In_ HANDLE TokenHandle, 4514 _In_ BOOLEAN DisableAllPrivileges, 4515 _In_opt_ PTOKEN_PRIVILEGES NewState, 4516 _In_ ULONG BufferLength, 4517 _Out_writes_bytes_to_opt_(BufferLength,*ReturnLength) 4518 PTOKEN_PRIVILEGES PreviousState, 4519 _When_(PreviousState!=NULL, _Out_) PULONG ReturnLength) 4520 { 4521 NTSTATUS Status; 4522 KPROCESSOR_MODE PreviousMode; 4523 PTOKEN Token; 4524 PLUID_AND_ATTRIBUTES CapturedPrivileges = NULL; 4525 ULONG CapturedCount = 0; 4526 ULONG CapturedLength = 0; 4527 ULONG NewStateSize = 0; 4528 ULONG ChangeCount; 4529 ULONG RequiredLength; 4530 BOOLEAN ChangesMade = FALSE; 4531 4532 PAGED_CODE(); 4533 4534 DPRINT("NtAdjustPrivilegesToken() called\n"); 4535 4536 /* Fail, if we do not disable all privileges but NewState is NULL */ 4537 if (DisableAllPrivileges == FALSE && NewState == NULL) 4538 return STATUS_INVALID_PARAMETER; 4539 4540 PreviousMode = KeGetPreviousMode(); 4541 if (PreviousMode != KernelMode) 4542 { 4543 _SEH2_TRY 4544 { 4545 /* Probe NewState */ 4546 if (DisableAllPrivileges == FALSE) 4547 { 4548 /* First probe the header */ 4549 ProbeForRead(NewState, sizeof(TOKEN_PRIVILEGES), sizeof(ULONG)); 4550 4551 CapturedCount = NewState->PrivilegeCount; 4552 NewStateSize = FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges[CapturedCount]); 4553 4554 ProbeForRead(NewState, NewStateSize, sizeof(ULONG)); 4555 } 4556 4557 /* Probe PreviousState and ReturnLength */ 4558 if (PreviousState != NULL) 4559 { 4560 ProbeForWrite(PreviousState, BufferLength, sizeof(ULONG)); 4561 ProbeForWrite(ReturnLength, sizeof(ULONG), sizeof(ULONG)); 4562 } 4563 } 4564 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4565 { 4566 /* Return the exception code */ 4567 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 4568 } 4569 _SEH2_END; 4570 } 4571 else 4572 { 4573 /* This is kernel mode, we trust the caller */ 4574 if (DisableAllPrivileges == FALSE) 4575 CapturedCount = NewState->PrivilegeCount; 4576 } 4577 4578 /* Do we need to capture the new state? */ 4579 if (DisableAllPrivileges == FALSE) 4580 { 4581 _SEH2_TRY 4582 { 4583 /* Capture the new state array of privileges */ 4584 Status = SeCaptureLuidAndAttributesArray(NewState->Privileges, 4585 CapturedCount, 4586 PreviousMode, 4587 NULL, 4588 0, 4589 PagedPool, 4590 TRUE, 4591 &CapturedPrivileges, 4592 &CapturedLength); 4593 } 4594 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4595 { 4596 /* Return the exception code */ 4597 Status = _SEH2_GetExceptionCode(); 4598 } 4599 _SEH2_END; 4600 4601 if (!NT_SUCCESS(Status)) 4602 return Status; 4603 } 4604 4605 /* Reference the token */ 4606 Status = ObReferenceObjectByHandle(TokenHandle, 4607 TOKEN_ADJUST_PRIVILEGES | (PreviousState != NULL ? TOKEN_QUERY : 0), 4608 SeTokenObjectType, 4609 PreviousMode, 4610 (PVOID*)&Token, 4611 NULL); 4612 if (!NT_SUCCESS(Status)) 4613 { 4614 DPRINT1("Failed to reference token (Status 0x%lx)\n", Status); 4615 4616 /* Release the captured privileges */ 4617 if (CapturedPrivileges != NULL) 4618 { 4619 SeReleaseLuidAndAttributesArray(CapturedPrivileges, 4620 PreviousMode, 4621 TRUE); 4622 } 4623 4624 return Status; 4625 } 4626 4627 /* Lock the token */ 4628 SepAcquireTokenLockExclusive(Token); 4629 4630 /* Count the privileges that need to be changed, do not apply them yet */ 4631 Status = SepAdjustPrivileges(Token, 4632 DisableAllPrivileges, 4633 CapturedPrivileges, 4634 CapturedCount, 4635 NULL, 4636 FALSE, 4637 &ChangeCount, 4638 &ChangesMade); 4639 4640 /* Check if the caller asked for the previous state */ 4641 if (PreviousState != NULL) 4642 { 4643 /* Calculate the required length */ 4644 RequiredLength = FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges[ChangeCount]); 4645 4646 /* Try to return the required buffer length */ 4647 _SEH2_TRY 4648 { 4649 *ReturnLength = RequiredLength; 4650 } 4651 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4652 { 4653 /* Do cleanup and return the exception code */ 4654 Status = _SEH2_GetExceptionCode(); 4655 _SEH2_YIELD(goto Cleanup); 4656 } 4657 _SEH2_END; 4658 4659 /* Fail, if the buffer length is smaller than the required length */ 4660 if (BufferLength < RequiredLength) 4661 { 4662 Status = STATUS_BUFFER_TOO_SMALL; 4663 goto Cleanup; 4664 } 4665 } 4666 4667 /* Now enter SEH, since we might return the old privileges */ 4668 _SEH2_TRY 4669 { 4670 /* This time apply the changes */ 4671 Status = SepAdjustPrivileges(Token, 4672 DisableAllPrivileges, 4673 CapturedPrivileges, 4674 CapturedCount, 4675 PreviousState, 4676 TRUE, 4677 &ChangeCount, 4678 &ChangesMade); 4679 } 4680 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4681 { 4682 /* Do cleanup and return the exception code */ 4683 Status = _SEH2_GetExceptionCode(); 4684 ChangesMade = TRUE; // Force write. 4685 _SEH2_YIELD(goto Cleanup); 4686 } 4687 _SEH2_END; 4688 4689 Cleanup: 4690 /* Touch the token if we made changes */ 4691 if (ChangesMade) 4692 ExAllocateLocallyUniqueId(&Token->ModifiedId); 4693 4694 /* Unlock and dereference the token */ 4695 SepReleaseTokenLock(Token); 4696 ObDereferenceObject(Token); 4697 4698 /* Release the captured privileges */ 4699 if (CapturedPrivileges != NULL) 4700 { 4701 SeReleaseLuidAndAttributesArray(CapturedPrivileges, 4702 PreviousMode, 4703 TRUE); 4704 } 4705 4706 DPRINT ("NtAdjustPrivilegesToken() done\n"); 4707 return Status; 4708 } 4709 4710 /** 4711 * @brief 4712 * Creates an access token. 4713 * 4714 * @param[out] TokenHandle 4715 * The returned created token handle to the caller. 4716 * 4717 * @param[in] DesiredAccess 4718 * The desired access rights for the token that we're creating. 4719 * 4720 * @param[in] ObjectAttributes 4721 * The object attributes for the token object that we're creating. 4722 * 4723 * @param[in] TokenType 4724 * The type of token to assign for the newly created token. 4725 * 4726 * @param[in] AuthenticationId 4727 * Authentication ID that represents the token's identity. 4728 * 4729 * @param[in] ExpirationTime 4730 * Expiration time for the token. If set to -1, the token never expires. 4731 * 4732 * @param[in] TokenUser 4733 * The main user entity for the token to assign. 4734 * 4735 * @param[in] TokenGroups 4736 * Group list of SIDs for the token to assign. 4737 * 4738 * @param[in] TokenPrivileges 4739 * Privileges for the token. 4740 * 4741 * @param[in] TokenOwner 4742 * The main user that owns the newly created token. 4743 * 4744 * @param[in] TokenPrimaryGroup 4745 * The primary group that represents as the main group of the token. 4746 * 4747 * @param[in] TokenDefaultDacl 4748 * Discretionary access control list for the token. This limits on how 4749 * the token can be used, accessed and used by whom. 4750 * 4751 * @param[in] TokenSource 4752 * The source origin of the token who creates it. 4753 * 4754 * @return 4755 * Returns STATUS_SUCCESS if the function has successfully created the token. 4756 * A failure NTSTATUS code is returned otherwise. 4757 */ 4758 __kernel_entry 4759 NTSTATUS 4760 NTAPI 4761 NtCreateToken( 4762 _Out_ PHANDLE TokenHandle, 4763 _In_ ACCESS_MASK DesiredAccess, 4764 _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, 4765 _In_ TOKEN_TYPE TokenType, 4766 _In_ PLUID AuthenticationId, 4767 _In_ PLARGE_INTEGER ExpirationTime, 4768 _In_ PTOKEN_USER TokenUser, 4769 _In_ PTOKEN_GROUPS TokenGroups, 4770 _In_ PTOKEN_PRIVILEGES TokenPrivileges, 4771 _In_opt_ PTOKEN_OWNER TokenOwner, 4772 _In_ PTOKEN_PRIMARY_GROUP TokenPrimaryGroup, 4773 _In_opt_ PTOKEN_DEFAULT_DACL TokenDefaultDacl, 4774 _In_ PTOKEN_SOURCE TokenSource) 4775 { 4776 HANDLE hToken; 4777 KPROCESSOR_MODE PreviousMode; 4778 ULONG PrivilegeCount, GroupCount; 4779 PSID OwnerSid, PrimaryGroupSid; 4780 PACL DefaultDacl; 4781 LARGE_INTEGER LocalExpirationTime = {{0, 0}}; 4782 LUID LocalAuthenticationId; 4783 TOKEN_SOURCE LocalTokenSource; 4784 SECURITY_QUALITY_OF_SERVICE LocalSecurityQos; 4785 PLUID_AND_ATTRIBUTES CapturedPrivileges = NULL; 4786 PSID_AND_ATTRIBUTES CapturedUser = NULL; 4787 PSID_AND_ATTRIBUTES CapturedGroups = NULL; 4788 PSID CapturedOwnerSid = NULL; 4789 PSID CapturedPrimaryGroupSid = NULL; 4790 PACL CapturedDefaultDacl = NULL; 4791 ULONG PrivilegesLength, UserLength, GroupsLength; 4792 NTSTATUS Status; 4793 4794 PAGED_CODE(); 4795 4796 PreviousMode = ExGetPreviousMode(); 4797 4798 if (PreviousMode != KernelMode) 4799 { 4800 _SEH2_TRY 4801 { 4802 ProbeForWriteHandle(TokenHandle); 4803 4804 if (ObjectAttributes != NULL) 4805 { 4806 ProbeForRead(ObjectAttributes, 4807 sizeof(OBJECT_ATTRIBUTES), 4808 sizeof(ULONG)); 4809 LocalSecurityQos = *(SECURITY_QUALITY_OF_SERVICE*)ObjectAttributes->SecurityQualityOfService; 4810 } 4811 4812 ProbeForRead(AuthenticationId, 4813 sizeof(LUID), 4814 sizeof(ULONG)); 4815 LocalAuthenticationId = *AuthenticationId; 4816 4817 LocalExpirationTime = ProbeForReadLargeInteger(ExpirationTime); 4818 4819 ProbeForRead(TokenUser, 4820 sizeof(TOKEN_USER), 4821 sizeof(ULONG)); 4822 4823 ProbeForRead(TokenGroups, 4824 sizeof(TOKEN_GROUPS), 4825 sizeof(ULONG)); 4826 GroupCount = TokenGroups->GroupCount; 4827 4828 ProbeForRead(TokenPrivileges, 4829 sizeof(TOKEN_PRIVILEGES), 4830 sizeof(ULONG)); 4831 PrivilegeCount = TokenPrivileges->PrivilegeCount; 4832 4833 if (TokenOwner != NULL) 4834 { 4835 ProbeForRead(TokenOwner, 4836 sizeof(TOKEN_OWNER), 4837 sizeof(ULONG)); 4838 OwnerSid = TokenOwner->Owner; 4839 } 4840 else 4841 { 4842 OwnerSid = NULL; 4843 } 4844 4845 ProbeForRead(TokenPrimaryGroup, 4846 sizeof(TOKEN_PRIMARY_GROUP), 4847 sizeof(ULONG)); 4848 PrimaryGroupSid = TokenPrimaryGroup->PrimaryGroup; 4849 4850 if (TokenDefaultDacl != NULL) 4851 { 4852 ProbeForRead(TokenDefaultDacl, 4853 sizeof(TOKEN_DEFAULT_DACL), 4854 sizeof(ULONG)); 4855 DefaultDacl = TokenDefaultDacl->DefaultDacl; 4856 } 4857 else 4858 { 4859 DefaultDacl = NULL; 4860 } 4861 4862 ProbeForRead(TokenSource, 4863 sizeof(TOKEN_SOURCE), 4864 sizeof(ULONG)); 4865 LocalTokenSource = *TokenSource; 4866 } 4867 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4868 { 4869 /* Return the exception code */ 4870 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 4871 } 4872 _SEH2_END; 4873 } 4874 else 4875 { 4876 if (ObjectAttributes != NULL) 4877 LocalSecurityQos = *(SECURITY_QUALITY_OF_SERVICE*)ObjectAttributes->SecurityQualityOfService; 4878 LocalAuthenticationId = *AuthenticationId; 4879 LocalExpirationTime = *ExpirationTime; 4880 GroupCount = TokenGroups->GroupCount; 4881 PrivilegeCount = TokenPrivileges->PrivilegeCount; 4882 OwnerSid = TokenOwner ? TokenOwner->Owner : NULL; 4883 PrimaryGroupSid = TokenPrimaryGroup->PrimaryGroup; 4884 DefaultDacl = TokenDefaultDacl ? TokenDefaultDacl->DefaultDacl : NULL; 4885 LocalTokenSource = *TokenSource; 4886 } 4887 4888 /* Check token type */ 4889 if ((TokenType < TokenPrimary) || 4890 (TokenType > TokenImpersonation)) 4891 { 4892 return STATUS_BAD_TOKEN_TYPE; 4893 } 4894 4895 /* Check for token creation privilege */ 4896 if (!SeSinglePrivilegeCheck(SeCreateTokenPrivilege, PreviousMode)) 4897 { 4898 return STATUS_PRIVILEGE_NOT_HELD; 4899 } 4900 4901 /* Capture the user SID and attributes */ 4902 Status = SeCaptureSidAndAttributesArray(&TokenUser->User, 4903 1, 4904 PreviousMode, 4905 NULL, 4906 0, 4907 PagedPool, 4908 FALSE, 4909 &CapturedUser, 4910 &UserLength); 4911 if (!NT_SUCCESS(Status)) 4912 { 4913 goto Cleanup; 4914 } 4915 4916 /* Capture the groups SID and attributes array */ 4917 Status = SeCaptureSidAndAttributesArray(&TokenGroups->Groups[0], 4918 GroupCount, 4919 PreviousMode, 4920 NULL, 4921 0, 4922 PagedPool, 4923 FALSE, 4924 &CapturedGroups, 4925 &GroupsLength); 4926 if (!NT_SUCCESS(Status)) 4927 { 4928 goto Cleanup; 4929 } 4930 4931 /* Capture privileges */ 4932 Status = SeCaptureLuidAndAttributesArray(&TokenPrivileges->Privileges[0], 4933 PrivilegeCount, 4934 PreviousMode, 4935 NULL, 4936 0, 4937 PagedPool, 4938 FALSE, 4939 &CapturedPrivileges, 4940 &PrivilegesLength); 4941 if (!NT_SUCCESS(Status)) 4942 { 4943 goto Cleanup; 4944 } 4945 4946 /* Capture the token owner SID */ 4947 if (TokenOwner != NULL) 4948 { 4949 Status = SepCaptureSid(OwnerSid, 4950 PreviousMode, 4951 PagedPool, 4952 FALSE, 4953 &CapturedOwnerSid); 4954 if (!NT_SUCCESS(Status)) 4955 { 4956 goto Cleanup; 4957 } 4958 } 4959 4960 /* Capture the token primary group SID */ 4961 Status = SepCaptureSid(PrimaryGroupSid, 4962 PreviousMode, 4963 PagedPool, 4964 FALSE, 4965 &CapturedPrimaryGroupSid); 4966 if (!NT_SUCCESS(Status)) 4967 { 4968 goto Cleanup; 4969 } 4970 4971 /* Capture DefaultDacl */ 4972 if (DefaultDacl != NULL) 4973 { 4974 Status = SepCaptureAcl(DefaultDacl, 4975 PreviousMode, 4976 NonPagedPool, 4977 FALSE, 4978 &CapturedDefaultDacl); 4979 if (!NT_SUCCESS(Status)) 4980 { 4981 goto Cleanup; 4982 } 4983 } 4984 4985 /* Call the internal function */ 4986 Status = SepCreateToken(&hToken, 4987 PreviousMode, 4988 DesiredAccess, 4989 ObjectAttributes, 4990 TokenType, 4991 LocalSecurityQos.ImpersonationLevel, 4992 &LocalAuthenticationId, 4993 &LocalExpirationTime, 4994 CapturedUser, 4995 GroupCount, 4996 CapturedGroups, 4997 GroupsLength, 4998 PrivilegeCount, 4999 CapturedPrivileges, 5000 CapturedOwnerSid, 5001 CapturedPrimaryGroupSid, 5002 CapturedDefaultDacl, 5003 &LocalTokenSource, 5004 FALSE); 5005 if (NT_SUCCESS(Status)) 5006 { 5007 _SEH2_TRY 5008 { 5009 *TokenHandle = hToken; 5010 } 5011 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 5012 { 5013 Status = _SEH2_GetExceptionCode(); 5014 } 5015 _SEH2_END; 5016 } 5017 5018 Cleanup: 5019 5020 /* Release what we captured */ 5021 SeReleaseSidAndAttributesArray(CapturedUser, PreviousMode, FALSE); 5022 SeReleaseSidAndAttributesArray(CapturedGroups, PreviousMode, FALSE); 5023 SeReleaseLuidAndAttributesArray(CapturedPrivileges, PreviousMode, FALSE); 5024 SepReleaseSid(CapturedOwnerSid, PreviousMode, FALSE); 5025 SepReleaseSid(CapturedPrimaryGroupSid, PreviousMode, FALSE); 5026 SepReleaseAcl(CapturedDefaultDacl, PreviousMode, FALSE); 5027 5028 return Status; 5029 } 5030 5031 /** 5032 * @brief 5033 * Opens a token that is tied to a thread handle. 5034 * 5035 * @param[out] ThreadHandle 5036 * Thread handle where the token is about to be opened. 5037 * 5038 * @param[in] DesiredAccess 5039 * The request access right for the token. 5040 * 5041 * @param[in] OpenAsSelf 5042 * If set to TRUE, the access check will be made with the security context 5043 * of the process of the calling thread (opening as self). Otherwise the access 5044 * check will be made with the security context of the calling thread instead. 5045 * 5046 * @param[in] HandleAttributes 5047 * Handle attributes for the opened thread token handle. 5048 * 5049 * @param[out] TokenHandle 5050 * The opened token handle returned to the caller for use. 5051 * 5052 * @return 5053 * Returns STATUS_SUCCESS if the function has successfully opened the thread 5054 * token. STATUS_CANT_OPEN_ANONYMOUS is returned if a token has SecurityAnonymous 5055 * as impersonation level and we cannot open it. A failure NTSTATUS code is returned 5056 * otherwise. 5057 */ 5058 NTSTATUS 5059 NTAPI 5060 NtOpenThreadTokenEx( 5061 _In_ HANDLE ThreadHandle, 5062 _In_ ACCESS_MASK DesiredAccess, 5063 _In_ BOOLEAN OpenAsSelf, 5064 _In_ ULONG HandleAttributes, 5065 _Out_ PHANDLE TokenHandle) 5066 { 5067 PETHREAD Thread; 5068 HANDLE hToken; 5069 PTOKEN Token, NewToken = NULL, PrimaryToken; 5070 BOOLEAN CopyOnOpen, EffectiveOnly; 5071 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; 5072 SE_IMPERSONATION_STATE ImpersonationState; 5073 OBJECT_ATTRIBUTES ObjectAttributes; 5074 SECURITY_DESCRIPTOR SecurityDescriptor; 5075 PACL Dacl = NULL; 5076 KPROCESSOR_MODE PreviousMode; 5077 NTSTATUS Status; 5078 BOOLEAN RestoreImpersonation = FALSE; 5079 5080 PAGED_CODE(); 5081 5082 PreviousMode = ExGetPreviousMode(); 5083 5084 if (PreviousMode != KernelMode) 5085 { 5086 _SEH2_TRY 5087 { 5088 ProbeForWriteHandle(TokenHandle); 5089 } 5090 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 5091 { 5092 /* Return the exception code */ 5093 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 5094 } 5095 _SEH2_END; 5096 } 5097 5098 /* Validate object attributes */ 5099 HandleAttributes = ObpValidateAttributes(HandleAttributes, PreviousMode); 5100 5101 /* 5102 * At first open the thread token for information access and verify 5103 * that the token associated with thread is valid. 5104 */ 5105 5106 Status = ObReferenceObjectByHandle(ThreadHandle, THREAD_QUERY_INFORMATION, 5107 PsThreadType, PreviousMode, (PVOID*)&Thread, 5108 NULL); 5109 if (!NT_SUCCESS(Status)) 5110 { 5111 return Status; 5112 } 5113 5114 Token = PsReferenceImpersonationToken(Thread, &CopyOnOpen, &EffectiveOnly, 5115 &ImpersonationLevel); 5116 if (Token == NULL) 5117 { 5118 ObDereferenceObject(Thread); 5119 return STATUS_NO_TOKEN; 5120 } 5121 5122 if (ImpersonationLevel == SecurityAnonymous) 5123 { 5124 PsDereferenceImpersonationToken(Token); 5125 ObDereferenceObject(Thread); 5126 return STATUS_CANT_OPEN_ANONYMOUS; 5127 } 5128 5129 /* 5130 * Revert to self if OpenAsSelf is specified. 5131 */ 5132 5133 if (OpenAsSelf) 5134 { 5135 RestoreImpersonation = PsDisableImpersonation(PsGetCurrentThread(), 5136 &ImpersonationState); 5137 } 5138 5139 if (CopyOnOpen) 5140 { 5141 PrimaryToken = PsReferencePrimaryToken(Thread->ThreadsProcess); 5142 5143 Status = SepCreateImpersonationTokenDacl(Token, PrimaryToken, &Dacl); 5144 5145 ObFastDereferenceObject(&Thread->ThreadsProcess->Token, PrimaryToken); 5146 5147 if (NT_SUCCESS(Status)) 5148 { 5149 if (Dacl) 5150 { 5151 Status = RtlCreateSecurityDescriptor(&SecurityDescriptor, 5152 SECURITY_DESCRIPTOR_REVISION); 5153 if (!NT_SUCCESS(Status)) 5154 { 5155 DPRINT1("NtOpenThreadTokenEx(): Failed to create a security descriptor (Status 0x%lx)\n", Status); 5156 } 5157 5158 Status = RtlSetDaclSecurityDescriptor(&SecurityDescriptor, TRUE, Dacl, 5159 FALSE); 5160 if (!NT_SUCCESS(Status)) 5161 { 5162 DPRINT1("NtOpenThreadTokenEx(): Failed to set a DACL to the security descriptor (Status 0x%lx)\n", Status); 5163 } 5164 } 5165 5166 InitializeObjectAttributes(&ObjectAttributes, NULL, HandleAttributes, 5167 NULL, Dacl ? &SecurityDescriptor : NULL); 5168 5169 Status = SepDuplicateToken(Token, &ObjectAttributes, EffectiveOnly, 5170 TokenImpersonation, ImpersonationLevel, 5171 KernelMode, &NewToken); 5172 if (!NT_SUCCESS(Status)) 5173 { 5174 DPRINT1("NtOpenThreadTokenEx(): Failed to duplicate the token (Status 0x%lx)\n"); 5175 } 5176 5177 ObReferenceObject(NewToken); 5178 Status = ObInsertObject(NewToken, NULL, DesiredAccess, 0, NULL, 5179 &hToken); 5180 if (!NT_SUCCESS(Status)) 5181 { 5182 DPRINT1("NtOpenThreadTokenEx(): Failed to insert the token object (Status 0x%lx)\n", Status); 5183 } 5184 } 5185 else 5186 { 5187 DPRINT1("NtOpenThreadTokenEx(): Failed to impersonate token from DACL (Status 0x%lx)\n", Status); 5188 } 5189 } 5190 else 5191 { 5192 Status = ObOpenObjectByPointer(Token, HandleAttributes, 5193 NULL, DesiredAccess, SeTokenObjectType, 5194 PreviousMode, &hToken); 5195 if (!NT_SUCCESS(Status)) 5196 { 5197 DPRINT1("NtOpenThreadTokenEx(): Failed to open the object (Status 0x%lx)\n", Status); 5198 } 5199 } 5200 5201 if (Dacl) ExFreePoolWithTag(Dacl, TAG_ACL); 5202 5203 if (RestoreImpersonation) 5204 { 5205 PsRestoreImpersonation(PsGetCurrentThread(), &ImpersonationState); 5206 } 5207 5208 ObDereferenceObject(Token); 5209 5210 if (NT_SUCCESS(Status) && CopyOnOpen) 5211 { 5212 Status = PsImpersonateClient(Thread, NewToken, FALSE, EffectiveOnly, ImpersonationLevel); 5213 if (!NT_SUCCESS(Status)) 5214 { 5215 DPRINT1("NtOpenThreadTokenEx(): Failed to impersonate the client (Status 0x%lx)\n"); 5216 } 5217 } 5218 5219 if (NewToken) ObDereferenceObject(NewToken); 5220 5221 ObDereferenceObject(Thread); 5222 5223 if (NT_SUCCESS(Status)) 5224 { 5225 _SEH2_TRY 5226 { 5227 *TokenHandle = hToken; 5228 } 5229 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 5230 { 5231 Status = _SEH2_GetExceptionCode(); 5232 } 5233 _SEH2_END; 5234 } 5235 5236 return Status; 5237 } 5238 5239 /** 5240 * @brief 5241 * Opens a token that is tied to a thread handle. 5242 * 5243 * @param[out] ThreadHandle 5244 * Thread handle where the token is about to be opened. 5245 * 5246 * @param[in] DesiredAccess 5247 * The request access right for the token. 5248 * 5249 * @param[in] OpenAsSelf 5250 * If set to TRUE, the access check will be made with the security context 5251 * of the process of the calling thread (opening as self). Otherwise the access 5252 * check will be made with the security context of the calling thread instead. 5253 * 5254 * @param[out] TokenHandle 5255 * The opened token handle returned to the caller for use. 5256 * 5257 * @return 5258 * See NtOpenThreadTokenEx. 5259 */ 5260 NTSTATUS 5261 NTAPI 5262 NtOpenThreadToken( 5263 _In_ HANDLE ThreadHandle, 5264 _In_ ACCESS_MASK DesiredAccess, 5265 _In_ BOOLEAN OpenAsSelf, 5266 _Out_ PHANDLE TokenHandle) 5267 { 5268 return NtOpenThreadTokenEx(ThreadHandle, DesiredAccess, OpenAsSelf, 0, 5269 TokenHandle); 5270 } 5271 5272 /** 5273 * @brief 5274 * Compares tokens if they're equal or not. 5275 * 5276 * @param[in] FirstToken 5277 * The first token. 5278 * 5279 * @param[in] SecondToken 5280 * The second token. 5281 * 5282 * @param[out] Equal 5283 * The retrieved value which determines if the tokens are 5284 * equal or not. 5285 * 5286 * @return 5287 * Returns STATUS_SUCCESS, otherwise it returns a failure NTSTATUS code. 5288 */ 5289 NTSTATUS 5290 NTAPI 5291 NtCompareTokens( 5292 _In_ HANDLE FirstTokenHandle, 5293 _In_ HANDLE SecondTokenHandle, 5294 _Out_ PBOOLEAN Equal) 5295 { 5296 KPROCESSOR_MODE PreviousMode; 5297 PTOKEN FirstToken, SecondToken; 5298 BOOLEAN IsEqual; 5299 NTSTATUS Status; 5300 5301 PAGED_CODE(); 5302 5303 PreviousMode = ExGetPreviousMode(); 5304 5305 if (PreviousMode != KernelMode) 5306 { 5307 _SEH2_TRY 5308 { 5309 ProbeForWriteBoolean(Equal); 5310 } 5311 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 5312 { 5313 /* Return the exception code */ 5314 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 5315 } 5316 _SEH2_END; 5317 } 5318 5319 Status = ObReferenceObjectByHandle(FirstTokenHandle, 5320 TOKEN_QUERY, 5321 SeTokenObjectType, 5322 PreviousMode, 5323 (PVOID*)&FirstToken, 5324 NULL); 5325 if (!NT_SUCCESS(Status)) 5326 { 5327 DPRINT1("ObReferenceObjectByHandle() failed (Status 0x%lx)\n", Status); 5328 return Status; 5329 } 5330 5331 Status = ObReferenceObjectByHandle(SecondTokenHandle, 5332 TOKEN_QUERY, 5333 SeTokenObjectType, 5334 PreviousMode, 5335 (PVOID*)&SecondToken, 5336 NULL); 5337 if (!NT_SUCCESS(Status)) 5338 { 5339 DPRINT1("ObReferenceObjectByHandle() failed (Status 0x%lx)\n", Status); 5340 ObDereferenceObject(FirstToken); 5341 return Status; 5342 } 5343 5344 if (FirstToken != SecondToken) 5345 { 5346 Status = SepCompareTokens(FirstToken, 5347 SecondToken, 5348 &IsEqual); 5349 } 5350 else 5351 { 5352 IsEqual = TRUE; 5353 } 5354 5355 ObDereferenceObject(SecondToken); 5356 ObDereferenceObject(FirstToken); 5357 5358 if (NT_SUCCESS(Status)) 5359 { 5360 _SEH2_TRY 5361 { 5362 *Equal = IsEqual; 5363 } 5364 _SEH2_EXCEPT(ExSystemExceptionFilter()) 5365 { 5366 Status = _SEH2_GetExceptionCode(); 5367 } 5368 _SEH2_END; 5369 } 5370 5371 return Status; 5372 } 5373 5374 /** 5375 * @unimplemented 5376 * @brief 5377 * Opens a token that is tied to a thread handle. 5378 * 5379 * @param[in] ExistingTokenHandle 5380 * An existing token for filtering. 5381 * 5382 * @param[in] Flags 5383 * Privilege flag options. This parameter argument influences how the token 5384 * is filtered. Such parameter can be 0. 5385 * 5386 * @param[in] SidsToDisable 5387 * Array of SIDs to disable. 5388 * 5389 * @param[in] PrivilegesToDelete 5390 * Array of privileges to delete. 5391 * 5392 * @param[in] RestrictedSids 5393 * An array of restricted SIDs for the new filtered token. 5394 * 5395 * @param[out] NewTokenHandle 5396 * The newly filtered token, returned to the caller. 5397 * 5398 * @return 5399 * To be added... 5400 */ 5401 NTSTATUS 5402 NTAPI 5403 NtFilterToken( 5404 _In_ HANDLE ExistingTokenHandle, 5405 _In_ ULONG Flags, 5406 _In_opt_ PTOKEN_GROUPS SidsToDisable, 5407 _In_opt_ PTOKEN_PRIVILEGES PrivilegesToDelete, 5408 _In_opt_ PTOKEN_GROUPS RestrictedSids, 5409 _Out_ PHANDLE NewTokenHandle) 5410 { 5411 UNIMPLEMENTED; 5412 return STATUS_NOT_IMPLEMENTED; 5413 } 5414 5415 /** 5416 * @brief 5417 * Allows the calling thread to impersonate the system's anonymous 5418 * logon token. 5419 * 5420 * @param[in] ThreadHandle 5421 * A handle to the thread to start the procedure of logon token 5422 * impersonation. The thread must have the THREAD_IMPERSONATE 5423 * access right. 5424 * 5425 * @return 5426 * Returns STATUS_SUCCESS if the thread has successfully impersonated the 5427 * anonymous logon token, otherwise a failure NTSTATUS code is returned. 5428 * 5429 * @remarks 5430 * By default the system gives the opportunity to the caller to impersonate 5431 * the anonymous logon token without including the Everyone Group SID. 5432 * In cases where the caller wants to impersonate the token including such 5433 * group, the EveryoneIncludesAnonymous registry value setting has to be set 5434 * to 1, from HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa registry 5435 * path. The calling thread must invoke PsRevertToSelf when impersonation 5436 * is no longer needed or RevertToSelf if the calling execution is done 5437 * in user mode. 5438 */ 5439 NTSTATUS 5440 NTAPI 5441 NtImpersonateAnonymousToken( 5442 _In_ HANDLE ThreadHandle) 5443 { 5444 PETHREAD Thread; 5445 KPROCESSOR_MODE PreviousMode; 5446 NTSTATUS Status; 5447 PAGED_CODE(); 5448 5449 PreviousMode = ExGetPreviousMode(); 5450 5451 /* Obtain the thread object from the handle */ 5452 Status = ObReferenceObjectByHandle(ThreadHandle, 5453 THREAD_IMPERSONATE, 5454 PsThreadType, 5455 PreviousMode, 5456 (PVOID*)&Thread, 5457 NULL); 5458 if (!NT_SUCCESS(Status)) 5459 { 5460 DPRINT1("NtImpersonateAnonymousToken(): Failed to reference the object (Status 0x%lx)\n", Status); 5461 return Status; 5462 } 5463 5464 /* Call the private routine to impersonate the token */ 5465 Status = SepImpersonateAnonymousToken(Thread, PreviousMode); 5466 if (!NT_SUCCESS(Status)) 5467 { 5468 DPRINT1("NtImpersonateAnonymousToken(): Failed to impersonate the token (Status 0x%lx)\n", Status); 5469 } 5470 5471 ObDereferenceObject(Thread); 5472 return Status; 5473 } 5474 5475 /* EOF */ 5476