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 PrimaryGroupIndex; 1008 ULONG VariableLength; 1009 ULONG TotalSize; 1010 ULONG PrivilegesIndex, GroupsIndex; 1011 1012 PAGED_CODE(); 1013 1014 /* Compute how much size we need to allocate for the token */ 1015 VariableLength = Token->VariableLength; 1016 TotalSize = FIELD_OFFSET(TOKEN, VariablePart) + VariableLength; 1017 1018 Status = ObCreateObject(PreviousMode, 1019 SeTokenObjectType, 1020 ObjectAttributes, 1021 PreviousMode, 1022 NULL, 1023 TotalSize, 1024 0, 1025 0, 1026 (PVOID*)&AccessToken); 1027 if (!NT_SUCCESS(Status)) 1028 { 1029 DPRINT1("ObCreateObject() failed (Status 0x%lx)\n", Status); 1030 return Status; 1031 } 1032 1033 /* Zero out the buffer and initialize the token */ 1034 RtlZeroMemory(AccessToken, TotalSize); 1035 1036 ExAllocateLocallyUniqueId(&AccessToken->TokenId); 1037 1038 AccessToken->TokenType = TokenType; 1039 AccessToken->ImpersonationLevel = Level; 1040 1041 /* Initialise the lock for the access token */ 1042 Status = SepCreateTokenLock(AccessToken); 1043 if (!NT_SUCCESS(Status)) 1044 { 1045 ObDereferenceObject(AccessToken); 1046 return Status; 1047 } 1048 1049 /* Copy the immutable fields */ 1050 RtlCopyLuid(&AccessToken->TokenSource.SourceIdentifier, 1051 &Token->TokenSource.SourceIdentifier); 1052 RtlCopyMemory(AccessToken->TokenSource.SourceName, 1053 Token->TokenSource.SourceName, 1054 sizeof(Token->TokenSource.SourceName)); 1055 1056 AccessToken->AuthenticationId = Token->AuthenticationId; 1057 AccessToken->ParentTokenId = Token->ParentTokenId; 1058 AccessToken->ExpirationTime = Token->ExpirationTime; 1059 AccessToken->OriginatingLogonSession = Token->OriginatingLogonSession; 1060 1061 /* Lock the source token and copy the mutable fields */ 1062 SepAcquireTokenLockExclusive(Token); 1063 1064 AccessToken->SessionId = Token->SessionId; 1065 RtlCopyLuid(&AccessToken->ModifiedId, &Token->ModifiedId); 1066 1067 AccessToken->TokenFlags = Token->TokenFlags & ~TOKEN_SESSION_NOT_REFERENCED; 1068 1069 /* Reference the logon session */ 1070 Status = SepRmReferenceLogonSession(&AccessToken->AuthenticationId); 1071 if (!NT_SUCCESS(Status)) 1072 { 1073 /* No logon session could be found, bail out */ 1074 DPRINT1("SepRmReferenceLogonSession() failed (Status 0x%lx)\n", Status); 1075 /* Set the flag for proper cleanup by the delete procedure */ 1076 AccessToken->TokenFlags |= TOKEN_SESSION_NOT_REFERENCED; 1077 goto Quit; 1078 } 1079 1080 /* Insert the referenced logon session into the token */ 1081 Status = SepRmInsertLogonSessionIntoToken(AccessToken); 1082 if (!NT_SUCCESS(Status)) 1083 { 1084 /* Failed to insert the logon session into the token, bail out */ 1085 DPRINT1("SepRmInsertLogonSessionIntoToken() failed (Status 0x%lx)\n", Status); 1086 goto Quit; 1087 } 1088 1089 /* Assign the data that reside in the TOKEN's variable information area */ 1090 AccessToken->VariableLength = VariableLength; 1091 EndMem = (PVOID)&AccessToken->VariablePart; 1092 1093 /* Copy the privileges */ 1094 AccessToken->PrivilegeCount = 0; 1095 AccessToken->Privileges = NULL; 1096 if (Token->Privileges && (Token->PrivilegeCount > 0)) 1097 { 1098 ULONG PrivilegesLength = Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES); 1099 PrivilegesLength = ALIGN_UP_BY(PrivilegesLength, sizeof(PVOID)); 1100 1101 ASSERT(VariableLength >= PrivilegesLength); 1102 1103 AccessToken->PrivilegeCount = Token->PrivilegeCount; 1104 AccessToken->Privileges = EndMem; 1105 EndMem = (PVOID)((ULONG_PTR)EndMem + PrivilegesLength); 1106 VariableLength -= PrivilegesLength; 1107 1108 RtlCopyMemory(AccessToken->Privileges, 1109 Token->Privileges, 1110 AccessToken->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES)); 1111 } 1112 1113 /* Copy the user and groups */ 1114 AccessToken->UserAndGroupCount = 0; 1115 AccessToken->UserAndGroups = NULL; 1116 if (Token->UserAndGroups && (Token->UserAndGroupCount > 0)) 1117 { 1118 AccessToken->UserAndGroupCount = Token->UserAndGroupCount; 1119 AccessToken->UserAndGroups = EndMem; 1120 EndMem = &AccessToken->UserAndGroups[AccessToken->UserAndGroupCount]; 1121 VariableLength -= ((ULONG_PTR)EndMem - (ULONG_PTR)AccessToken->UserAndGroups); 1122 1123 Status = RtlCopySidAndAttributesArray(AccessToken->UserAndGroupCount, 1124 Token->UserAndGroups, 1125 VariableLength, 1126 AccessToken->UserAndGroups, 1127 EndMem, 1128 &EndMem, 1129 &VariableLength); 1130 if (!NT_SUCCESS(Status)) 1131 { 1132 DPRINT1("RtlCopySidAndAttributesArray(UserAndGroups) failed (Status 0x%lx)\n", Status); 1133 goto Quit; 1134 } 1135 } 1136 1137 /* Find the token primary group */ 1138 Status = SepFindPrimaryGroupAndDefaultOwner(AccessToken, 1139 Token->PrimaryGroup, 1140 NULL, 1141 &PrimaryGroupIndex, 1142 NULL); 1143 if (!NT_SUCCESS(Status)) 1144 { 1145 DPRINT1("SepFindPrimaryGroupAndDefaultOwner failed (Status 0x%lx)\n", Status); 1146 goto Quit; 1147 } 1148 1149 AccessToken->PrimaryGroup = AccessToken->UserAndGroups[PrimaryGroupIndex].Sid; 1150 AccessToken->DefaultOwnerIndex = Token->DefaultOwnerIndex; 1151 1152 /* Copy the restricted SIDs */ 1153 AccessToken->RestrictedSidCount = 0; 1154 AccessToken->RestrictedSids = NULL; 1155 if (Token->RestrictedSids && (Token->RestrictedSidCount > 0)) 1156 { 1157 AccessToken->RestrictedSidCount = Token->RestrictedSidCount; 1158 AccessToken->RestrictedSids = EndMem; 1159 EndMem = &AccessToken->RestrictedSids[AccessToken->RestrictedSidCount]; 1160 VariableLength -= ((ULONG_PTR)EndMem - (ULONG_PTR)AccessToken->RestrictedSids); 1161 1162 Status = RtlCopySidAndAttributesArray(AccessToken->RestrictedSidCount, 1163 Token->RestrictedSids, 1164 VariableLength, 1165 AccessToken->RestrictedSids, 1166 EndMem, 1167 &EndMem, 1168 &VariableLength); 1169 if (!NT_SUCCESS(Status)) 1170 { 1171 DPRINT1("RtlCopySidAndAttributesArray(RestrictedSids) failed (Status 0x%lx)\n", Status); 1172 goto Quit; 1173 } 1174 } 1175 1176 /* 1177 * Filter the token by removing the disabled privileges 1178 * and groups if the caller wants to duplicate an access 1179 * token as effective only. 1180 */ 1181 if (EffectiveOnly) 1182 { 1183 /* Begin querying the groups and search for disabled ones */ 1184 for (GroupsIndex = 0; GroupsIndex < AccessToken->UserAndGroupCount; GroupsIndex++) 1185 { 1186 /* 1187 * A group or user is considered disabled if its attributes is either 1188 * 0 or SE_GROUP_ENABLED is not included in the attributes flags list. 1189 * That is because a certain user and/or group can have several attributes 1190 * that bear no influence on whether a user/group is enabled or not 1191 * (SE_GROUP_ENABLED_BY_DEFAULT for example which is a mere indicator 1192 * that the group has just been enabled by default). A mandatory 1193 * group (that is, the group has SE_GROUP_MANDATORY attribute) 1194 * by standards it's always enabled and no one can disable it. 1195 */ 1196 if (AccessToken->UserAndGroups[GroupsIndex].Attributes == 0 || 1197 (AccessToken->UserAndGroups[GroupsIndex].Attributes & SE_GROUP_ENABLED) == 0) 1198 { 1199 /* 1200 * If this group is an administrators group 1201 * and the token belongs to such group, 1202 * we've to take away TOKEN_HAS_ADMIN_GROUP 1203 * for the fact that's not enabled and as 1204 * such the token no longer belongs to 1205 * this group. 1206 */ 1207 if (RtlEqualSid(SeAliasAdminsSid, 1208 &AccessToken->UserAndGroups[GroupsIndex].Sid)) 1209 { 1210 AccessToken->TokenFlags &= ~TOKEN_HAS_ADMIN_GROUP; 1211 } 1212 1213 /* 1214 * A group is not enabled, it's time to remove 1215 * from the token and update the groups index 1216 * accordingly and continue with the next group. 1217 */ 1218 SepRemoveUserGroupToken(AccessToken, GroupsIndex); 1219 GroupsIndex--; 1220 } 1221 } 1222 1223 /* Begin querying the privileges and search for disabled ones */ 1224 for (PrivilegesIndex = 0; PrivilegesIndex < AccessToken->PrivilegeCount; PrivilegesIndex++) 1225 { 1226 /* 1227 * A privilege is considered disabled if its attributes is either 1228 * 0 or SE_PRIVILEGE_ENABLED is not included in the attributes flags list. 1229 * That is because a certain privilege can have several attributes 1230 * that bear no influence on whether a privilege is enabled or not 1231 * (SE_PRIVILEGE_ENABLED_BY_DEFAULT for example which is a mere indicator 1232 * that the privilege has just been enabled by default). 1233 */ 1234 if (AccessToken->Privileges[PrivilegesIndex].Attributes == 0 || 1235 (AccessToken->Privileges[PrivilegesIndex].Attributes & SE_PRIVILEGE_ENABLED) == 0) 1236 { 1237 /* 1238 * A privilege is not enabled, therefor it's time 1239 * to strip it from the token and continue with the next 1240 * privilege. Of course we must also want to update the 1241 * privileges index accordingly. 1242 */ 1243 SepRemovePrivilegeToken(AccessToken, PrivilegesIndex); 1244 PrivilegesIndex--; 1245 } 1246 } 1247 } 1248 1249 // 1250 // NOTE: So far our dynamic area only contains 1251 // the default dacl, so this makes the following 1252 // code pretty simple. The day where it stores 1253 // other data, the code will require adaptations. 1254 // 1255 1256 /* Now allocate the TOKEN's dynamic information area and set the data */ 1257 AccessToken->DynamicAvailable = 0; // Unused memory in the dynamic area. 1258 AccessToken->DynamicPart = NULL; 1259 if (Token->DynamicPart && Token->DefaultDacl) 1260 { 1261 AccessToken->DynamicPart = ExAllocatePoolWithTag(PagedPool, 1262 Token->DefaultDacl->AclSize, 1263 TAG_TOKEN_DYNAMIC); 1264 if (AccessToken->DynamicPart == NULL) 1265 { 1266 Status = STATUS_INSUFFICIENT_RESOURCES; 1267 goto Quit; 1268 } 1269 EndMem = (PVOID)AccessToken->DynamicPart; 1270 1271 AccessToken->DefaultDacl = EndMem; 1272 1273 RtlCopyMemory(AccessToken->DefaultDacl, 1274 Token->DefaultDacl, 1275 Token->DefaultDacl->AclSize); 1276 } 1277 1278 /* Unlock the source token */ 1279 SepReleaseTokenLock(Token); 1280 1281 /* Return the token */ 1282 *NewAccessToken = AccessToken; 1283 Status = STATUS_SUCCESS; 1284 1285 Quit: 1286 if (!NT_SUCCESS(Status)) 1287 { 1288 /* Unlock the source token */ 1289 SepReleaseTokenLock(Token); 1290 1291 /* Dereference the token, the delete procedure will clean it up */ 1292 ObDereferenceObject(AccessToken); 1293 } 1294 1295 return Status; 1296 } 1297 1298 /** 1299 * @brief 1300 * Subtracts a token in exchange of duplicating a new one. 1301 * 1302 * @param[in] ParentToken 1303 * The parent access token for duplication. 1304 * 1305 * @param[out] Token 1306 * The new duplicated token. 1307 * 1308 * @param[in] InUse 1309 * Set this to TRUE if the token is about to be used immediately after the call execution 1310 * of this function, FALSE otherwise. 1311 * 1312 * @param[in] SessionId 1313 * Session ID for the token to be assigned. 1314 * 1315 * @return 1316 * Returns STATUS_SUCCESS if token subtracting and duplication have completed successfully. 1317 * A failure NTSTATUS code is returned otherwise. 1318 */ 1319 NTSTATUS 1320 NTAPI 1321 SeSubProcessToken( 1322 _In_ PTOKEN ParentToken, 1323 _Out_ PTOKEN *Token, 1324 _In_ BOOLEAN InUse, 1325 _In_ ULONG SessionId) 1326 { 1327 PTOKEN NewToken; 1328 OBJECT_ATTRIBUTES ObjectAttributes; 1329 NTSTATUS Status; 1330 1331 /* Initialize the attributes and duplicate it */ 1332 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL); 1333 Status = SepDuplicateToken(ParentToken, 1334 &ObjectAttributes, 1335 FALSE, 1336 TokenPrimary, 1337 ParentToken->ImpersonationLevel, 1338 KernelMode, 1339 &NewToken); 1340 if (NT_SUCCESS(Status)) 1341 { 1342 /* Insert it */ 1343 Status = ObInsertObject(NewToken, 1344 NULL, 1345 0, 1346 0, 1347 NULL, 1348 NULL); 1349 if (NT_SUCCESS(Status)) 1350 { 1351 /* Set the session ID */ 1352 NewToken->SessionId = SessionId; 1353 NewToken->TokenInUse = InUse; 1354 1355 /* Return the token */ 1356 *Token = NewToken; 1357 } 1358 } 1359 1360 /* Return status */ 1361 return Status; 1362 } 1363 1364 /** 1365 * @brief 1366 * Checks if the token is a child of the other token 1367 * of the current process that the calling thread is invoking this function. 1368 * 1369 * @param[in] Token 1370 * An access token to determine if it's a child or not. 1371 * 1372 * @param[out] IsChild 1373 * The returned boolean result. 1374 * 1375 * @return 1376 * Returns STATUS_SUCCESS when the function finishes its operation. STATUS_UNSUCCESSFUL is 1377 * returned if primary token of the current calling process couldn't be referenced otherwise. 1378 */ 1379 NTSTATUS 1380 NTAPI 1381 SeIsTokenChild( 1382 _In_ PTOKEN Token, 1383 _Out_ PBOOLEAN IsChild) 1384 { 1385 PTOKEN ProcessToken; 1386 LUID ProcessTokenId, CallerParentId; 1387 1388 /* Assume failure */ 1389 *IsChild = FALSE; 1390 1391 /* Reference the process token */ 1392 ProcessToken = PsReferencePrimaryToken(PsGetCurrentProcess()); 1393 if (!ProcessToken) 1394 return STATUS_UNSUCCESSFUL; 1395 1396 /* Get its token ID */ 1397 ProcessTokenId = ProcessToken->TokenId; 1398 1399 /* Dereference the token */ 1400 ObFastDereferenceObject(&PsGetCurrentProcess()->Token, ProcessToken); 1401 1402 /* Get our parent token ID */ 1403 CallerParentId = Token->ParentTokenId; 1404 1405 /* Compare the token IDs */ 1406 if (RtlEqualLuid(&CallerParentId, &ProcessTokenId)) 1407 *IsChild = TRUE; 1408 1409 /* Return success */ 1410 return STATUS_SUCCESS; 1411 } 1412 1413 /** 1414 * @brief 1415 * Checks if the token is a sibling of the other token of 1416 * the current process that the calling thread is invoking this function. 1417 * 1418 * @param[in] Token 1419 * An access token to determine if it's a sibling or not. 1420 * 1421 * @param[out] IsSibling 1422 * The returned boolean result. 1423 * 1424 * @return 1425 * Returns STATUS_SUCCESS when the function finishes its operation. STATUS_UNSUCCESSFUL is 1426 * returned if primary token of the current calling process couldn't be referenced otherwise. 1427 */ 1428 NTSTATUS 1429 NTAPI 1430 SeIsTokenSibling( 1431 _In_ PTOKEN Token, 1432 _Out_ PBOOLEAN IsSibling) 1433 { 1434 PTOKEN ProcessToken; 1435 LUID ProcessParentId, ProcessAuthId; 1436 LUID CallerParentId, CallerAuthId; 1437 1438 /* Assume failure */ 1439 *IsSibling = FALSE; 1440 1441 /* Reference the process token */ 1442 ProcessToken = PsReferencePrimaryToken(PsGetCurrentProcess()); 1443 if (!ProcessToken) 1444 return STATUS_UNSUCCESSFUL; 1445 1446 /* Get its parent and authentication IDs */ 1447 ProcessParentId = ProcessToken->ParentTokenId; 1448 ProcessAuthId = ProcessToken->AuthenticationId; 1449 1450 /* Dereference the token */ 1451 ObFastDereferenceObject(&PsGetCurrentProcess()->Token, ProcessToken); 1452 1453 /* Get our parent and authentication IDs */ 1454 CallerParentId = Token->ParentTokenId; 1455 CallerAuthId = Token->AuthenticationId; 1456 1457 /* Compare the token IDs */ 1458 if (RtlEqualLuid(&CallerParentId, &ProcessParentId) && 1459 RtlEqualLuid(&CallerAuthId, &ProcessAuthId)) 1460 { 1461 *IsSibling = TRUE; 1462 } 1463 1464 /* Return success */ 1465 return STATUS_SUCCESS; 1466 } 1467 1468 /** 1469 * @brief 1470 * Copies an existing access token (technically duplicating a new one). 1471 * 1472 * @param[in] Token 1473 * Token to copy. 1474 * 1475 * @param[in] Level 1476 * Impersonation security level to assign to the newly copied token. 1477 * 1478 * @param[in] PreviousMode 1479 * Processor request level mode. 1480 * 1481 * @param[out] NewToken 1482 * The newly copied token. 1483 * 1484 * @return 1485 * Returns STATUS_SUCCESS when token copying has finished successfully. A failure 1486 * NTSTATUS code is returned otherwise. 1487 */ 1488 NTSTATUS 1489 NTAPI 1490 SeCopyClientToken( 1491 _In_ PACCESS_TOKEN Token, 1492 _In_ SECURITY_IMPERSONATION_LEVEL Level, 1493 _In_ KPROCESSOR_MODE PreviousMode, 1494 _Out_ PACCESS_TOKEN* NewToken) 1495 { 1496 NTSTATUS Status; 1497 OBJECT_ATTRIBUTES ObjectAttributes; 1498 1499 PAGED_CODE(); 1500 1501 InitializeObjectAttributes(&ObjectAttributes, 1502 NULL, 1503 0, 1504 NULL, 1505 NULL); 1506 1507 Status = SepDuplicateToken(Token, 1508 &ObjectAttributes, 1509 FALSE, 1510 TokenImpersonation, 1511 Level, 1512 PreviousMode, 1513 (PTOKEN*)NewToken); 1514 1515 return Status; 1516 } 1517 1518 /** 1519 * @brief 1520 * Internal function that deals with access token object destruction and deletion. 1521 * The function is used solely by the object manager mechanism that handles the life 1522 * management of a token object. 1523 * 1524 * @param[in] ObjectBody 1525 * The object body that represents an access token object. 1526 * 1527 * @return 1528 * Nothing. 1529 */ 1530 VOID 1531 NTAPI 1532 SepDeleteToken( 1533 _In_ PVOID ObjectBody) 1534 { 1535 NTSTATUS Status; 1536 PTOKEN AccessToken = (PTOKEN)ObjectBody; 1537 1538 DPRINT("SepDeleteToken()\n"); 1539 1540 /* Remove the referenced logon session from token */ 1541 if (AccessToken->LogonSession) 1542 { 1543 Status = SepRmRemoveLogonSessionFromToken(AccessToken); 1544 if (!NT_SUCCESS(Status)) 1545 { 1546 /* Something seriously went wrong */ 1547 DPRINT1("SepDeleteToken(): Failed to remove the logon session from token (Status: 0x%lx)\n", Status); 1548 return; 1549 } 1550 } 1551 1552 /* Dereference the logon session */ 1553 if ((AccessToken->TokenFlags & TOKEN_SESSION_NOT_REFERENCED) == 0) 1554 SepRmDereferenceLogonSession(&AccessToken->AuthenticationId); 1555 1556 /* Delete the token lock */ 1557 if (AccessToken->TokenLock) 1558 SepDeleteTokenLock(AccessToken); 1559 1560 /* Delete the dynamic information area */ 1561 if (AccessToken->DynamicPart) 1562 ExFreePoolWithTag(AccessToken->DynamicPart, TAG_TOKEN_DYNAMIC); 1563 } 1564 1565 /** 1566 * @brief 1567 * Internal function that initializes critical kernel data for access 1568 * token implementation in SRM. 1569 * 1570 * @return 1571 * Nothing. 1572 */ 1573 CODE_SEG("INIT") 1574 VOID 1575 NTAPI 1576 SepInitializeTokenImplementation(VOID) 1577 { 1578 UNICODE_STRING Name; 1579 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; 1580 1581 DPRINT("Creating Token Object Type\n"); 1582 1583 /* Initialize the Token type */ 1584 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); 1585 RtlInitUnicodeString(&Name, L"Token"); 1586 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); 1587 ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK; 1588 ObjectTypeInitializer.SecurityRequired = TRUE; 1589 ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(TOKEN); 1590 ObjectTypeInitializer.GenericMapping = SepTokenMapping; 1591 ObjectTypeInitializer.PoolType = PagedPool; 1592 ObjectTypeInitializer.ValidAccessMask = TOKEN_ALL_ACCESS; 1593 ObjectTypeInitializer.UseDefaultObject = TRUE; 1594 ObjectTypeInitializer.DeleteProcedure = SepDeleteToken; 1595 ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &SeTokenObjectType); 1596 } 1597 1598 /** 1599 * @brief 1600 * Assigns a primary access token to a given process. 1601 * 1602 * @param[in] Process 1603 * Process where the token is about to be assigned. 1604 * 1605 * @param[in] Token 1606 * The token to be assigned. 1607 * 1608 * @return 1609 * Nothing. 1610 */ 1611 VOID 1612 NTAPI 1613 SeAssignPrimaryToken( 1614 _In_ PEPROCESS Process, 1615 _In_ PTOKEN Token) 1616 { 1617 PAGED_CODE(); 1618 1619 /* Sanity checks */ 1620 ASSERT(Token->TokenType == TokenPrimary); 1621 ASSERT(!Token->TokenInUse); 1622 1623 /* Clean any previous token */ 1624 if (Process->Token.Object) SeDeassignPrimaryToken(Process); 1625 1626 /* Set the new token */ 1627 ObReferenceObject(Token); 1628 Token->TokenInUse = TRUE; 1629 ObInitializeFastReference(&Process->Token, Token); 1630 } 1631 1632 /** 1633 * @brief 1634 * Internal function responsible for access token object creation in the kernel. 1635 * A fully created token objected is inserted into the token handle, thus the handle 1636 * becoming a valid handle to an access token object and ready for use. 1637 * 1638 * @param[out] TokenHandle 1639 * Valid token handle that's ready for use after token creation and object insertion. 1640 * 1641 * @param[in] PreviousMode 1642 * Processor request level mode. 1643 * 1644 * @param[in] DesiredAccess 1645 * Desired access right for the token object to be granted. This kind of access right 1646 * impacts how the token can be used and who. 1647 * 1648 * @param[in] ObjectAttributes 1649 * Object attributes for the token to be created. 1650 * 1651 * @param[in] TokenType 1652 * Type of token to assign upon creation. 1653 * 1654 * @param[in] ImpersonationLevel 1655 * Security impersonation level of token to assign upon creation. 1656 * 1657 * @param[in] AuthenticationId 1658 * Authentication ID that represents the authentication information of the token. 1659 * 1660 * @param[in] ExpirationTime 1661 * Expiration time of the token to assign. A value of -1 means that the token never 1662 * expires and its life depends upon the amount of references this token object has. 1663 * 1664 * @param[in] User 1665 * User entry to assign to the token. 1666 * 1667 * @param[in] GroupCount 1668 * The total number of groups count for the token. 1669 * 1670 * @param[in] Groups 1671 * The group entries for the token. 1672 * 1673 * @param[in] GroupsLength 1674 * The length size of the groups array, pointed by the Groups parameter. 1675 * 1676 * @param[in] PrivilegeCount 1677 * The total number of priivleges that the newly created token has. 1678 * 1679 * @param[in] Privileges 1680 * The privileges for the token. 1681 * 1682 * @param[in] Owner 1683 * The main user (or also owner) that represents the token that we create. 1684 * 1685 * @param[in] PrimaryGroup 1686 * The main group that represents the token that we create. 1687 * 1688 * @param[in] DefaultDacl 1689 * A discretionary access control list for the token. 1690 * 1691 * @param[in] TokenSource 1692 * Source (or the origin) of the access token that creates it. 1693 * 1694 * @param[in] SystemToken 1695 * If set to TRUE, the newly created token is a system token and only in charge 1696 * by the internal system. The function directly returns a pointer to the 1697 * created token object for system kernel use. Otherwise if set to FALSE, the 1698 * function inserts the object to a handle making it a regular access token. 1699 * 1700 * @return 1701 * Returns STATUS_SUCCESS if token creation has completed successfully. 1702 * STATUS_INSUFFICIENT_RESOURCES is returned if the dynamic area of memory of the 1703 * token hasn't been allocated because of lack of memory resources. A failure 1704 * NTSTATUS code is returned otherwise. 1705 */ 1706 NTSTATUS 1707 NTAPI 1708 SepCreateToken( 1709 _Out_ PHANDLE TokenHandle, 1710 _In_ KPROCESSOR_MODE PreviousMode, 1711 _In_ ACCESS_MASK DesiredAccess, 1712 _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, 1713 _In_ TOKEN_TYPE TokenType, 1714 _In_ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, 1715 _In_ PLUID AuthenticationId, 1716 _In_ PLARGE_INTEGER ExpirationTime, 1717 _In_ PSID_AND_ATTRIBUTES User, 1718 _In_ ULONG GroupCount, 1719 _In_ PSID_AND_ATTRIBUTES Groups, 1720 _In_ ULONG GroupsLength, 1721 _In_ ULONG PrivilegeCount, 1722 _In_ PLUID_AND_ATTRIBUTES Privileges, 1723 _In_opt_ PSID Owner, 1724 _In_ PSID PrimaryGroup, 1725 _In_opt_ PACL DefaultDacl, 1726 _In_ PTOKEN_SOURCE TokenSource, 1727 _In_ BOOLEAN SystemToken) 1728 { 1729 NTSTATUS Status; 1730 PTOKEN AccessToken; 1731 ULONG TokenFlags = 0; 1732 ULONG PrimaryGroupIndex, DefaultOwnerIndex; 1733 LUID TokenId; 1734 LUID ModifiedId; 1735 PVOID EndMem; 1736 ULONG PrivilegesLength; 1737 ULONG UserGroupsLength; 1738 ULONG VariableLength; 1739 ULONG TotalSize; 1740 ULONG i; 1741 1742 PAGED_CODE(); 1743 1744 /* Loop all groups */ 1745 for (i = 0; i < GroupCount; i++) 1746 { 1747 /* Check for mandatory groups */ 1748 if (Groups[i].Attributes & SE_GROUP_MANDATORY) 1749 { 1750 /* Force them to be enabled */ 1751 Groups[i].Attributes |= (SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT); 1752 } 1753 1754 /* Check of the group is an admin group */ 1755 if (RtlEqualSid(SeAliasAdminsSid, Groups[i].Sid)) 1756 { 1757 /* Remember this so we can optimize queries later */ 1758 TokenFlags |= TOKEN_HAS_ADMIN_GROUP; 1759 } 1760 } 1761 1762 /* Allocate unique IDs for the token */ 1763 ExAllocateLocallyUniqueId(&TokenId); 1764 ExAllocateLocallyUniqueId(&ModifiedId); 1765 1766 /* Compute how much size we need to allocate for the token */ 1767 1768 /* Privileges size */ 1769 PrivilegesLength = PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES); 1770 PrivilegesLength = ALIGN_UP_BY(PrivilegesLength, sizeof(PVOID)); 1771 1772 /* User and groups size */ 1773 UserGroupsLength = (1 + GroupCount) * sizeof(SID_AND_ATTRIBUTES); 1774 UserGroupsLength += RtlLengthSid(User->Sid); 1775 for (i = 0; i < GroupCount; i++) 1776 { 1777 UserGroupsLength += RtlLengthSid(Groups[i].Sid); 1778 } 1779 UserGroupsLength = ALIGN_UP_BY(UserGroupsLength, sizeof(PVOID)); 1780 1781 /* Add the additional groups array length */ 1782 UserGroupsLength += ALIGN_UP_BY(GroupsLength, sizeof(PVOID)); 1783 1784 VariableLength = PrivilegesLength + UserGroupsLength; 1785 TotalSize = FIELD_OFFSET(TOKEN, VariablePart) + VariableLength; 1786 1787 Status = ObCreateObject(PreviousMode, 1788 SeTokenObjectType, 1789 ObjectAttributes, 1790 PreviousMode, 1791 NULL, 1792 TotalSize, 1793 0, 1794 0, 1795 (PVOID*)&AccessToken); 1796 if (!NT_SUCCESS(Status)) 1797 { 1798 DPRINT1("ObCreateObject() failed (Status 0x%lx)\n", Status); 1799 return Status; 1800 } 1801 1802 /* Zero out the buffer and initialize the token */ 1803 RtlZeroMemory(AccessToken, TotalSize); 1804 1805 RtlCopyLuid(&AccessToken->TokenId, &TokenId); 1806 1807 AccessToken->TokenType = TokenType; 1808 AccessToken->ImpersonationLevel = ImpersonationLevel; 1809 1810 /* Initialise the lock for the access token */ 1811 Status = SepCreateTokenLock(AccessToken); 1812 if (!NT_SUCCESS(Status)) 1813 goto Quit; 1814 1815 RtlCopyLuid(&AccessToken->TokenSource.SourceIdentifier, 1816 &TokenSource->SourceIdentifier); 1817 RtlCopyMemory(AccessToken->TokenSource.SourceName, 1818 TokenSource->SourceName, 1819 sizeof(TokenSource->SourceName)); 1820 1821 AccessToken->ExpirationTime = *ExpirationTime; 1822 RtlCopyLuid(&AccessToken->ModifiedId, &ModifiedId); 1823 1824 AccessToken->TokenFlags = TokenFlags & ~TOKEN_SESSION_NOT_REFERENCED; 1825 1826 /* Copy and reference the logon session */ 1827 RtlCopyLuid(&AccessToken->AuthenticationId, AuthenticationId); 1828 Status = SepRmReferenceLogonSession(&AccessToken->AuthenticationId); 1829 if (!NT_SUCCESS(Status)) 1830 { 1831 /* No logon session could be found, bail out */ 1832 DPRINT1("SepRmReferenceLogonSession() failed (Status 0x%lx)\n", Status); 1833 /* Set the flag for proper cleanup by the delete procedure */ 1834 AccessToken->TokenFlags |= TOKEN_SESSION_NOT_REFERENCED; 1835 goto Quit; 1836 } 1837 1838 /* Insert the referenced logon session into the token */ 1839 Status = SepRmInsertLogonSessionIntoToken(AccessToken); 1840 if (!NT_SUCCESS(Status)) 1841 { 1842 /* Failed to insert the logon session into the token, bail out */ 1843 DPRINT1("SepRmInsertLogonSessionIntoToken() failed (Status 0x%lx)\n", Status); 1844 goto Quit; 1845 } 1846 1847 /* Assign the data that reside in the TOKEN's variable information area */ 1848 AccessToken->VariableLength = VariableLength; 1849 EndMem = (PVOID)&AccessToken->VariablePart; 1850 1851 /* Copy the privileges */ 1852 AccessToken->PrivilegeCount = PrivilegeCount; 1853 AccessToken->Privileges = NULL; 1854 if (PrivilegeCount > 0) 1855 { 1856 AccessToken->Privileges = EndMem; 1857 EndMem = (PVOID)((ULONG_PTR)EndMem + PrivilegesLength); 1858 VariableLength -= PrivilegesLength; 1859 1860 if (PreviousMode != KernelMode) 1861 { 1862 _SEH2_TRY 1863 { 1864 RtlCopyMemory(AccessToken->Privileges, 1865 Privileges, 1866 PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES)); 1867 } 1868 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1869 { 1870 Status = _SEH2_GetExceptionCode(); 1871 } 1872 _SEH2_END; 1873 } 1874 else 1875 { 1876 RtlCopyMemory(AccessToken->Privileges, 1877 Privileges, 1878 PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES)); 1879 } 1880 1881 if (!NT_SUCCESS(Status)) 1882 goto Quit; 1883 } 1884 1885 /* Update the privilege flags */ 1886 SepUpdatePrivilegeFlagsToken(AccessToken); 1887 1888 /* Copy the user and groups */ 1889 AccessToken->UserAndGroupCount = 1 + GroupCount; 1890 AccessToken->UserAndGroups = EndMem; 1891 EndMem = &AccessToken->UserAndGroups[AccessToken->UserAndGroupCount]; 1892 VariableLength -= ((ULONG_PTR)EndMem - (ULONG_PTR)AccessToken->UserAndGroups); 1893 1894 Status = RtlCopySidAndAttributesArray(1, 1895 User, 1896 VariableLength, 1897 &AccessToken->UserAndGroups[0], 1898 EndMem, 1899 &EndMem, 1900 &VariableLength); 1901 if (!NT_SUCCESS(Status)) 1902 goto Quit; 1903 1904 Status = RtlCopySidAndAttributesArray(GroupCount, 1905 Groups, 1906 VariableLength, 1907 &AccessToken->UserAndGroups[1], 1908 EndMem, 1909 &EndMem, 1910 &VariableLength); 1911 if (!NT_SUCCESS(Status)) 1912 goto Quit; 1913 1914 /* Find the token primary group and default owner */ 1915 Status = SepFindPrimaryGroupAndDefaultOwner(AccessToken, 1916 PrimaryGroup, 1917 Owner, 1918 &PrimaryGroupIndex, 1919 &DefaultOwnerIndex); 1920 if (!NT_SUCCESS(Status)) 1921 { 1922 DPRINT1("SepFindPrimaryGroupAndDefaultOwner failed (Status 0x%lx)\n", Status); 1923 goto Quit; 1924 } 1925 1926 AccessToken->PrimaryGroup = AccessToken->UserAndGroups[PrimaryGroupIndex].Sid; 1927 AccessToken->DefaultOwnerIndex = DefaultOwnerIndex; 1928 1929 /* Now allocate the TOKEN's dynamic information area and set the data */ 1930 AccessToken->DynamicAvailable = 0; // Unused memory in the dynamic area. 1931 AccessToken->DynamicPart = NULL; 1932 if (DefaultDacl != NULL) 1933 { 1934 AccessToken->DynamicPart = ExAllocatePoolWithTag(PagedPool, 1935 DefaultDacl->AclSize, 1936 TAG_TOKEN_DYNAMIC); 1937 if (AccessToken->DynamicPart == NULL) 1938 { 1939 Status = STATUS_INSUFFICIENT_RESOURCES; 1940 goto Quit; 1941 } 1942 EndMem = (PVOID)AccessToken->DynamicPart; 1943 1944 AccessToken->DefaultDacl = EndMem; 1945 1946 RtlCopyMemory(AccessToken->DefaultDacl, 1947 DefaultDacl, 1948 DefaultDacl->AclSize); 1949 } 1950 1951 /* Insert the token only if it's not the system token, otherwise return it directly */ 1952 if (!SystemToken) 1953 { 1954 Status = ObInsertObject(AccessToken, 1955 NULL, 1956 DesiredAccess, 1957 0, 1958 NULL, 1959 TokenHandle); 1960 if (!NT_SUCCESS(Status)) 1961 { 1962 DPRINT1("ObInsertObject() failed (Status 0x%lx)\n", Status); 1963 } 1964 } 1965 else 1966 { 1967 /* Return pointer instead of handle */ 1968 *TokenHandle = (HANDLE)AccessToken; 1969 } 1970 1971 Quit: 1972 if (!NT_SUCCESS(Status)) 1973 { 1974 /* Dereference the token, the delete procedure will clean it up */ 1975 ObDereferenceObject(AccessToken); 1976 } 1977 1978 return Status; 1979 } 1980 1981 /** 1982 * @brief 1983 * Private helper function responsible for creating a restricted access 1984 * token, that is, a filtered token from privileges and groups and with 1985 * restricted SIDs added into the token on demand by the caller. 1986 * 1987 * @param[in] Token 1988 * An existing and valid access token. 1989 * 1990 * @param[in] PrivilegesToBeDeleted 1991 * A list of privileges to be deleted within the token that's going 1992 * to be filtered. This parameter is ignored if the caller wants to disable 1993 * all the privileges by specifying DISABLE_MAX_PRIVILEGE in the flags 1994 * parameter. 1995 * 1996 * @param[in] SidsToBeDisabled 1997 * A list of group SIDs to be disabled within the token. This parameter 1998 * can be NULL. 1999 * 2000 * @param[in] RestrictedSidsIntoToken 2001 * A list of restricted SIDs to be added into the token. This parameter 2002 * can be NULL. 2003 * 2004 * @param[in] PrivilegesCount 2005 * The privilege count of the privileges list. 2006 * 2007 * @param[in] RegularGroupsSidCount 2008 * The SIDs count of the group SIDs list. 2009 * 2010 * @param[in] RestrictedSidsCount 2011 * The restricted SIDs count of restricted SIDs list. 2012 * 2013 * @param[in] PrivilegeFlags 2014 * Influences how the privileges should be filtered in an access 2015 * token. See NtFilterToken syscall for more information. 2016 * 2017 * @param[in] PreviousMode 2018 * Processor level access mode. 2019 * 2020 * @param[out] FilteredToken 2021 * The filtered token, returned to the caller. 2022 * 2023 * @return 2024 * Returns STATUS_SUCCESS if token token filtering has completed successfully. 2025 * STATUS_INVALID_PARAMETER is returned if one or more of the parameters 2026 * do not meet the conditions imposed by the function. A failure NTSTATUS 2027 * code is returned otherwise. 2028 * 2029 * @remarks 2030 * The final outcome of privileges and/or SIDs filtering is not always 2031 * deterministic. That is, any privileges or SIDs that aren't present 2032 * in the access token are ignored and the function continues with the 2033 * next privilege or SID to find for filtering. For a fully deterministic 2034 * outcome the caller is responsible for querying the information details 2035 * of privileges and SIDs present in the token and then afterwards use 2036 * such obtained information to do any kind of filtering to the token. 2037 */ 2038 static 2039 NTSTATUS 2040 SepPerformTokenFiltering( 2041 _In_ PTOKEN Token, 2042 _In_opt_ PLUID_AND_ATTRIBUTES PrivilegesToBeDeleted, 2043 _In_opt_ PSID_AND_ATTRIBUTES SidsToBeDisabled, 2044 _In_opt_ PSID_AND_ATTRIBUTES RestrictedSidsIntoToken, 2045 _When_(PrivilegesToBeDeleted != NULL, _In_) ULONG PrivilegesCount, 2046 _When_(SidsToBeDisabled != NULL, _In_) ULONG RegularGroupsSidCount, 2047 _When_(RestrictedSidsIntoToken != NULL, _In_) ULONG RestrictedSidsCount, 2048 _In_ ULONG PrivilegeFlags, 2049 _In_ KPROCESSOR_MODE PreviousMode, 2050 _Out_ PTOKEN *FilteredToken) 2051 { 2052 PTOKEN AccessToken; 2053 NTSTATUS Status; 2054 PVOID EndMem; 2055 ULONG RestrictedSidsLength; 2056 ULONG PrivilegesLength; 2057 ULONG PrimaryGroupIndex; 2058 ULONG RestrictedSidsInList; 2059 ULONG RestrictedSidsInToken; 2060 ULONG VariableLength, TotalSize; 2061 ULONG PrivsInToken, PrivsInList; 2062 ULONG GroupsInToken, GroupsInList; 2063 BOOLEAN WantPrivilegesDisabled; 2064 BOOLEAN FoundPrivilege; 2065 BOOLEAN FoundGroup; 2066 PAGED_CODE(); 2067 2068 /* Ensure that the token we get is not garbage */ 2069 ASSERT(Token); 2070 2071 /* Assume the caller doesn't want privileges disabled */ 2072 WantPrivilegesDisabled = FALSE; 2073 2074 /* Assume we haven't found anything */ 2075 FoundPrivilege = FALSE; 2076 FoundGroup = FALSE; 2077 2078 /* 2079 * Take the size that we need for filtered token 2080 * allocation based upon the existing access token 2081 * we've been given. 2082 */ 2083 VariableLength = Token->VariableLength; 2084 2085 if (RestrictedSidsIntoToken != NULL) 2086 { 2087 /* 2088 * If the caller provided a list of restricted SIDs 2089 * to be added onto the filtered access token then 2090 * we must compute the size which is the total space 2091 * of the current token and the length of the restricted 2092 * SIDs for the filtered token. 2093 */ 2094 RestrictedSidsLength = RestrictedSidsCount * sizeof(SID_AND_ATTRIBUTES); 2095 RestrictedSidsLength += RtlLengthSidAndAttributes(RestrictedSidsCount, RestrictedSidsIntoToken); 2096 RestrictedSidsLength = ALIGN_UP_BY(RestrictedSidsLength, sizeof(PVOID)); 2097 2098 /* 2099 * The variable length of the token is not just 2100 * the actual space length of the existing token 2101 * but also the sum of the restricted SIDs length. 2102 */ 2103 VariableLength += RestrictedSidsLength; 2104 TotalSize = FIELD_OFFSET(TOKEN, VariablePart) + VariableLength + RestrictedSidsLength; 2105 } 2106 else 2107 { 2108 /* Otherwise the size is of the actual current token */ 2109 TotalSize = FIELD_OFFSET(TOKEN, VariablePart) + VariableLength; 2110 } 2111 2112 /* Set up a filtered token object */ 2113 Status = ObCreateObject(PreviousMode, 2114 SeTokenObjectType, 2115 NULL, 2116 PreviousMode, 2117 NULL, 2118 TotalSize, 2119 0, 2120 0, 2121 (PVOID*)&AccessToken); 2122 if (!NT_SUCCESS(Status)) 2123 { 2124 DPRINT1("SepPerformTokenFiltering(): Failed to create the filtered token object (Status 0x%lx)\n", Status); 2125 return Status; 2126 } 2127 2128 /* Initialize the token and begin filling stuff to it */ 2129 RtlZeroMemory(AccessToken, TotalSize); 2130 2131 /* Set up a lock for the new token */ 2132 Status = SepCreateTokenLock(AccessToken); 2133 if (!NT_SUCCESS(Status)) 2134 { 2135 ObDereferenceObject(AccessToken); 2136 return Status; 2137 } 2138 2139 /* Allocate new IDs for the token */ 2140 ExAllocateLocallyUniqueId(&AccessToken->TokenId); 2141 ExAllocateLocallyUniqueId(&AccessToken->ModifiedId); 2142 2143 /* Copy the type and impersonation level from the token */ 2144 AccessToken->TokenType = Token->TokenType; 2145 AccessToken->ImpersonationLevel = Token->ImpersonationLevel; 2146 2147 /* Copy the immutable fields */ 2148 RtlCopyLuid(&AccessToken->TokenSource.SourceIdentifier, 2149 &Token->TokenSource.SourceIdentifier); 2150 RtlCopyMemory(AccessToken->TokenSource.SourceName, 2151 Token->TokenSource.SourceName, 2152 sizeof(Token->TokenSource.SourceName)); 2153 2154 RtlCopyLuid(&AccessToken->AuthenticationId, &Token->AuthenticationId); 2155 RtlCopyLuid(&AccessToken->ParentTokenId, &Token->TokenId); 2156 RtlCopyLuid(&AccessToken->OriginatingLogonSession, 2157 &Token->OriginatingLogonSession); 2158 2159 AccessToken->ExpirationTime = Token->ExpirationTime; 2160 2161 /* Copy the mutable fields */ 2162 AccessToken->SessionId = Token->SessionId; 2163 AccessToken->TokenFlags = Token->TokenFlags & ~TOKEN_SESSION_NOT_REFERENCED; 2164 2165 /* Reference the logon session */ 2166 Status = SepRmReferenceLogonSession(&AccessToken->AuthenticationId); 2167 if (!NT_SUCCESS(Status)) 2168 { 2169 /* We failed, bail out*/ 2170 DPRINT1("SepPerformTokenFiltering(): Failed to reference the logon session (Status 0x%lx)\n", Status); 2171 AccessToken->TokenFlags |= TOKEN_SESSION_NOT_REFERENCED; 2172 goto Quit; 2173 } 2174 2175 /* Insert the referenced logon session into the token */ 2176 Status = SepRmInsertLogonSessionIntoToken(AccessToken); 2177 if (!NT_SUCCESS(Status)) 2178 { 2179 /* Failed to insert the logon session into the token, bail out */ 2180 DPRINT1("SepPerformTokenFiltering(): Failed to insert the logon session into token (Status 0x%lx)\n", Status); 2181 goto Quit; 2182 } 2183 2184 /* Assign the data that reside in the token's variable information area */ 2185 AccessToken->VariableLength = VariableLength; 2186 EndMem = (PVOID)&AccessToken->VariablePart; 2187 2188 /* Copy the privileges from the existing token */ 2189 AccessToken->PrivilegeCount = 0; 2190 AccessToken->Privileges = NULL; 2191 if (Token->Privileges && (Token->PrivilegeCount > 0)) 2192 { 2193 PrivilegesLength = Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES); 2194 PrivilegesLength = ALIGN_UP_BY(PrivilegesLength, sizeof(PVOID)); 2195 2196 /* 2197 * Ensure that the token can actually hold all 2198 * the privileges from the existing token. 2199 * Otherwise something's seriously wrong and 2200 * we've to guard ourselves. 2201 */ 2202 ASSERT(VariableLength >= PrivilegesLength); 2203 2204 AccessToken->PrivilegeCount = Token->PrivilegeCount; 2205 AccessToken->Privileges = EndMem; 2206 EndMem = (PVOID)((ULONG_PTR)EndMem + PrivilegesLength); 2207 VariableLength -= PrivilegesLength; 2208 2209 if (PreviousMode != KernelMode) 2210 { 2211 _SEH2_TRY 2212 { 2213 RtlCopyMemory(AccessToken->Privileges, 2214 Token->Privileges, 2215 AccessToken->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES)); 2216 } 2217 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2218 { 2219 Status = _SEH2_GetExceptionCode(); 2220 _SEH2_YIELD(goto Quit); 2221 } 2222 _SEH2_END; 2223 } 2224 else 2225 { 2226 RtlCopyMemory(AccessToken->Privileges, 2227 Token->Privileges, 2228 AccessToken->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES)); 2229 } 2230 } 2231 2232 /* Copy the user and groups */ 2233 AccessToken->UserAndGroupCount = 0; 2234 AccessToken->UserAndGroups = NULL; 2235 if (Token->UserAndGroups && (Token->UserAndGroupCount > 0)) 2236 { 2237 AccessToken->UserAndGroupCount = Token->UserAndGroupCount; 2238 AccessToken->UserAndGroups = EndMem; 2239 EndMem = &AccessToken->UserAndGroups[AccessToken->UserAndGroupCount]; 2240 VariableLength -= ((ULONG_PTR)EndMem - (ULONG_PTR)AccessToken->UserAndGroups); 2241 2242 if (PreviousMode != KernelMode) 2243 { 2244 _SEH2_TRY 2245 { 2246 Status = RtlCopySidAndAttributesArray(AccessToken->UserAndGroupCount, 2247 Token->UserAndGroups, 2248 VariableLength, 2249 AccessToken->UserAndGroups, 2250 EndMem, 2251 &EndMem, 2252 &VariableLength); 2253 } 2254 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2255 { 2256 Status = _SEH2_GetExceptionCode(); 2257 _SEH2_YIELD(goto Quit); 2258 } 2259 _SEH2_END; 2260 } 2261 else 2262 { 2263 Status = RtlCopySidAndAttributesArray(AccessToken->UserAndGroupCount, 2264 Token->UserAndGroups, 2265 VariableLength, 2266 AccessToken->UserAndGroups, 2267 EndMem, 2268 &EndMem, 2269 &VariableLength); 2270 if (!NT_SUCCESS(Status)) 2271 { 2272 DPRINT1("SepPerformTokenFiltering(): Failed to copy the groups into token (Status 0x%lx)\n", Status); 2273 goto Quit; 2274 } 2275 } 2276 } 2277 2278 /* Copy the restricted SIDs */ 2279 AccessToken->RestrictedSidCount = 0; 2280 AccessToken->RestrictedSids = NULL; 2281 if (Token->RestrictedSids && (Token->RestrictedSidCount > 0)) 2282 { 2283 AccessToken->RestrictedSidCount = Token->RestrictedSidCount; 2284 AccessToken->RestrictedSids = EndMem; 2285 EndMem = &AccessToken->RestrictedSids[AccessToken->RestrictedSidCount]; 2286 VariableLength -= ((ULONG_PTR)EndMem - (ULONG_PTR)AccessToken->RestrictedSids); 2287 2288 if (PreviousMode != KernelMode) 2289 { 2290 _SEH2_TRY 2291 { 2292 Status = RtlCopySidAndAttributesArray(AccessToken->RestrictedSidCount, 2293 Token->RestrictedSids, 2294 VariableLength, 2295 AccessToken->RestrictedSids, 2296 EndMem, 2297 &EndMem, 2298 &VariableLength); 2299 } 2300 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2301 { 2302 Status = _SEH2_GetExceptionCode(); 2303 _SEH2_YIELD(goto Quit); 2304 } 2305 _SEH2_END; 2306 } 2307 else 2308 { 2309 Status = RtlCopySidAndAttributesArray(AccessToken->RestrictedSidCount, 2310 Token->RestrictedSids, 2311 VariableLength, 2312 AccessToken->RestrictedSids, 2313 EndMem, 2314 &EndMem, 2315 &VariableLength); 2316 if (!NT_SUCCESS(Status)) 2317 { 2318 DPRINT1("SepPerformTokenFiltering(): Failed to copy the restricted SIDs into token (Status 0x%lx)\n", Status); 2319 goto Quit; 2320 } 2321 } 2322 } 2323 2324 /* Search for the primary group */ 2325 Status = SepFindPrimaryGroupAndDefaultOwner(AccessToken, 2326 Token->PrimaryGroup, 2327 NULL, 2328 &PrimaryGroupIndex, 2329 NULL); 2330 if (!NT_SUCCESS(Status)) 2331 { 2332 DPRINT1("SepPerformTokenFiltering(): Failed searching for the primary group (Status 0x%lx)\n", Status); 2333 goto Quit; 2334 } 2335 2336 /* Assign the primary group and default owner index now */ 2337 AccessToken->PrimaryGroup = AccessToken->UserAndGroups[PrimaryGroupIndex].Sid; 2338 AccessToken->DefaultOwnerIndex = Token->DefaultOwnerIndex; 2339 2340 /* Now allocate the token's dynamic information area and set the data */ 2341 AccessToken->DynamicAvailable = 0; 2342 AccessToken->DynamicPart = NULL; 2343 if (Token->DynamicPart && Token->DefaultDacl) 2344 { 2345 AccessToken->DynamicPart = ExAllocatePoolWithTag(PagedPool, 2346 Token->DefaultDacl->AclSize, 2347 TAG_TOKEN_DYNAMIC); 2348 if (AccessToken->DynamicPart == NULL) 2349 { 2350 Status = STATUS_INSUFFICIENT_RESOURCES; 2351 goto Quit; 2352 } 2353 2354 EndMem = (PVOID)AccessToken->DynamicPart; 2355 AccessToken->DefaultDacl = EndMem; 2356 2357 RtlCopyMemory(AccessToken->DefaultDacl, 2358 Token->DefaultDacl, 2359 Token->DefaultDacl->AclSize); 2360 } 2361 2362 /* 2363 * Now figure out what does the caller 2364 * want with the privileges. 2365 */ 2366 if (PrivilegeFlags & DISABLE_MAX_PRIVILEGE) 2367 { 2368 /* 2369 * The caller wants them disabled, cache this request 2370 * for later operations. 2371 */ 2372 WantPrivilegesDisabled = TRUE; 2373 } 2374 2375 if (PrivilegeFlags & SANDBOX_INERT) 2376 { 2377 /* The caller wants an inert token, store the TOKEN_SANDBOX_INERT flag now */ 2378 AccessToken->TokenFlags |= TOKEN_SANDBOX_INERT; 2379 } 2380 2381 /* 2382 * Now it's time to filter the token's privileges. 2383 * Loop all the privileges in the token. 2384 */ 2385 for (PrivsInToken = 0; PrivsInToken < AccessToken->PrivilegeCount; PrivsInToken++) 2386 { 2387 if (WantPrivilegesDisabled) 2388 { 2389 /* 2390 * We got the acknowledgement that the caller wants 2391 * to disable all the privileges so let's just do it. 2392 * However, as per the general documentation is stated 2393 * that only SE_CHANGE_NOTIFY_PRIVILEGE must be kept 2394 * therefore in that case we must skip this privilege. 2395 */ 2396 if (AccessToken->Privileges[PrivsInToken].Luid.LowPart == SE_CHANGE_NOTIFY_PRIVILEGE) 2397 { 2398 continue; 2399 } 2400 else 2401 { 2402 /* 2403 * The act of disabling privileges actually means 2404 * "deleting" them from the access token entirely. 2405 * First we must disable them so that we can update 2406 * token flags accordingly. 2407 */ 2408 AccessToken->Privileges[PrivsInToken].Attributes &= ~SE_PRIVILEGE_ENABLED; 2409 SepUpdateSinglePrivilegeFlagToken(AccessToken, PrivsInToken); 2410 2411 /* Remove the privileges now */ 2412 SepRemovePrivilegeToken(AccessToken, PrivsInToken); 2413 PrivsInToken--; 2414 } 2415 } 2416 else 2417 { 2418 if (PrivilegesToBeDeleted != NULL) 2419 { 2420 /* Loop the privileges we've got to delete */ 2421 for (PrivsInList = 0; PrivsInList < PrivilegesCount; PrivsInList++) 2422 { 2423 /* Does this privilege exist in the token? */ 2424 if (RtlEqualLuid(&AccessToken->Privileges[PrivsInToken].Luid, 2425 &PrivilegesToBeDeleted[PrivsInList].Luid)) 2426 { 2427 /* Mark that we found it */ 2428 FoundPrivilege = TRUE; 2429 break; 2430 } 2431 } 2432 2433 /* Did we find the privilege? */ 2434 if (PrivsInList == PrivilegesCount) 2435 { 2436 /* We didn't, continue with next one */ 2437 continue; 2438 } 2439 } 2440 } 2441 2442 /* 2443 * If we have found the target privilege in the token 2444 * based on the privileges list given by the caller 2445 * then begin deleting it. 2446 */ 2447 if (FoundPrivilege) 2448 { 2449 /* Disable the privilege and update the flags */ 2450 AccessToken->Privileges[PrivsInToken].Attributes &= ~SE_PRIVILEGE_ENABLED; 2451 SepUpdateSinglePrivilegeFlagToken(AccessToken, PrivsInToken); 2452 2453 /* Delete the privilege */ 2454 SepRemovePrivilegeToken(AccessToken, PrivsInToken); 2455 2456 /* 2457 * Adjust the index and reset the FoundPrivilege indicator 2458 * so that we can continue with the next privilege to delete. 2459 */ 2460 PrivsInToken--; 2461 FoundPrivilege = FALSE; 2462 continue; 2463 } 2464 } 2465 2466 /* 2467 * Loop the group SIDs that we want to disable as 2468 * per on the request by the caller. 2469 */ 2470 if (SidsToBeDisabled != NULL) 2471 { 2472 for (GroupsInToken = 0; GroupsInToken < AccessToken->UserAndGroupCount; GroupsInToken++) 2473 { 2474 for (GroupsInList = 0; GroupsInList < RegularGroupsSidCount; GroupsInList++) 2475 { 2476 /* Does this group SID exist in the token? */ 2477 if (RtlEqualSid(&AccessToken->UserAndGroups[GroupsInToken].Sid, 2478 &SidsToBeDisabled[GroupsInList].Sid)) 2479 { 2480 /* Mark that we found it */ 2481 FoundGroup = TRUE; 2482 break; 2483 } 2484 } 2485 2486 /* Did we find the group? */ 2487 if (GroupsInList == RegularGroupsSidCount) 2488 { 2489 /* We didn't, continue with next one */ 2490 continue; 2491 } 2492 2493 /* If we have found the group, disable it */ 2494 if (FoundGroup) 2495 { 2496 /* 2497 * If the acess token belongs to the administrators 2498 * group and this is the target group, we must take 2499 * away TOKEN_HAS_ADMIN_GROUP flag from the token. 2500 */ 2501 if (RtlEqualSid(SeAliasAdminsSid, 2502 &AccessToken->UserAndGroups[GroupsInToken].Sid)) 2503 { 2504 AccessToken->TokenFlags &= ~TOKEN_HAS_ADMIN_GROUP; 2505 } 2506 2507 /* 2508 * If the target group that we have found it is the 2509 * owner then from now on it no longer is but the user. 2510 * Therefore assign the default owner index as the user. 2511 */ 2512 if (AccessToken->DefaultOwnerIndex == GroupsInToken) 2513 { 2514 AccessToken->DefaultOwnerIndex = 0; 2515 } 2516 2517 /* 2518 * The principle of disabling a group SID is by 2519 * taking away SE_GROUP_ENABLED_BY_DEFAULT and 2520 * SE_GROUP_ENABLED attributes and assign 2521 * SE_GROUP_USE_FOR_DENY_ONLY. This renders 2522 * SID a "Deny only" SID. 2523 */ 2524 AccessToken->UserAndGroups[GroupsInToken].Attributes &= ~(SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT); 2525 AccessToken->UserAndGroups[GroupsInToken].Attributes |= SE_GROUP_USE_FOR_DENY_ONLY; 2526 2527 /* Adjust the index and continue with the next group */ 2528 GroupsInToken--; 2529 FoundGroup = FALSE; 2530 continue; 2531 } 2532 } 2533 } 2534 2535 /* 2536 * Insert the restricted SIDs into the token on 2537 * the request by the caller. 2538 */ 2539 if (RestrictedSidsIntoToken != NULL) 2540 { 2541 for (RestrictedSidsInList = 0; RestrictedSidsInList < RestrictedSidsCount; RestrictedSidsInList++) 2542 { 2543 /* Did the caller assign attributes to the restricted SIDs? */ 2544 if (RestrictedSidsIntoToken[RestrictedSidsInList].Attributes != 0) 2545 { 2546 /* There mustn't be any attributes, bail out */ 2547 DPRINT1("SepPerformTokenFiltering(): There mustn't be any attributes to restricted SIDs!\n"); 2548 Status = STATUS_INVALID_PARAMETER; 2549 goto Quit; 2550 } 2551 } 2552 2553 /* 2554 * Ensure that the token can hold the restricted SIDs 2555 * (the variable length is calculated at the beginning 2556 * of the routine call). 2557 */ 2558 ASSERT(VariableLength >= RestrictedSidsLength); 2559 2560 /* 2561 * Now let's begin inserting the restricted SIDs into the filtered 2562 * access token from the list the caller gave us. 2563 */ 2564 AccessToken->RestrictedSidCount = RestrictedSidsCount; 2565 AccessToken->RestrictedSids = EndMem; 2566 EndMem = (PVOID)((ULONG_PTR)EndMem + RestrictedSidsLength); 2567 VariableLength -= RestrictedSidsLength; 2568 2569 if (PreviousMode != KernelMode) 2570 { 2571 _SEH2_TRY 2572 { 2573 RtlCopyMemory(AccessToken->RestrictedSids, 2574 RestrictedSidsIntoToken, 2575 AccessToken->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES)); 2576 } 2577 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 2578 { 2579 Status = _SEH2_GetExceptionCode(); 2580 _SEH2_YIELD(goto Quit); 2581 } 2582 _SEH2_END; 2583 } 2584 else 2585 { 2586 RtlCopyMemory(AccessToken->RestrictedSids, 2587 RestrictedSidsIntoToken, 2588 AccessToken->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES)); 2589 } 2590 2591 /* 2592 * As we've copied the restricted SIDs into 2593 * the token, we must assign them the following 2594 * combination of attributes SE_GROUP_ENABLED, 2595 * SE_GROUP_ENABLED_BY_DEFAULT and SE_GROUP_MANDATORY. 2596 * With such attributes we estabilish that restricting 2597 * SIDs into the token are enabled for access checks. 2598 */ 2599 for (RestrictedSidsInToken = 0; RestrictedSidsInToken < AccessToken->RestrictedSidCount; RestrictedSidsInToken++) 2600 { 2601 AccessToken->RestrictedSids[RestrictedSidsInToken].Attributes |= (SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_MANDATORY); 2602 } 2603 2604 /* 2605 * As we added restricted SIDs into the token, mark 2606 * it as restricted. 2607 */ 2608 AccessToken->TokenFlags |= TOKEN_IS_RESTRICTED; 2609 } 2610 2611 /* We've finally filtered the token, give it to the caller */ 2612 *FilteredToken = AccessToken; 2613 Status = STATUS_SUCCESS; 2614 DPRINT("SepPerformTokenFiltering(): The token has been filtered!\n"); 2615 2616 Quit: 2617 if (!NT_SUCCESS(Status)) 2618 { 2619 /* Dereference the token */ 2620 ObDereferenceObject(AccessToken); 2621 } 2622 2623 return Status; 2624 } 2625 2626 /** 2627 * @brief 2628 * Creates the system process token. 2629 * 2630 * @return 2631 * Returns the system process token if the operations have 2632 * completed successfully. 2633 */ 2634 CODE_SEG("INIT") 2635 PTOKEN 2636 NTAPI 2637 SepCreateSystemProcessToken(VOID) 2638 { 2639 LUID_AND_ATTRIBUTES Privileges[25]; 2640 ULONG GroupAttributes, OwnerAttributes; 2641 SID_AND_ATTRIBUTES Groups[32]; 2642 LARGE_INTEGER Expiration; 2643 SID_AND_ATTRIBUTES UserSid; 2644 ULONG GroupsLength; 2645 PSID PrimaryGroup; 2646 OBJECT_ATTRIBUTES ObjectAttributes; 2647 PSID Owner; 2648 ULONG i; 2649 PTOKEN Token; 2650 NTSTATUS Status; 2651 2652 /* Don't ever expire */ 2653 Expiration.QuadPart = -1; 2654 2655 /* All groups mandatory and enabled */ 2656 GroupAttributes = SE_GROUP_ENABLED | SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT; 2657 OwnerAttributes = SE_GROUP_ENABLED | SE_GROUP_OWNER | SE_GROUP_ENABLED_BY_DEFAULT; 2658 2659 /* User is Local System */ 2660 UserSid.Sid = SeLocalSystemSid; 2661 UserSid.Attributes = 0; 2662 2663 /* Primary group is Local System */ 2664 PrimaryGroup = SeLocalSystemSid; 2665 2666 /* Owner is Administrators */ 2667 Owner = SeAliasAdminsSid; 2668 2669 /* Groups are Administrators, World, and Authenticated Users */ 2670 Groups[0].Sid = SeAliasAdminsSid; 2671 Groups[0].Attributes = OwnerAttributes; 2672 Groups[1].Sid = SeWorldSid; 2673 Groups[1].Attributes = GroupAttributes; 2674 Groups[2].Sid = SeAuthenticatedUsersSid; 2675 Groups[2].Attributes = GroupAttributes; 2676 GroupsLength = sizeof(SID_AND_ATTRIBUTES) + 2677 SeLengthSid(Groups[0].Sid) + 2678 SeLengthSid(Groups[1].Sid) + 2679 SeLengthSid(Groups[2].Sid); 2680 ASSERT(GroupsLength <= sizeof(Groups)); 2681 2682 /* Setup the privileges */ 2683 i = 0; 2684 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED; 2685 Privileges[i++].Luid = SeTcbPrivilege; 2686 2687 Privileges[i].Attributes = 0; 2688 Privileges[i++].Luid = SeCreateTokenPrivilege; 2689 2690 Privileges[i].Attributes = 0; 2691 Privileges[i++].Luid = SeTakeOwnershipPrivilege; 2692 2693 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED; 2694 Privileges[i++].Luid = SeCreatePagefilePrivilege; 2695 2696 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED; 2697 Privileges[i++].Luid = SeLockMemoryPrivilege; 2698 2699 Privileges[i].Attributes = 0; 2700 Privileges[i++].Luid = SeAssignPrimaryTokenPrivilege; 2701 2702 Privileges[i].Attributes = 0; 2703 Privileges[i++].Luid = SeIncreaseQuotaPrivilege; 2704 2705 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED; 2706 Privileges[i++].Luid = SeIncreaseBasePriorityPrivilege; 2707 2708 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED; 2709 Privileges[i++].Luid = SeCreatePermanentPrivilege; 2710 2711 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED; 2712 Privileges[i++].Luid = SeDebugPrivilege; 2713 2714 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED; 2715 Privileges[i++].Luid = SeAuditPrivilege; 2716 2717 Privileges[i].Attributes = 0; 2718 Privileges[i++].Luid = SeSecurityPrivilege; 2719 2720 Privileges[i].Attributes = 0; 2721 Privileges[i++].Luid = SeSystemEnvironmentPrivilege; 2722 2723 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED; 2724 Privileges[i++].Luid = SeChangeNotifyPrivilege; 2725 2726 Privileges[i].Attributes = 0; 2727 Privileges[i++].Luid = SeBackupPrivilege; 2728 2729 Privileges[i].Attributes = 0; 2730 Privileges[i++].Luid = SeRestorePrivilege; 2731 2732 Privileges[i].Attributes = 0; 2733 Privileges[i++].Luid = SeShutdownPrivilege; 2734 2735 Privileges[i].Attributes = 0; 2736 Privileges[i++].Luid = SeLoadDriverPrivilege; 2737 2738 Privileges[i].Attributes = SE_PRIVILEGE_ENABLED_BY_DEFAULT | SE_PRIVILEGE_ENABLED; 2739 Privileges[i++].Luid = SeProfileSingleProcessPrivilege; 2740 2741 Privileges[i].Attributes = 0; 2742 Privileges[i++].Luid = SeSystemtimePrivilege; 2743 ASSERT(i == 20); 2744 2745 /* Setup the object attributes */ 2746 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL); 2747 ASSERT(SeSystemDefaultDacl != NULL); 2748 2749 /* Create the token */ 2750 Status = SepCreateToken((PHANDLE)&Token, 2751 KernelMode, 2752 0, 2753 &ObjectAttributes, 2754 TokenPrimary, 2755 SecurityAnonymous, 2756 &SeSystemAuthenticationId, 2757 &Expiration, 2758 &UserSid, 2759 3, 2760 Groups, 2761 GroupsLength, 2762 20, 2763 Privileges, 2764 Owner, 2765 PrimaryGroup, 2766 SeSystemDefaultDacl, 2767 &SeSystemTokenSource, 2768 TRUE); 2769 ASSERT(Status == STATUS_SUCCESS); 2770 2771 /* Return the token */ 2772 return Token; 2773 } 2774 2775 /** 2776 * @brief 2777 * Creates the anonymous logon token for the system. The difference between this 2778 * token and the other one is the inclusion of everyone SID group (being SeWorldSid). 2779 * The other token lacks such group. 2780 * 2781 * @return 2782 * Returns the system's anonymous logon token if the operations have 2783 * completed successfully. 2784 */ 2785 CODE_SEG("INIT") 2786 PTOKEN 2787 SepCreateSystemAnonymousLogonToken(VOID) 2788 { 2789 SID_AND_ATTRIBUTES Groups[32], UserSid; 2790 PSID PrimaryGroup; 2791 PTOKEN Token; 2792 ULONG GroupsLength; 2793 LARGE_INTEGER Expiration; 2794 OBJECT_ATTRIBUTES ObjectAttributes; 2795 NTSTATUS Status; 2796 2797 /* The token never expires */ 2798 Expiration.QuadPart = -1; 2799 2800 /* The user is the anonymous logon */ 2801 UserSid.Sid = SeAnonymousLogonSid; 2802 UserSid.Attributes = 0; 2803 2804 /* The primary group is also the anonymous logon */ 2805 PrimaryGroup = SeAnonymousLogonSid; 2806 2807 /* The only group for the token is the World */ 2808 Groups[0].Sid = SeWorldSid; 2809 Groups[0].Attributes = SE_GROUP_ENABLED | SE_GROUP_MANDATORY | SE_GROUP_ENABLED_BY_DEFAULT; 2810 GroupsLength = sizeof(SID_AND_ATTRIBUTES) + 2811 SeLengthSid(Groups[0].Sid); 2812 ASSERT(GroupsLength <= sizeof(Groups)); 2813 2814 /* Initialise the object attributes for the token */ 2815 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL); 2816 ASSERT(SeSystemAnonymousLogonDacl != NULL); 2817 2818 /* Create token */ 2819 Status = SepCreateToken((PHANDLE)&Token, 2820 KernelMode, 2821 0, 2822 &ObjectAttributes, 2823 TokenPrimary, 2824 SecurityAnonymous, 2825 &SeAnonymousAuthenticationId, 2826 &Expiration, 2827 &UserSid, 2828 1, 2829 Groups, 2830 GroupsLength, 2831 0, 2832 NULL, 2833 NULL, 2834 PrimaryGroup, 2835 SeSystemAnonymousLogonDacl, 2836 &SeSystemTokenSource, 2837 TRUE); 2838 ASSERT(Status == STATUS_SUCCESS); 2839 2840 /* Return the anonymous logon token */ 2841 return Token; 2842 } 2843 2844 /** 2845 * @brief 2846 * Creates the anonymous logon token for the system. This kind of token 2847 * doesn't include the everyone SID group (being SeWorldSid). 2848 * 2849 * @return 2850 * Returns the system's anonymous logon token if the operations have 2851 * completed successfully. 2852 */ 2853 CODE_SEG("INIT") 2854 PTOKEN 2855 SepCreateSystemAnonymousLogonTokenNoEveryone(VOID) 2856 { 2857 SID_AND_ATTRIBUTES UserSid; 2858 PSID PrimaryGroup; 2859 PTOKEN Token; 2860 LARGE_INTEGER Expiration; 2861 OBJECT_ATTRIBUTES ObjectAttributes; 2862 NTSTATUS Status; 2863 2864 /* The token never expires */ 2865 Expiration.QuadPart = -1; 2866 2867 /* The user is the anonymous logon */ 2868 UserSid.Sid = SeAnonymousLogonSid; 2869 UserSid.Attributes = 0; 2870 2871 /* The primary group is also the anonymous logon */ 2872 PrimaryGroup = SeAnonymousLogonSid; 2873 2874 /* Initialise the object attributes for the token */ 2875 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL); 2876 ASSERT(SeSystemAnonymousLogonDacl != NULL); 2877 2878 /* Create token */ 2879 Status = SepCreateToken((PHANDLE)&Token, 2880 KernelMode, 2881 0, 2882 &ObjectAttributes, 2883 TokenPrimary, 2884 SecurityAnonymous, 2885 &SeAnonymousAuthenticationId, 2886 &Expiration, 2887 &UserSid, 2888 0, 2889 NULL, 2890 0, 2891 0, 2892 NULL, 2893 NULL, 2894 PrimaryGroup, 2895 SeSystemAnonymousLogonDacl, 2896 &SeSystemTokenSource, 2897 TRUE); 2898 ASSERT(Status == STATUS_SUCCESS); 2899 2900 /* Return the anonymous (not including everyone) logon token */ 2901 return Token; 2902 } 2903 2904 /* PUBLIC FUNCTIONS ***********************************************************/ 2905 2906 /** 2907 * @brief 2908 * Filters an access token from an existing token, making it more restricted 2909 * than the previous one. 2910 * 2911 * @param[in] ExistingToken 2912 * An existing token for filtering. 2913 * 2914 * @param[in] Flags 2915 * Privilege flag options. This parameter argument influences how the token 2916 * is filtered. Such parameter can be 0. See NtFilterToken syscall for 2917 * more information. 2918 * 2919 * @param[in] SidsToDisable 2920 * Array of SIDs to disable. Such parameter can be NULL. 2921 * 2922 * @param[in] PrivilegesToDelete 2923 * Array of privileges to delete. If DISABLE_MAX_PRIVILEGE flag is specified 2924 * in the Flags parameter, PrivilegesToDelete is ignored. 2925 * 2926 * @param[in] RestrictedSids 2927 * An array of restricted SIDs for the new filtered token. Such parameter 2928 * can be NULL. 2929 * 2930 * @param[out] FilteredToken 2931 * The newly filtered token, returned to the caller. 2932 * 2933 * @return 2934 * Returns STATUS_SUCCESS if the function has successfully completed its 2935 * operations and that the access token has been filtered. STATUS_INVALID_PARAMETER 2936 * is returned if one or more of the parameter are not valid. A failure NTSTATUS code 2937 * is returned otherwise. 2938 * 2939 * @remarks 2940 * WARNING -- The caller IS RESPONSIBLE for locking the existing access token 2941 * before attempting to do any kind of filtering operation into 2942 * the token. The lock MUST BE RELEASED after this kernel routine 2943 * has finished doing its work. 2944 */ 2945 NTSTATUS 2946 NTAPI 2947 SeFilterToken( 2948 _In_ PACCESS_TOKEN ExistingToken, 2949 _In_ ULONG Flags, 2950 _In_opt_ PTOKEN_GROUPS SidsToDisable, 2951 _In_opt_ PTOKEN_PRIVILEGES PrivilegesToDelete, 2952 _In_opt_ PTOKEN_GROUPS RestrictedSids, 2953 _Out_ PACCESS_TOKEN *FilteredToken) 2954 { 2955 NTSTATUS Status; 2956 PTOKEN AccessToken; 2957 ULONG PrivilegesCount = 0; 2958 ULONG SidsCount = 0; 2959 ULONG RestrictedSidsCount = 0; 2960 PAGED_CODE(); 2961 2962 /* Begin copying the counters */ 2963 if (SidsToDisable != NULL) 2964 { 2965 SidsCount = SidsToDisable->GroupCount; 2966 } 2967 2968 if (PrivilegesToDelete != NULL) 2969 { 2970 PrivilegesCount = PrivilegesToDelete->PrivilegeCount; 2971 } 2972 2973 if (RestrictedSids != NULL) 2974 { 2975 RestrictedSidsCount = RestrictedSids->GroupCount; 2976 } 2977 2978 /* Call the internal API */ 2979 Status = SepPerformTokenFiltering(ExistingToken, 2980 PrivilegesToDelete->Privileges, 2981 SidsToDisable->Groups, 2982 RestrictedSids->Groups, 2983 PrivilegesCount, 2984 SidsCount, 2985 RestrictedSidsCount, 2986 Flags, 2987 KernelMode, 2988 &AccessToken); 2989 if (!NT_SUCCESS(Status)) 2990 { 2991 DPRINT1("SeFilterToken(): Failed to filter the token (Status 0x%lx)\n", Status); 2992 return Status; 2993 } 2994 2995 /* Insert the filtered token */ 2996 Status = ObInsertObject(AccessToken, 2997 NULL, 2998 0, 2999 0, 3000 NULL, 3001 NULL); 3002 if (!NT_SUCCESS(Status)) 3003 { 3004 DPRINT1("SeFilterToken(): Failed to insert the token (Status 0x%lx)\n", Status); 3005 return Status; 3006 } 3007 3008 /* Give it to the caller */ 3009 *FilteredToken = AccessToken; 3010 return Status; 3011 } 3012 3013 /** 3014 * @brief 3015 * Queries information details about the given token to the call. The difference 3016 * between NtQueryInformationToken and this routine is that the system call has 3017 * user mode buffer data probing and additional protection checks whereas this 3018 * routine doesn't have any of these. The routine is used exclusively in kernel 3019 * mode. 3020 * 3021 * @param[in] AccessToken 3022 * An access token to be given. 3023 * 3024 * @param[in] TokenInformationClass 3025 * Token information class. 3026 * 3027 * @param[out] TokenInformation 3028 * Buffer with retrieved information. Such information is arbitrary, depending 3029 * on the requested information class. 3030 * 3031 * @return 3032 * Returns STATUS_SUCCESS if the operation to query the desired information 3033 * has completed successfully. STATUS_INSUFFICIENT_RESOURCES is returned if 3034 * pool memory allocation has failed to satisfy an operation. Otherwise 3035 * STATUS_INVALID_INFO_CLASS is returned indicating that the information 3036 * class provided is not supported by the routine. 3037 * 3038 * @remarks 3039 * Only certain information classes are not implemented in this function and 3040 * these are TokenOrigin, TokenGroupsAndPrivileges, TokenRestrictedSids and 3041 * TokenSandBoxInert. The following classes are implemented in NtQueryInformationToken 3042 * only. 3043 */ 3044 NTSTATUS 3045 NTAPI 3046 SeQueryInformationToken( 3047 _In_ PACCESS_TOKEN AccessToken, 3048 _In_ TOKEN_INFORMATION_CLASS TokenInformationClass, 3049 _Outptr_result_buffer_(_Inexpressible_(token-dependent)) PVOID *TokenInformation) 3050 { 3051 NTSTATUS Status; 3052 PTOKEN Token = (PTOKEN)AccessToken; 3053 ULONG RequiredLength; 3054 union 3055 { 3056 PSID PSid; 3057 ULONG Ulong; 3058 } Unused; 3059 3060 PAGED_CODE(); 3061 3062 /* Lock the token */ 3063 SepAcquireTokenLockShared(Token); 3064 3065 switch (TokenInformationClass) 3066 { 3067 case TokenUser: 3068 { 3069 PTOKEN_USER tu; 3070 3071 DPRINT("SeQueryInformationToken(TokenUser)\n"); 3072 RequiredLength = sizeof(TOKEN_USER) + 3073 RtlLengthSid(Token->UserAndGroups[0].Sid); 3074 3075 /* Allocate the output buffer */ 3076 tu = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE); 3077 if (tu == NULL) 3078 { 3079 Status = STATUS_INSUFFICIENT_RESOURCES; 3080 break; 3081 } 3082 3083 Status = RtlCopySidAndAttributesArray(1, 3084 &Token->UserAndGroups[0], 3085 RequiredLength - sizeof(TOKEN_USER), 3086 &tu->User, 3087 (PSID)(tu + 1), 3088 &Unused.PSid, 3089 &Unused.Ulong); 3090 3091 /* Return the structure */ 3092 *TokenInformation = tu; 3093 Status = STATUS_SUCCESS; 3094 break; 3095 } 3096 3097 case TokenGroups: 3098 { 3099 PTOKEN_GROUPS tg; 3100 ULONG SidLen; 3101 PSID Sid; 3102 3103 DPRINT("SeQueryInformationToken(TokenGroups)\n"); 3104 RequiredLength = sizeof(tg->GroupCount) + 3105 RtlLengthSidAndAttributes(Token->UserAndGroupCount - 1, &Token->UserAndGroups[1]); 3106 3107 SidLen = RequiredLength - sizeof(tg->GroupCount) - 3108 ((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES)); 3109 3110 /* Allocate the output buffer */ 3111 tg = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE); 3112 if (tg == NULL) 3113 { 3114 Status = STATUS_INSUFFICIENT_RESOURCES; 3115 break; 3116 } 3117 3118 Sid = (PSID)((ULONG_PTR)tg + sizeof(tg->GroupCount) + 3119 ((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES))); 3120 3121 tg->GroupCount = Token->UserAndGroupCount - 1; 3122 Status = RtlCopySidAndAttributesArray(Token->UserAndGroupCount - 1, 3123 &Token->UserAndGroups[1], 3124 SidLen, 3125 &tg->Groups[0], 3126 Sid, 3127 &Unused.PSid, 3128 &Unused.Ulong); 3129 3130 /* Return the structure */ 3131 *TokenInformation = tg; 3132 Status = STATUS_SUCCESS; 3133 break; 3134 } 3135 3136 case TokenPrivileges: 3137 { 3138 PTOKEN_PRIVILEGES tp; 3139 3140 DPRINT("SeQueryInformationToken(TokenPrivileges)\n"); 3141 RequiredLength = sizeof(tp->PrivilegeCount) + 3142 (Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES)); 3143 3144 /* Allocate the output buffer */ 3145 tp = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE); 3146 if (tp == NULL) 3147 { 3148 Status = STATUS_INSUFFICIENT_RESOURCES; 3149 break; 3150 } 3151 3152 tp->PrivilegeCount = Token->PrivilegeCount; 3153 RtlCopyLuidAndAttributesArray(Token->PrivilegeCount, 3154 Token->Privileges, 3155 &tp->Privileges[0]); 3156 3157 /* Return the structure */ 3158 *TokenInformation = tp; 3159 Status = STATUS_SUCCESS; 3160 break; 3161 } 3162 3163 case TokenOwner: 3164 { 3165 PTOKEN_OWNER to; 3166 ULONG SidLen; 3167 3168 DPRINT("SeQueryInformationToken(TokenOwner)\n"); 3169 SidLen = RtlLengthSid(Token->UserAndGroups[Token->DefaultOwnerIndex].Sid); 3170 RequiredLength = sizeof(TOKEN_OWNER) + SidLen; 3171 3172 /* Allocate the output buffer */ 3173 to = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE); 3174 if (to == NULL) 3175 { 3176 Status = STATUS_INSUFFICIENT_RESOURCES; 3177 break; 3178 } 3179 3180 to->Owner = (PSID)(to + 1); 3181 Status = RtlCopySid(SidLen, 3182 to->Owner, 3183 Token->UserAndGroups[Token->DefaultOwnerIndex].Sid); 3184 3185 /* Return the structure */ 3186 *TokenInformation = to; 3187 Status = STATUS_SUCCESS; 3188 break; 3189 } 3190 3191 case TokenPrimaryGroup: 3192 { 3193 PTOKEN_PRIMARY_GROUP tpg; 3194 ULONG SidLen; 3195 3196 DPRINT("SeQueryInformationToken(TokenPrimaryGroup)\n"); 3197 SidLen = RtlLengthSid(Token->PrimaryGroup); 3198 RequiredLength = sizeof(TOKEN_PRIMARY_GROUP) + SidLen; 3199 3200 /* Allocate the output buffer */ 3201 tpg = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE); 3202 if (tpg == NULL) 3203 { 3204 Status = STATUS_INSUFFICIENT_RESOURCES; 3205 break; 3206 } 3207 3208 tpg->PrimaryGroup = (PSID)(tpg + 1); 3209 Status = RtlCopySid(SidLen, 3210 tpg->PrimaryGroup, 3211 Token->PrimaryGroup); 3212 3213 /* Return the structure */ 3214 *TokenInformation = tpg; 3215 Status = STATUS_SUCCESS; 3216 break; 3217 } 3218 3219 case TokenDefaultDacl: 3220 { 3221 PTOKEN_DEFAULT_DACL tdd; 3222 3223 DPRINT("SeQueryInformationToken(TokenDefaultDacl)\n"); 3224 RequiredLength = sizeof(TOKEN_DEFAULT_DACL); 3225 3226 if (Token->DefaultDacl != NULL) 3227 RequiredLength += Token->DefaultDacl->AclSize; 3228 3229 /* Allocate the output buffer */ 3230 tdd = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE); 3231 if (tdd == NULL) 3232 { 3233 Status = STATUS_INSUFFICIENT_RESOURCES; 3234 break; 3235 } 3236 3237 if (Token->DefaultDacl != NULL) 3238 { 3239 tdd->DefaultDacl = (PACL)(tdd + 1); 3240 RtlCopyMemory(tdd->DefaultDacl, 3241 Token->DefaultDacl, 3242 Token->DefaultDacl->AclSize); 3243 } 3244 else 3245 { 3246 tdd->DefaultDacl = NULL; 3247 } 3248 3249 /* Return the structure */ 3250 *TokenInformation = tdd; 3251 Status = STATUS_SUCCESS; 3252 break; 3253 } 3254 3255 case TokenSource: 3256 { 3257 PTOKEN_SOURCE ts; 3258 3259 DPRINT("SeQueryInformationToken(TokenSource)\n"); 3260 RequiredLength = sizeof(TOKEN_SOURCE); 3261 3262 /* Allocate the output buffer */ 3263 ts = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE); 3264 if (ts == NULL) 3265 { 3266 Status = STATUS_INSUFFICIENT_RESOURCES; 3267 break; 3268 } 3269 3270 *ts = Token->TokenSource; 3271 3272 /* Return the structure */ 3273 *TokenInformation = ts; 3274 Status = STATUS_SUCCESS; 3275 break; 3276 } 3277 3278 case TokenType: 3279 { 3280 PTOKEN_TYPE tt; 3281 3282 DPRINT("SeQueryInformationToken(TokenType)\n"); 3283 RequiredLength = sizeof(TOKEN_TYPE); 3284 3285 /* Allocate the output buffer */ 3286 tt = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE); 3287 if (tt == NULL) 3288 { 3289 Status = STATUS_INSUFFICIENT_RESOURCES; 3290 break; 3291 } 3292 3293 *tt = Token->TokenType; 3294 3295 /* Return the structure */ 3296 *TokenInformation = tt; 3297 Status = STATUS_SUCCESS; 3298 break; 3299 } 3300 3301 case TokenImpersonationLevel: 3302 { 3303 PSECURITY_IMPERSONATION_LEVEL sil; 3304 3305 DPRINT("SeQueryInformationToken(TokenImpersonationLevel)\n"); 3306 RequiredLength = sizeof(SECURITY_IMPERSONATION_LEVEL); 3307 3308 /* Fail if the token is not an impersonation token */ 3309 if (Token->TokenType != TokenImpersonation) 3310 { 3311 Status = STATUS_INVALID_INFO_CLASS; 3312 break; 3313 } 3314 3315 /* Allocate the output buffer */ 3316 sil = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE); 3317 if (sil == NULL) 3318 { 3319 Status = STATUS_INSUFFICIENT_RESOURCES; 3320 break; 3321 } 3322 3323 *sil = Token->ImpersonationLevel; 3324 3325 /* Return the structure */ 3326 *TokenInformation = sil; 3327 Status = STATUS_SUCCESS; 3328 break; 3329 } 3330 3331 case TokenStatistics: 3332 { 3333 PTOKEN_STATISTICS ts; 3334 3335 DPRINT("SeQueryInformationToken(TokenStatistics)\n"); 3336 RequiredLength = sizeof(TOKEN_STATISTICS); 3337 3338 /* Allocate the output buffer */ 3339 ts = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE); 3340 if (ts == NULL) 3341 { 3342 Status = STATUS_INSUFFICIENT_RESOURCES; 3343 break; 3344 } 3345 3346 ts->TokenId = Token->TokenId; 3347 ts->AuthenticationId = Token->AuthenticationId; 3348 ts->ExpirationTime = Token->ExpirationTime; 3349 ts->TokenType = Token->TokenType; 3350 ts->ImpersonationLevel = Token->ImpersonationLevel; 3351 ts->DynamicCharged = Token->DynamicCharged; 3352 ts->DynamicAvailable = Token->DynamicAvailable; 3353 ts->GroupCount = Token->UserAndGroupCount - 1; 3354 ts->PrivilegeCount = Token->PrivilegeCount; 3355 ts->ModifiedId = Token->ModifiedId; 3356 3357 /* Return the structure */ 3358 *TokenInformation = ts; 3359 Status = STATUS_SUCCESS; 3360 break; 3361 } 3362 3363 case TokenSessionId: 3364 { 3365 DPRINT("SeQueryInformationToken(TokenSessionId)\n"); 3366 Status = SeQuerySessionIdToken(Token, (PULONG)TokenInformation); 3367 break; 3368 } 3369 3370 default: 3371 DPRINT1("SeQueryInformationToken(%d) invalid information class\n", TokenInformationClass); 3372 Status = STATUS_INVALID_INFO_CLASS; 3373 break; 3374 } 3375 3376 /* Release the lock of the token */ 3377 SepReleaseTokenLock(Token); 3378 3379 return Status; 3380 } 3381 3382 /** 3383 * @brief 3384 * Queries the session ID of an access token. 3385 * 3386 * @param[in] Token 3387 * A valid access token where the session ID has to be gathered. 3388 * 3389 * @param[out] pSessionId 3390 * The returned pointer to a session ID to the caller. 3391 * 3392 * @return 3393 * Returns STATUS_SUCCESS. 3394 */ 3395 NTSTATUS 3396 NTAPI 3397 SeQuerySessionIdToken( 3398 _In_ PACCESS_TOKEN Token, 3399 _Out_ PULONG pSessionId) 3400 { 3401 PAGED_CODE(); 3402 3403 /* Lock the token */ 3404 SepAcquireTokenLockShared(Token); 3405 3406 *pSessionId = ((PTOKEN)Token)->SessionId; 3407 3408 /* Unlock the token */ 3409 SepReleaseTokenLock(Token); 3410 3411 return STATUS_SUCCESS; 3412 } 3413 3414 /** 3415 * @brief 3416 * Queries the authentication ID of an access token. 3417 * 3418 * @param[in] Token 3419 * A valid access token where the authentication ID has to be gathered. 3420 * 3421 * @param[out] pSessionId 3422 * The returned pointer to an authentication ID to the caller. 3423 * 3424 * @return 3425 * Returns STATUS_SUCCESS. 3426 */ 3427 NTSTATUS 3428 NTAPI 3429 SeQueryAuthenticationIdToken( 3430 _In_ PACCESS_TOKEN Token, 3431 _Out_ PLUID LogonId) 3432 { 3433 PAGED_CODE(); 3434 3435 *LogonId = ((PTOKEN)Token)->AuthenticationId; 3436 3437 return STATUS_SUCCESS; 3438 } 3439 3440 /** 3441 * @brief 3442 * Gathers the security impersonation level of an access token. 3443 * 3444 * @param[in] Token 3445 * A valid access token where the impersonation level has to be gathered. 3446 * 3447 * @return 3448 * Returns the security impersonation level from a valid token. 3449 */ 3450 SECURITY_IMPERSONATION_LEVEL 3451 NTAPI 3452 SeTokenImpersonationLevel( 3453 _In_ PACCESS_TOKEN Token) 3454 { 3455 PAGED_CODE(); 3456 3457 return ((PTOKEN)Token)->ImpersonationLevel; 3458 } 3459 3460 /** 3461 * @brief 3462 * Gathers the token type of an access token. A token ca be either 3463 * a primary token or impersonation token. 3464 * 3465 * @param[in] Token 3466 * A valid access token where the token type has to be gathered. 3467 * 3468 * @return 3469 * Returns the token type from a valid token. 3470 */ 3471 TOKEN_TYPE 3472 NTAPI 3473 SeTokenType( 3474 _In_ PACCESS_TOKEN Token) 3475 { 3476 PAGED_CODE(); 3477 3478 return ((PTOKEN)Token)->TokenType; 3479 } 3480 3481 /** 3482 * @brief 3483 * Determines if a token is either an admin token or not. Such 3484 * condition is checked based upon TOKEN_HAS_ADMIN_GROUP flag, 3485 * which means if the respective access token belongs to an 3486 * administrator group or not. 3487 * 3488 * @param[in] Token 3489 * A valid access token to determine if such token is admin or not. 3490 * 3491 * @return 3492 * Returns TRUE if the token is an admin one, FALSE otherwise. 3493 */ 3494 BOOLEAN 3495 NTAPI 3496 SeTokenIsAdmin( 3497 _In_ PACCESS_TOKEN Token) 3498 { 3499 PAGED_CODE(); 3500 3501 // NOTE: Win7+ instead really checks the list of groups in the token 3502 // (since TOKEN_HAS_ADMIN_GROUP == TOKEN_WRITE_RESTRICTED ...) 3503 return (((PTOKEN)Token)->TokenFlags & TOKEN_HAS_ADMIN_GROUP) != 0; 3504 } 3505 3506 /** 3507 * @brief 3508 * Determines if a token is restricted or not, based upon the token 3509 * flags. 3510 * 3511 * @param[in] Token 3512 * A valid access token to determine if such token is restricted. 3513 * 3514 * @return 3515 * Returns TRUE if the token is restricted, FALSE otherwise. 3516 */ 3517 BOOLEAN 3518 NTAPI 3519 SeTokenIsRestricted( 3520 _In_ PACCESS_TOKEN Token) 3521 { 3522 PAGED_CODE(); 3523 3524 return (((PTOKEN)Token)->TokenFlags & TOKEN_IS_RESTRICTED) != 0; 3525 } 3526 3527 /** 3528 * @brief 3529 * Determines if a token is write restricted, that is, nobody can write anything 3530 * to it. 3531 * 3532 * @param[in] Token 3533 * A valid access token to determine if such token is write restricted. 3534 * 3535 * @return 3536 * Returns TRUE if the token is write restricted, FALSE otherwise. 3537 * 3538 * @remarks 3539 * First introduced in NT 5.1 SP2 x86 (5.1.2600.2622), absent in NT 5.2, 3540 * then finally re-introduced in Vista+. 3541 */ 3542 BOOLEAN 3543 NTAPI 3544 SeTokenIsWriteRestricted( 3545 _In_ PACCESS_TOKEN Token) 3546 { 3547 PAGED_CODE(); 3548 3549 // NOTE: NT 5.1 SP2 x86 checks the SE_BACKUP_PRIVILEGES_CHECKED flag 3550 // while Vista+ checks the TOKEN_WRITE_RESTRICTED flag as one expects. 3551 return (((PTOKEN)Token)->TokenFlags & SE_BACKUP_PRIVILEGES_CHECKED) != 0; 3552 } 3553 3554 /** 3555 * @brief 3556 * Ensures that client impersonation can occur by checking if the token 3557 * we're going to assign as the impersonation token can be actually impersonated 3558 * in the first place. The routine is used primarily by PsImpersonateClient. 3559 * 3560 * @param[in] ProcessToken 3561 * Token from a process. 3562 * 3563 * @param[in] TokenToImpersonate 3564 * Token that we are going to impersonate. 3565 * 3566 * @param[in] ImpersonationLevel 3567 * Security impersonation level grade. 3568 * 3569 * @return 3570 * Returns TRUE if the conditions checked are met for token impersonation, 3571 * FALSE otherwise. 3572 */ 3573 BOOLEAN 3574 NTAPI 3575 SeTokenCanImpersonate( 3576 _In_ PTOKEN ProcessToken, 3577 _In_ PTOKEN TokenToImpersonate, 3578 _In_ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel) 3579 { 3580 BOOLEAN CanImpersonate; 3581 PAGED_CODE(); 3582 3583 /* 3584 * SecurityAnonymous and SecurityIdentification levels do not 3585 * allow impersonation. 3586 */ 3587 if (ImpersonationLevel == SecurityAnonymous || 3588 ImpersonationLevel == SecurityIdentification) 3589 { 3590 return FALSE; 3591 } 3592 3593 /* Time to lock our tokens */ 3594 SepAcquireTokenLockShared(ProcessToken); 3595 SepAcquireTokenLockShared(TokenToImpersonate); 3596 3597 /* What kind of authentication ID does the token have? */ 3598 if (RtlEqualLuid(&TokenToImpersonate->AuthenticationId, 3599 &SeAnonymousAuthenticationId)) 3600 { 3601 /* 3602 * OK, it looks like the token has an anonymous 3603 * authentication. Is that token created by the system? 3604 */ 3605 if (TokenToImpersonate->TokenSource.SourceName != SeSystemTokenSource.SourceName && 3606 !RtlEqualLuid(&TokenToImpersonate->TokenSource.SourceIdentifier, &SeSystemTokenSource.SourceIdentifier)) 3607 { 3608 /* It isn't, we can't impersonate regular tokens */ 3609 DPRINT("SeTokenCanImpersonate(): Token has an anonymous authentication ID, can't impersonate!\n"); 3610 CanImpersonate = FALSE; 3611 goto Quit; 3612 } 3613 } 3614 3615 /* Are the SID values from both tokens equal? */ 3616 if (!RtlEqualSid(ProcessToken->UserAndGroups->Sid, 3617 TokenToImpersonate->UserAndGroups->Sid)) 3618 { 3619 /* They aren't, bail out */ 3620 DPRINT("SeTokenCanImpersonate(): Tokens SIDs are not equal!\n"); 3621 CanImpersonate = FALSE; 3622 goto Quit; 3623 } 3624 3625 /* 3626 * Make sure the tokens aren't diverged in terms of 3627 * restrictions, that is, one token is restricted 3628 * but the other one isn't. 3629 */ 3630 if (SeTokenIsRestricted(ProcessToken) != 3631 SeTokenIsRestricted(TokenToImpersonate)) 3632 { 3633 /* 3634 * One token is restricted so we cannot 3635 * continue further at this point, bail out. 3636 */ 3637 DPRINT("SeTokenCanImpersonate(): One token is restricted, can't continue!\n"); 3638 CanImpersonate = FALSE; 3639 goto Quit; 3640 } 3641 3642 /* If we've reached that far then we can impersonate! */ 3643 DPRINT("SeTokenCanImpersonate(): We can impersonate.\n"); 3644 CanImpersonate = TRUE; 3645 3646 Quit: 3647 /* We're done, unlock the tokens now */ 3648 SepReleaseTokenLock(ProcessToken); 3649 SepReleaseTokenLock(TokenToImpersonate); 3650 3651 return CanImpersonate; 3652 } 3653 3654 /* SYSTEM CALLS ***************************************************************/ 3655 3656 /** 3657 * @brief 3658 * Queries a specific type of information in regard of an access token based upon 3659 * the information class. The calling thread must have specific access rights in order 3660 * to obtain specific information about the token. 3661 * 3662 * @param[in] TokenHandle 3663 * A handle of a token where information is to be gathered. 3664 * 3665 * @param[in] TokenInformationClass 3666 * Token information class. 3667 * 3668 * @param[out] TokenInformation 3669 * A returned output buffer with token information, which information is arbitrarily upon 3670 * the information class chosen. 3671 * 3672 * @param[in] TokenInformationLength 3673 * Length of the token information buffer, in bytes. 3674 * 3675 * @param[out] ReturnLength 3676 * If specified in the call, the function returns the total length size of the token 3677 * information buffer.. 3678 * 3679 * @return 3680 * Returns STATUS_SUCCESS if information querying has completed successfully. 3681 * STATUS_BUFFER_TOO_SMALL is returned if the information length that represents 3682 * the token information buffer is not greater than the required length. 3683 * STATUS_INVALID_HANDLE is returned if the token handle is not a valid one. 3684 * STATUS_INVALID_INFO_CLASS is returned if the information class is not a valid 3685 * one (that is, the class doesn't belong to TOKEN_INFORMATION_CLASS). A failure 3686 * NTSTATUS code is returned otherwise. 3687 */ 3688 _Must_inspect_result_ 3689 __kernel_entry 3690 NTSTATUS 3691 NTAPI 3692 NtQueryInformationToken( 3693 _In_ HANDLE TokenHandle, 3694 _In_ TOKEN_INFORMATION_CLASS TokenInformationClass, 3695 _Out_writes_bytes_to_opt_(TokenInformationLength, *ReturnLength) 3696 PVOID TokenInformation, 3697 _In_ ULONG TokenInformationLength, 3698 _Out_ PULONG ReturnLength) 3699 { 3700 NTSTATUS Status; 3701 KPROCESSOR_MODE PreviousMode; 3702 PTOKEN Token; 3703 ULONG RequiredLength; 3704 union 3705 { 3706 PSID PSid; 3707 ULONG Ulong; 3708 } Unused; 3709 3710 PAGED_CODE(); 3711 3712 PreviousMode = ExGetPreviousMode(); 3713 3714 /* Check buffers and class validity */ 3715 Status = DefaultQueryInfoBufferCheck(TokenInformationClass, 3716 SeTokenInformationClass, 3717 RTL_NUMBER_OF(SeTokenInformationClass), 3718 TokenInformation, 3719 TokenInformationLength, 3720 ReturnLength, 3721 NULL, 3722 PreviousMode, 3723 TRUE); 3724 if (!NT_SUCCESS(Status)) 3725 { 3726 DPRINT("NtQueryInformationToken() failed, Status: 0x%x\n", Status); 3727 return Status; 3728 } 3729 3730 Status = ObReferenceObjectByHandle(TokenHandle, 3731 (TokenInformationClass == TokenSource) ? TOKEN_QUERY_SOURCE : TOKEN_QUERY, 3732 SeTokenObjectType, 3733 PreviousMode, 3734 (PVOID*)&Token, 3735 NULL); 3736 if (NT_SUCCESS(Status)) 3737 { 3738 /* Lock the token */ 3739 SepAcquireTokenLockShared(Token); 3740 3741 switch (TokenInformationClass) 3742 { 3743 case TokenUser: 3744 { 3745 PTOKEN_USER tu = (PTOKEN_USER)TokenInformation; 3746 3747 DPRINT("NtQueryInformationToken(TokenUser)\n"); 3748 RequiredLength = sizeof(TOKEN_USER) + 3749 RtlLengthSid(Token->UserAndGroups[0].Sid); 3750 3751 _SEH2_TRY 3752 { 3753 if (TokenInformationLength >= RequiredLength) 3754 { 3755 Status = RtlCopySidAndAttributesArray(1, 3756 &Token->UserAndGroups[0], 3757 RequiredLength - sizeof(TOKEN_USER), 3758 &tu->User, 3759 (PSID)(tu + 1), 3760 &Unused.PSid, 3761 &Unused.Ulong); 3762 } 3763 else 3764 { 3765 Status = STATUS_BUFFER_TOO_SMALL; 3766 } 3767 3768 if (ReturnLength != NULL) 3769 { 3770 *ReturnLength = RequiredLength; 3771 } 3772 } 3773 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3774 { 3775 Status = _SEH2_GetExceptionCode(); 3776 } 3777 _SEH2_END; 3778 3779 break; 3780 } 3781 3782 case TokenGroups: 3783 { 3784 PTOKEN_GROUPS tg = (PTOKEN_GROUPS)TokenInformation; 3785 3786 DPRINT("NtQueryInformationToken(TokenGroups)\n"); 3787 RequiredLength = sizeof(tg->GroupCount) + 3788 RtlLengthSidAndAttributes(Token->UserAndGroupCount - 1, &Token->UserAndGroups[1]); 3789 3790 _SEH2_TRY 3791 { 3792 if (TokenInformationLength >= RequiredLength) 3793 { 3794 ULONG SidLen = RequiredLength - sizeof(tg->GroupCount) - 3795 ((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES)); 3796 PSID Sid = (PSID_AND_ATTRIBUTES)((ULONG_PTR)tg + sizeof(tg->GroupCount) + 3797 ((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES))); 3798 3799 tg->GroupCount = Token->UserAndGroupCount - 1; 3800 Status = RtlCopySidAndAttributesArray(Token->UserAndGroupCount - 1, 3801 &Token->UserAndGroups[1], 3802 SidLen, 3803 &tg->Groups[0], 3804 Sid, 3805 &Unused.PSid, 3806 &Unused.Ulong); 3807 } 3808 else 3809 { 3810 Status = STATUS_BUFFER_TOO_SMALL; 3811 } 3812 3813 if (ReturnLength != NULL) 3814 { 3815 *ReturnLength = RequiredLength; 3816 } 3817 } 3818 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3819 { 3820 Status = _SEH2_GetExceptionCode(); 3821 } 3822 _SEH2_END; 3823 3824 break; 3825 } 3826 3827 case TokenPrivileges: 3828 { 3829 PTOKEN_PRIVILEGES tp = (PTOKEN_PRIVILEGES)TokenInformation; 3830 3831 DPRINT("NtQueryInformationToken(TokenPrivileges)\n"); 3832 RequiredLength = sizeof(tp->PrivilegeCount) + 3833 (Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES)); 3834 3835 _SEH2_TRY 3836 { 3837 if (TokenInformationLength >= RequiredLength) 3838 { 3839 tp->PrivilegeCount = Token->PrivilegeCount; 3840 RtlCopyLuidAndAttributesArray(Token->PrivilegeCount, 3841 Token->Privileges, 3842 &tp->Privileges[0]); 3843 } 3844 else 3845 { 3846 Status = STATUS_BUFFER_TOO_SMALL; 3847 } 3848 3849 if (ReturnLength != NULL) 3850 { 3851 *ReturnLength = RequiredLength; 3852 } 3853 } 3854 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3855 { 3856 Status = _SEH2_GetExceptionCode(); 3857 } 3858 _SEH2_END; 3859 3860 break; 3861 } 3862 3863 case TokenOwner: 3864 { 3865 PTOKEN_OWNER to = (PTOKEN_OWNER)TokenInformation; 3866 ULONG SidLen; 3867 3868 DPRINT("NtQueryInformationToken(TokenOwner)\n"); 3869 SidLen = RtlLengthSid(Token->UserAndGroups[Token->DefaultOwnerIndex].Sid); 3870 RequiredLength = sizeof(TOKEN_OWNER) + SidLen; 3871 3872 _SEH2_TRY 3873 { 3874 if (TokenInformationLength >= RequiredLength) 3875 { 3876 to->Owner = (PSID)(to + 1); 3877 Status = RtlCopySid(SidLen, 3878 to->Owner, 3879 Token->UserAndGroups[Token->DefaultOwnerIndex].Sid); 3880 } 3881 else 3882 { 3883 Status = STATUS_BUFFER_TOO_SMALL; 3884 } 3885 3886 if (ReturnLength != NULL) 3887 { 3888 *ReturnLength = RequiredLength; 3889 } 3890 } 3891 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3892 { 3893 Status = _SEH2_GetExceptionCode(); 3894 } 3895 _SEH2_END; 3896 3897 break; 3898 } 3899 3900 case TokenPrimaryGroup: 3901 { 3902 PTOKEN_PRIMARY_GROUP tpg = (PTOKEN_PRIMARY_GROUP)TokenInformation; 3903 ULONG SidLen; 3904 3905 DPRINT("NtQueryInformationToken(TokenPrimaryGroup)\n"); 3906 SidLen = RtlLengthSid(Token->PrimaryGroup); 3907 RequiredLength = sizeof(TOKEN_PRIMARY_GROUP) + SidLen; 3908 3909 _SEH2_TRY 3910 { 3911 if (TokenInformationLength >= RequiredLength) 3912 { 3913 tpg->PrimaryGroup = (PSID)(tpg + 1); 3914 Status = RtlCopySid(SidLen, 3915 tpg->PrimaryGroup, 3916 Token->PrimaryGroup); 3917 } 3918 else 3919 { 3920 Status = STATUS_BUFFER_TOO_SMALL; 3921 } 3922 3923 if (ReturnLength != NULL) 3924 { 3925 *ReturnLength = RequiredLength; 3926 } 3927 } 3928 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3929 { 3930 Status = _SEH2_GetExceptionCode(); 3931 } 3932 _SEH2_END; 3933 3934 break; 3935 } 3936 3937 case TokenDefaultDacl: 3938 { 3939 PTOKEN_DEFAULT_DACL tdd = (PTOKEN_DEFAULT_DACL)TokenInformation; 3940 3941 DPRINT("NtQueryInformationToken(TokenDefaultDacl)\n"); 3942 RequiredLength = sizeof(TOKEN_DEFAULT_DACL); 3943 3944 if (Token->DefaultDacl != NULL) 3945 RequiredLength += Token->DefaultDacl->AclSize; 3946 3947 _SEH2_TRY 3948 { 3949 if (TokenInformationLength >= RequiredLength) 3950 { 3951 if (Token->DefaultDacl != NULL) 3952 { 3953 tdd->DefaultDacl = (PACL)(tdd + 1); 3954 RtlCopyMemory(tdd->DefaultDacl, 3955 Token->DefaultDacl, 3956 Token->DefaultDacl->AclSize); 3957 } 3958 else 3959 { 3960 tdd->DefaultDacl = NULL; 3961 } 3962 } 3963 else 3964 { 3965 Status = STATUS_BUFFER_TOO_SMALL; 3966 } 3967 3968 if (ReturnLength != NULL) 3969 { 3970 *ReturnLength = RequiredLength; 3971 } 3972 } 3973 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3974 { 3975 Status = _SEH2_GetExceptionCode(); 3976 } 3977 _SEH2_END; 3978 3979 break; 3980 } 3981 3982 case TokenSource: 3983 { 3984 PTOKEN_SOURCE ts = (PTOKEN_SOURCE)TokenInformation; 3985 3986 DPRINT("NtQueryInformationToken(TokenSource)\n"); 3987 RequiredLength = sizeof(TOKEN_SOURCE); 3988 3989 _SEH2_TRY 3990 { 3991 if (TokenInformationLength >= RequiredLength) 3992 { 3993 *ts = Token->TokenSource; 3994 } 3995 else 3996 { 3997 Status = STATUS_BUFFER_TOO_SMALL; 3998 } 3999 4000 if (ReturnLength != NULL) 4001 { 4002 *ReturnLength = RequiredLength; 4003 } 4004 } 4005 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4006 { 4007 Status = _SEH2_GetExceptionCode(); 4008 } 4009 _SEH2_END; 4010 4011 break; 4012 } 4013 4014 case TokenType: 4015 { 4016 PTOKEN_TYPE tt = (PTOKEN_TYPE)TokenInformation; 4017 4018 DPRINT("NtQueryInformationToken(TokenType)\n"); 4019 RequiredLength = sizeof(TOKEN_TYPE); 4020 4021 _SEH2_TRY 4022 { 4023 if (TokenInformationLength >= RequiredLength) 4024 { 4025 *tt = Token->TokenType; 4026 } 4027 else 4028 { 4029 Status = STATUS_BUFFER_TOO_SMALL; 4030 } 4031 4032 if (ReturnLength != NULL) 4033 { 4034 *ReturnLength = RequiredLength; 4035 } 4036 } 4037 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4038 { 4039 Status = _SEH2_GetExceptionCode(); 4040 } 4041 _SEH2_END; 4042 4043 break; 4044 } 4045 4046 case TokenImpersonationLevel: 4047 { 4048 PSECURITY_IMPERSONATION_LEVEL sil = (PSECURITY_IMPERSONATION_LEVEL)TokenInformation; 4049 4050 DPRINT("NtQueryInformationToken(TokenImpersonationLevel)\n"); 4051 4052 /* Fail if the token is not an impersonation token */ 4053 if (Token->TokenType != TokenImpersonation) 4054 { 4055 Status = STATUS_INVALID_INFO_CLASS; 4056 break; 4057 } 4058 4059 RequiredLength = sizeof(SECURITY_IMPERSONATION_LEVEL); 4060 4061 _SEH2_TRY 4062 { 4063 if (TokenInformationLength >= RequiredLength) 4064 { 4065 *sil = Token->ImpersonationLevel; 4066 } 4067 else 4068 { 4069 Status = STATUS_BUFFER_TOO_SMALL; 4070 } 4071 4072 if (ReturnLength != NULL) 4073 { 4074 *ReturnLength = RequiredLength; 4075 } 4076 } 4077 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4078 { 4079 Status = _SEH2_GetExceptionCode(); 4080 } 4081 _SEH2_END; 4082 4083 break; 4084 } 4085 4086 case TokenStatistics: 4087 { 4088 PTOKEN_STATISTICS ts = (PTOKEN_STATISTICS)TokenInformation; 4089 4090 DPRINT("NtQueryInformationToken(TokenStatistics)\n"); 4091 RequiredLength = sizeof(TOKEN_STATISTICS); 4092 4093 _SEH2_TRY 4094 { 4095 if (TokenInformationLength >= RequiredLength) 4096 { 4097 ts->TokenId = Token->TokenId; 4098 ts->AuthenticationId = Token->AuthenticationId; 4099 ts->ExpirationTime = Token->ExpirationTime; 4100 ts->TokenType = Token->TokenType; 4101 ts->ImpersonationLevel = Token->ImpersonationLevel; 4102 ts->DynamicCharged = Token->DynamicCharged; 4103 ts->DynamicAvailable = Token->DynamicAvailable; 4104 ts->GroupCount = Token->UserAndGroupCount - 1; 4105 ts->PrivilegeCount = Token->PrivilegeCount; 4106 ts->ModifiedId = Token->ModifiedId; 4107 } 4108 else 4109 { 4110 Status = STATUS_BUFFER_TOO_SMALL; 4111 } 4112 4113 if (ReturnLength != NULL) 4114 { 4115 *ReturnLength = RequiredLength; 4116 } 4117 } 4118 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4119 { 4120 Status = _SEH2_GetExceptionCode(); 4121 } 4122 _SEH2_END; 4123 4124 break; 4125 } 4126 4127 case TokenOrigin: 4128 { 4129 PTOKEN_ORIGIN to = (PTOKEN_ORIGIN)TokenInformation; 4130 4131 DPRINT("NtQueryInformationToken(TokenOrigin)\n"); 4132 RequiredLength = sizeof(TOKEN_ORIGIN); 4133 4134 _SEH2_TRY 4135 { 4136 if (TokenInformationLength >= RequiredLength) 4137 { 4138 RtlCopyLuid(&to->OriginatingLogonSession, 4139 &Token->AuthenticationId); 4140 } 4141 else 4142 { 4143 Status = STATUS_BUFFER_TOO_SMALL; 4144 } 4145 4146 if (ReturnLength != NULL) 4147 { 4148 *ReturnLength = RequiredLength; 4149 } 4150 } 4151 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4152 { 4153 Status = _SEH2_GetExceptionCode(); 4154 } 4155 _SEH2_END; 4156 4157 break; 4158 } 4159 4160 case TokenGroupsAndPrivileges: 4161 DPRINT1("NtQueryInformationToken(TokenGroupsAndPrivileges) not implemented\n"); 4162 Status = STATUS_NOT_IMPLEMENTED; 4163 break; 4164 4165 case TokenRestrictedSids: 4166 { 4167 PTOKEN_GROUPS tg = (PTOKEN_GROUPS)TokenInformation; 4168 4169 DPRINT("NtQueryInformationToken(TokenRestrictedSids)\n"); 4170 RequiredLength = sizeof(tg->GroupCount) + 4171 RtlLengthSidAndAttributes(Token->RestrictedSidCount, Token->RestrictedSids); 4172 4173 _SEH2_TRY 4174 { 4175 if (TokenInformationLength >= RequiredLength) 4176 { 4177 ULONG SidLen = RequiredLength - sizeof(tg->GroupCount) - 4178 (Token->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES)); 4179 PSID Sid = (PSID)((ULONG_PTR)tg + sizeof(tg->GroupCount) + 4180 (Token->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES))); 4181 4182 tg->GroupCount = Token->RestrictedSidCount; 4183 Status = RtlCopySidAndAttributesArray(Token->RestrictedSidCount, 4184 Token->RestrictedSids, 4185 SidLen, 4186 &tg->Groups[0], 4187 Sid, 4188 &Unused.PSid, 4189 &Unused.Ulong); 4190 } 4191 else 4192 { 4193 Status = STATUS_BUFFER_TOO_SMALL; 4194 } 4195 4196 if (ReturnLength != NULL) 4197 { 4198 *ReturnLength = RequiredLength; 4199 } 4200 } 4201 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4202 { 4203 Status = _SEH2_GetExceptionCode(); 4204 } 4205 _SEH2_END; 4206 4207 break; 4208 } 4209 4210 case TokenSandBoxInert: 4211 DPRINT1("NtQueryInformationToken(TokenSandboxInert) not implemented\n"); 4212 Status = STATUS_NOT_IMPLEMENTED; 4213 break; 4214 4215 case TokenSessionId: 4216 { 4217 ULONG SessionId = 0; 4218 4219 DPRINT("NtQueryInformationToken(TokenSessionId)\n"); 4220 4221 Status = SeQuerySessionIdToken(Token, &SessionId); 4222 if (NT_SUCCESS(Status)) 4223 { 4224 _SEH2_TRY 4225 { 4226 /* Buffer size was already verified, no need to check here again */ 4227 *(PULONG)TokenInformation = SessionId; 4228 4229 if (ReturnLength != NULL) 4230 { 4231 *ReturnLength = sizeof(ULONG); 4232 } 4233 } 4234 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4235 { 4236 Status = _SEH2_GetExceptionCode(); 4237 } 4238 _SEH2_END; 4239 } 4240 4241 break; 4242 } 4243 4244 default: 4245 DPRINT1("NtQueryInformationToken(%d) invalid information class\n", TokenInformationClass); 4246 Status = STATUS_INVALID_INFO_CLASS; 4247 break; 4248 } 4249 4250 /* Unlock and dereference the token */ 4251 SepReleaseTokenLock(Token); 4252 ObDereferenceObject(Token); 4253 } 4254 4255 return Status; 4256 } 4257 4258 /** 4259 * @unimplemented 4260 * @brief 4261 * Sets (modifies) some specific information in regard of an access token. The 4262 * calling thread must have specific access rights in order to modify token's 4263 * information data. 4264 * 4265 * @param[in] TokenHandle 4266 * A handle of a token where information is to be modified. 4267 * 4268 * @param[in] TokenInformationClass 4269 * Token information class. 4270 * 4271 * @param[in] TokenInformation 4272 * An arbitrary pointer to a buffer with token information to set. Such 4273 * arbitrary buffer depends on the information class chosen that the caller 4274 * wants to modify such information data of a token. 4275 * 4276 * @param[in] TokenInformationLength 4277 * Length of the token information buffer, in bytes. 4278 * 4279 * @return 4280 * Returns STATUS_SUCCESS if information setting has completed successfully. 4281 * STATUS_INFO_LENGTH_MISMATCH is returned if the information length of the 4282 * buffer is less than the required length. STATUS_INSUFFICIENT_RESOURCES is 4283 * returned if memory pool allocation has failed. STATUS_PRIVILEGE_NOT_HELD 4284 * is returned if the calling thread hasn't the required privileges to perform 4285 * the operation in question. A failure NTSTATUS code is returned otherwise. 4286 * 4287 * @remarks 4288 * The function is partly implemented, mainly TokenOrigin and TokenDefaultDacl. 4289 */ 4290 _Must_inspect_result_ 4291 __kernel_entry 4292 NTSTATUS 4293 NTAPI 4294 NtSetInformationToken( 4295 _In_ HANDLE TokenHandle, 4296 _In_ TOKEN_INFORMATION_CLASS TokenInformationClass, 4297 _In_reads_bytes_(TokenInformationLength) PVOID TokenInformation, 4298 _In_ ULONG TokenInformationLength) 4299 { 4300 NTSTATUS Status; 4301 PTOKEN Token; 4302 KPROCESSOR_MODE PreviousMode; 4303 ULONG NeededAccess = TOKEN_ADJUST_DEFAULT; 4304 4305 PAGED_CODE(); 4306 4307 PreviousMode = ExGetPreviousMode(); 4308 4309 Status = DefaultSetInfoBufferCheck(TokenInformationClass, 4310 SeTokenInformationClass, 4311 RTL_NUMBER_OF(SeTokenInformationClass), 4312 TokenInformation, 4313 TokenInformationLength, 4314 PreviousMode); 4315 if (!NT_SUCCESS(Status)) 4316 { 4317 /* Invalid buffers */ 4318 DPRINT("NtSetInformationToken() failed, Status: 0x%x\n", Status); 4319 return Status; 4320 } 4321 4322 if (TokenInformationClass == TokenSessionId) 4323 { 4324 NeededAccess |= TOKEN_ADJUST_SESSIONID; 4325 } 4326 4327 Status = ObReferenceObjectByHandle(TokenHandle, 4328 NeededAccess, 4329 SeTokenObjectType, 4330 PreviousMode, 4331 (PVOID*)&Token, 4332 NULL); 4333 if (NT_SUCCESS(Status)) 4334 { 4335 switch (TokenInformationClass) 4336 { 4337 case TokenOwner: 4338 { 4339 if (TokenInformationLength >= sizeof(TOKEN_OWNER)) 4340 { 4341 PTOKEN_OWNER to = (PTOKEN_OWNER)TokenInformation; 4342 PSID InputSid = NULL, CapturedSid; 4343 ULONG DefaultOwnerIndex; 4344 4345 _SEH2_TRY 4346 { 4347 InputSid = to->Owner; 4348 } 4349 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4350 { 4351 Status = _SEH2_GetExceptionCode(); 4352 _SEH2_YIELD(goto Cleanup); 4353 } 4354 _SEH2_END; 4355 4356 Status = SepCaptureSid(InputSid, 4357 PreviousMode, 4358 PagedPool, 4359 FALSE, 4360 &CapturedSid); 4361 if (NT_SUCCESS(Status)) 4362 { 4363 /* Lock the token */ 4364 SepAcquireTokenLockExclusive(Token); 4365 4366 /* Find the owner amongst the existing token user and groups */ 4367 Status = SepFindPrimaryGroupAndDefaultOwner(Token, 4368 NULL, 4369 CapturedSid, 4370 NULL, 4371 &DefaultOwnerIndex); 4372 if (NT_SUCCESS(Status)) 4373 { 4374 /* Found it */ 4375 Token->DefaultOwnerIndex = DefaultOwnerIndex; 4376 ExAllocateLocallyUniqueId(&Token->ModifiedId); 4377 } 4378 4379 /* Unlock the token */ 4380 SepReleaseTokenLock(Token); 4381 4382 SepReleaseSid(CapturedSid, 4383 PreviousMode, 4384 FALSE); 4385 } 4386 } 4387 else 4388 { 4389 Status = STATUS_INFO_LENGTH_MISMATCH; 4390 } 4391 break; 4392 } 4393 4394 case TokenPrimaryGroup: 4395 { 4396 if (TokenInformationLength >= sizeof(TOKEN_PRIMARY_GROUP)) 4397 { 4398 PTOKEN_PRIMARY_GROUP tpg = (PTOKEN_PRIMARY_GROUP)TokenInformation; 4399 PSID InputSid = NULL, CapturedSid; 4400 ULONG PrimaryGroupIndex; 4401 4402 _SEH2_TRY 4403 { 4404 InputSid = tpg->PrimaryGroup; 4405 } 4406 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4407 { 4408 Status = _SEH2_GetExceptionCode(); 4409 _SEH2_YIELD(goto Cleanup); 4410 } 4411 _SEH2_END; 4412 4413 Status = SepCaptureSid(InputSid, 4414 PreviousMode, 4415 PagedPool, 4416 FALSE, 4417 &CapturedSid); 4418 if (NT_SUCCESS(Status)) 4419 { 4420 /* Lock the token */ 4421 SepAcquireTokenLockExclusive(Token); 4422 4423 /* Find the primary group amongst the existing token user and groups */ 4424 Status = SepFindPrimaryGroupAndDefaultOwner(Token, 4425 CapturedSid, 4426 NULL, 4427 &PrimaryGroupIndex, 4428 NULL); 4429 if (NT_SUCCESS(Status)) 4430 { 4431 /* Found it */ 4432 Token->PrimaryGroup = Token->UserAndGroups[PrimaryGroupIndex].Sid; 4433 ExAllocateLocallyUniqueId(&Token->ModifiedId); 4434 } 4435 4436 /* Unlock the token */ 4437 SepReleaseTokenLock(Token); 4438 4439 SepReleaseSid(CapturedSid, 4440 PreviousMode, 4441 FALSE); 4442 } 4443 } 4444 else 4445 { 4446 Status = STATUS_INFO_LENGTH_MISMATCH; 4447 } 4448 break; 4449 } 4450 4451 case TokenDefaultDacl: 4452 { 4453 if (TokenInformationLength >= sizeof(TOKEN_DEFAULT_DACL)) 4454 { 4455 PTOKEN_DEFAULT_DACL tdd = (PTOKEN_DEFAULT_DACL)TokenInformation; 4456 PACL InputAcl = NULL; 4457 4458 _SEH2_TRY 4459 { 4460 InputAcl = tdd->DefaultDacl; 4461 } 4462 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4463 { 4464 Status = _SEH2_GetExceptionCode(); 4465 _SEH2_YIELD(goto Cleanup); 4466 } 4467 _SEH2_END; 4468 4469 if (InputAcl != NULL) 4470 { 4471 PACL CapturedAcl; 4472 4473 /* Capture and copy the dacl */ 4474 Status = SepCaptureAcl(InputAcl, 4475 PreviousMode, 4476 PagedPool, 4477 TRUE, 4478 &CapturedAcl); 4479 if (NT_SUCCESS(Status)) 4480 { 4481 ULONG DynamicLength; 4482 4483 /* Lock the token */ 4484 SepAcquireTokenLockExclusive(Token); 4485 4486 // 4487 // NOTE: So far our dynamic area only contains 4488 // the default dacl, so this makes the following 4489 // code pretty simple. The day where it stores 4490 // other data, the code will require adaptations. 4491 // 4492 4493 DynamicLength = Token->DynamicAvailable; 4494 // Add here any other data length present in the dynamic area... 4495 if (Token->DefaultDacl) 4496 DynamicLength += Token->DefaultDacl->AclSize; 4497 4498 /* Reallocate the dynamic area if it is too small */ 4499 Status = STATUS_SUCCESS; 4500 if ((DynamicLength < CapturedAcl->AclSize) || 4501 (Token->DynamicPart == NULL)) 4502 { 4503 PVOID NewDynamicPart; 4504 4505 NewDynamicPart = ExAllocatePoolWithTag(PagedPool, 4506 CapturedAcl->AclSize, 4507 TAG_TOKEN_DYNAMIC); 4508 if (NewDynamicPart == NULL) 4509 { 4510 Status = STATUS_INSUFFICIENT_RESOURCES; 4511 } 4512 else 4513 { 4514 if (Token->DynamicPart != NULL) 4515 { 4516 // RtlCopyMemory(NewDynamicPart, Token->DynamicPart, DynamicLength); 4517 ExFreePoolWithTag(Token->DynamicPart, TAG_TOKEN_DYNAMIC); 4518 } 4519 Token->DynamicPart = NewDynamicPart; 4520 Token->DynamicAvailable = 0; 4521 } 4522 } 4523 else 4524 { 4525 Token->DynamicAvailable = DynamicLength - CapturedAcl->AclSize; 4526 } 4527 4528 if (NT_SUCCESS(Status)) 4529 { 4530 /* Set the new dacl */ 4531 Token->DefaultDacl = (PVOID)Token->DynamicPart; 4532 RtlCopyMemory(Token->DefaultDacl, 4533 CapturedAcl, 4534 CapturedAcl->AclSize); 4535 4536 ExAllocateLocallyUniqueId(&Token->ModifiedId); 4537 } 4538 4539 /* Unlock the token */ 4540 SepReleaseTokenLock(Token); 4541 4542 ExFreePoolWithTag(CapturedAcl, TAG_ACL); 4543 } 4544 } 4545 else 4546 { 4547 /* Lock the token */ 4548 SepAcquireTokenLockExclusive(Token); 4549 4550 /* Clear the default dacl if present */ 4551 if (Token->DefaultDacl != NULL) 4552 { 4553 Token->DynamicAvailable += Token->DefaultDacl->AclSize; 4554 RtlZeroMemory(Token->DefaultDacl, Token->DefaultDacl->AclSize); 4555 Token->DefaultDacl = NULL; 4556 4557 ExAllocateLocallyUniqueId(&Token->ModifiedId); 4558 } 4559 4560 /* Unlock the token */ 4561 SepReleaseTokenLock(Token); 4562 } 4563 } 4564 else 4565 { 4566 Status = STATUS_INFO_LENGTH_MISMATCH; 4567 } 4568 break; 4569 } 4570 4571 case TokenSessionId: 4572 { 4573 ULONG SessionId = 0; 4574 4575 _SEH2_TRY 4576 { 4577 /* Buffer size was already verified, no need to check here again */ 4578 SessionId = *(PULONG)TokenInformation; 4579 } 4580 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4581 { 4582 Status = _SEH2_GetExceptionCode(); 4583 _SEH2_YIELD(goto Cleanup); 4584 } 4585 _SEH2_END; 4586 4587 /* Check for TCB privilege */ 4588 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode)) 4589 { 4590 Status = STATUS_PRIVILEGE_NOT_HELD; 4591 break; 4592 } 4593 4594 /* Lock the token */ 4595 SepAcquireTokenLockExclusive(Token); 4596 4597 Token->SessionId = SessionId; 4598 ExAllocateLocallyUniqueId(&Token->ModifiedId); 4599 4600 /* Unlock the token */ 4601 SepReleaseTokenLock(Token); 4602 4603 break; 4604 } 4605 4606 case TokenSessionReference: 4607 { 4608 ULONG SessionReference; 4609 4610 _SEH2_TRY 4611 { 4612 /* Buffer size was already verified, no need to check here again */ 4613 SessionReference = *(PULONG)TokenInformation; 4614 } 4615 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4616 { 4617 Status = _SEH2_GetExceptionCode(); 4618 _SEH2_YIELD(goto Cleanup); 4619 } 4620 _SEH2_END; 4621 4622 /* Check for TCB privilege */ 4623 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode)) 4624 { 4625 Status = STATUS_PRIVILEGE_NOT_HELD; 4626 goto Cleanup; 4627 } 4628 4629 /* Check if it is 0 */ 4630 if (SessionReference == 0) 4631 { 4632 ULONG OldTokenFlags; 4633 4634 /* Lock the token */ 4635 SepAcquireTokenLockExclusive(Token); 4636 4637 /* Atomically set the flag in the token */ 4638 OldTokenFlags = RtlInterlockedSetBits(&Token->TokenFlags, 4639 TOKEN_SESSION_NOT_REFERENCED); 4640 /* 4641 * If the flag was already set, do not dereference again 4642 * the logon session. Use SessionReference as an indicator 4643 * to know whether to really dereference the session. 4644 */ 4645 if (OldTokenFlags == Token->TokenFlags) 4646 SessionReference = ULONG_MAX; 4647 4648 /* 4649 * Otherwise if the flag was never set but just for this first time then 4650 * remove the referenced logon session data from the token and dereference 4651 * the logon session when needed. 4652 */ 4653 if (SessionReference == 0) 4654 { 4655 SepRmRemoveLogonSessionFromToken(Token); 4656 SepRmDereferenceLogonSession(&Token->AuthenticationId); 4657 } 4658 4659 /* Unlock the token */ 4660 SepReleaseTokenLock(Token); 4661 } 4662 break; 4663 } 4664 4665 case TokenAuditPolicy: 4666 { 4667 PTOKEN_AUDIT_POLICY_INFORMATION PolicyInformation = 4668 (PTOKEN_AUDIT_POLICY_INFORMATION)TokenInformation; 4669 SEP_AUDIT_POLICY AuditPolicy; 4670 ULONG i; 4671 4672 _SEH2_TRY 4673 { 4674 ProbeForRead(PolicyInformation, 4675 FIELD_OFFSET(TOKEN_AUDIT_POLICY_INFORMATION, 4676 Policies[PolicyInformation->PolicyCount]), 4677 sizeof(ULONG)); 4678 4679 /* Loop all policies in the structure */ 4680 for (i = 0; i < PolicyInformation->PolicyCount; i++) 4681 { 4682 /* Set the corresponding bits in the packed structure */ 4683 switch (PolicyInformation->Policies[i].Category) 4684 { 4685 case AuditCategorySystem: 4686 AuditPolicy.PolicyElements.System = PolicyInformation->Policies[i].Value; 4687 break; 4688 4689 case AuditCategoryLogon: 4690 AuditPolicy.PolicyElements.Logon = PolicyInformation->Policies[i].Value; 4691 break; 4692 4693 case AuditCategoryObjectAccess: 4694 AuditPolicy.PolicyElements.ObjectAccess = PolicyInformation->Policies[i].Value; 4695 break; 4696 4697 case AuditCategoryPrivilegeUse: 4698 AuditPolicy.PolicyElements.PrivilegeUse = PolicyInformation->Policies[i].Value; 4699 break; 4700 4701 case AuditCategoryDetailedTracking: 4702 AuditPolicy.PolicyElements.DetailedTracking = PolicyInformation->Policies[i].Value; 4703 break; 4704 4705 case AuditCategoryPolicyChange: 4706 AuditPolicy.PolicyElements.PolicyChange = PolicyInformation->Policies[i].Value; 4707 break; 4708 4709 case AuditCategoryAccountManagement: 4710 AuditPolicy.PolicyElements.AccountManagement = PolicyInformation->Policies[i].Value; 4711 break; 4712 4713 case AuditCategoryDirectoryServiceAccess: 4714 AuditPolicy.PolicyElements.DirectoryServiceAccess = PolicyInformation->Policies[i].Value; 4715 break; 4716 4717 case AuditCategoryAccountLogon: 4718 AuditPolicy.PolicyElements.AccountLogon = PolicyInformation->Policies[i].Value; 4719 break; 4720 } 4721 } 4722 } 4723 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4724 { 4725 Status = _SEH2_GetExceptionCode(); 4726 _SEH2_YIELD(goto Cleanup); 4727 } 4728 _SEH2_END; 4729 4730 /* Check for TCB privilege */ 4731 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode)) 4732 { 4733 Status = STATUS_PRIVILEGE_NOT_HELD; 4734 break; 4735 } 4736 4737 /* Lock the token */ 4738 SepAcquireTokenLockExclusive(Token); 4739 4740 /* Set the new audit policy */ 4741 Token->AuditPolicy = AuditPolicy; 4742 ExAllocateLocallyUniqueId(&Token->ModifiedId); 4743 4744 /* Unlock the token */ 4745 SepReleaseTokenLock(Token); 4746 4747 break; 4748 } 4749 4750 case TokenOrigin: 4751 { 4752 TOKEN_ORIGIN TokenOrigin; 4753 4754 _SEH2_TRY 4755 { 4756 /* Copy the token origin */ 4757 TokenOrigin = *(PTOKEN_ORIGIN)TokenInformation; 4758 } 4759 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4760 { 4761 Status = _SEH2_GetExceptionCode(); 4762 _SEH2_YIELD(goto Cleanup); 4763 } 4764 _SEH2_END; 4765 4766 /* Check for TCB privilege */ 4767 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode)) 4768 { 4769 Status = STATUS_PRIVILEGE_NOT_HELD; 4770 break; 4771 } 4772 4773 /* Lock the token */ 4774 SepAcquireTokenLockExclusive(Token); 4775 4776 /* Check if there is no token origin set yet */ 4777 if (RtlIsZeroLuid(&Token->OriginatingLogonSession)) 4778 { 4779 /* Set the token origin */ 4780 Token->OriginatingLogonSession = 4781 TokenOrigin.OriginatingLogonSession; 4782 4783 ExAllocateLocallyUniqueId(&Token->ModifiedId); 4784 } 4785 4786 /* Unlock the token */ 4787 SepReleaseTokenLock(Token); 4788 4789 break; 4790 } 4791 4792 default: 4793 { 4794 DPRINT1("Invalid TokenInformationClass: 0x%lx\n", 4795 TokenInformationClass); 4796 Status = STATUS_INVALID_INFO_CLASS; 4797 break; 4798 } 4799 } 4800 Cleanup: 4801 ObDereferenceObject(Token); 4802 } 4803 4804 if (!NT_SUCCESS(Status)) 4805 { 4806 DPRINT1("NtSetInformationToken failed with Status 0x%lx\n", Status); 4807 } 4808 4809 return Status; 4810 } 4811 4812 /** 4813 * @brief 4814 * Duplicates a token. 4815 * 4816 * @param[in] ExistingTokenHandle 4817 * An existing token to duplicate. 4818 * 4819 * @param[in] DesiredAccess 4820 * The desired access rights for the new duplicated token. 4821 * 4822 * @param[in] ObjectAttributes 4823 * Object attributes for the new duplicated token. 4824 * 4825 * @param[in] EffectiveOnly 4826 * If set to TRUE, the function removes all the disabled privileges and groups 4827 * of the token to duplicate. 4828 * 4829 * @param[in] TokenType 4830 * Type of token to assign to the duplicated token. 4831 * 4832 * @param[out] NewTokenHandle 4833 * The returned duplicated token handle. 4834 * 4835 * @return 4836 * STATUS_SUCCESS is returned if token duplication has completed successfully. 4837 * STATUS_BAD_IMPERSONATION_LEVEL is returned if the caller erroneously wants 4838 * to raise the impersonation level even though the conditions do not permit 4839 * it. A failure NTSTATUS code is returned otherwise. 4840 * 4841 * @remarks 4842 * Some sources claim 4th param is ImpersonationLevel, but on W2K 4843 * this is certainly NOT true, although I can't say for sure that EffectiveOnly 4844 * is correct either. -Gunnar 4845 * This is true. EffectiveOnly overrides SQOS.EffectiveOnly. - IAI 4846 * NOTE for readers: http://hex.pp.ua/nt/NtDuplicateToken.php is therefore 4847 * wrong in that regard, while MSDN documentation is correct. 4848 */ 4849 _Must_inspect_result_ 4850 __kernel_entry 4851 NTSTATUS 4852 NTAPI 4853 NtDuplicateToken( 4854 _In_ HANDLE ExistingTokenHandle, 4855 _In_ ACCESS_MASK DesiredAccess, 4856 _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, 4857 _In_ BOOLEAN EffectiveOnly, 4858 _In_ TOKEN_TYPE TokenType, 4859 _Out_ PHANDLE NewTokenHandle) 4860 { 4861 KPROCESSOR_MODE PreviousMode; 4862 HANDLE hToken; 4863 PTOKEN Token; 4864 PTOKEN NewToken; 4865 PSECURITY_QUALITY_OF_SERVICE CapturedSecurityQualityOfService; 4866 BOOLEAN QoSPresent; 4867 OBJECT_HANDLE_INFORMATION HandleInformation; 4868 NTSTATUS Status; 4869 4870 PAGED_CODE(); 4871 4872 if (TokenType != TokenImpersonation && 4873 TokenType != TokenPrimary) 4874 { 4875 return STATUS_INVALID_PARAMETER; 4876 } 4877 4878 PreviousMode = KeGetPreviousMode(); 4879 4880 if (PreviousMode != KernelMode) 4881 { 4882 _SEH2_TRY 4883 { 4884 ProbeForWriteHandle(NewTokenHandle); 4885 } 4886 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4887 { 4888 /* Return the exception code */ 4889 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 4890 } 4891 _SEH2_END; 4892 } 4893 4894 Status = SepCaptureSecurityQualityOfService(ObjectAttributes, 4895 PreviousMode, 4896 PagedPool, 4897 FALSE, 4898 &CapturedSecurityQualityOfService, 4899 &QoSPresent); 4900 if (!NT_SUCCESS(Status)) 4901 { 4902 DPRINT1("NtDuplicateToken() failed to capture QoS! Status: 0x%x\n", Status); 4903 return Status; 4904 } 4905 4906 Status = ObReferenceObjectByHandle(ExistingTokenHandle, 4907 TOKEN_DUPLICATE, 4908 SeTokenObjectType, 4909 PreviousMode, 4910 (PVOID*)&Token, 4911 &HandleInformation); 4912 if (!NT_SUCCESS(Status)) 4913 { 4914 DPRINT1("Failed to reference token (Status 0x%lx)\n", Status); 4915 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService, 4916 PreviousMode, 4917 FALSE); 4918 return Status; 4919 } 4920 4921 /* 4922 * Fail, if the original token is an impersonation token and the caller 4923 * tries to raise the impersonation level of the new token above the 4924 * impersonation level of the original token. 4925 */ 4926 if (Token->TokenType == TokenImpersonation) 4927 { 4928 if (QoSPresent && 4929 CapturedSecurityQualityOfService->ImpersonationLevel >Token->ImpersonationLevel) 4930 { 4931 ObDereferenceObject(Token); 4932 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService, 4933 PreviousMode, 4934 FALSE); 4935 return STATUS_BAD_IMPERSONATION_LEVEL; 4936 } 4937 } 4938 4939 /* 4940 * Fail, if a primary token is to be created from an impersonation token 4941 * and and the impersonation level of the impersonation token is below SecurityImpersonation. 4942 */ 4943 if (Token->TokenType == TokenImpersonation && 4944 TokenType == TokenPrimary && 4945 Token->ImpersonationLevel < SecurityImpersonation) 4946 { 4947 ObDereferenceObject(Token); 4948 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService, 4949 PreviousMode, 4950 FALSE); 4951 return STATUS_BAD_IMPERSONATION_LEVEL; 4952 } 4953 4954 Status = SepDuplicateToken(Token, 4955 ObjectAttributes, 4956 EffectiveOnly, 4957 TokenType, 4958 (QoSPresent ? CapturedSecurityQualityOfService->ImpersonationLevel : SecurityAnonymous), 4959 PreviousMode, 4960 &NewToken); 4961 4962 ObDereferenceObject(Token); 4963 4964 if (NT_SUCCESS(Status)) 4965 { 4966 Status = ObInsertObject(NewToken, 4967 NULL, 4968 (DesiredAccess ? DesiredAccess : HandleInformation.GrantedAccess), 4969 0, 4970 NULL, 4971 &hToken); 4972 if (NT_SUCCESS(Status)) 4973 { 4974 _SEH2_TRY 4975 { 4976 *NewTokenHandle = hToken; 4977 } 4978 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 4979 { 4980 Status = _SEH2_GetExceptionCode(); 4981 } 4982 _SEH2_END; 4983 } 4984 } 4985 4986 /* Free the captured structure */ 4987 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService, 4988 PreviousMode, 4989 FALSE); 4990 4991 return Status; 4992 } 4993 4994 /** 4995 * @brief 4996 * Private routine that iterates over the groups of an 4997 * access token to be adjusted as per on request by the 4998 * caller, where a group can be enabled or disabled. 4999 * 5000 * @param[in] Token 5001 * Access token where its groups are to be enabled or disabled. 5002 * 5003 * @param[in] NewState 5004 * A list of groups with new state attributes to be assigned to 5005 * the token. 5006 * 5007 * @param[in] NewStateCount 5008 * The captured count number of groups in the list. 5009 * 5010 * @param[in] ApplyChanges 5011 * If set to FALSE, the function will only iterate over the token's 5012 * groups without performing any kind of modification. If set to TRUE, 5013 * the changes will be applied immediately when the function has done 5014 * looping the groups. 5015 * 5016 * @param[in] ResetToDefaultStates 5017 * The function will reset the groups in an access token to default 5018 * states if set to TRUE. In such scenario the function ignores 5019 * NewState outright. Otherwise if set to FALSE, the function will 5020 * use NewState to assign the newly attributes to adjust the token's 5021 * groups. SE_GROUP_ENABLED_BY_DEFAULT is a flag indicator that is used 5022 * for such purpose. 5023 * 5024 * @param[out] ChangesMade 5025 * Returns TRUE if changes to token's groups have been made, otherwise 5026 * FALSE is returned. Bear in mind such changes aren't always deterministic. 5027 * See remarks for further details. 5028 * 5029 * @param[out] PreviousGroupsState 5030 * If requested by the caller, the function will return the previous state 5031 * of groups in an access token prior taking action on adjusting the token. 5032 * This is a UM (user mode) pointer and it's prone to raise exceptions 5033 * if such pointer address is not valid. 5034 * 5035 * @param[out] ChangedGroups 5036 * Returns the total number of changed groups in an access token. This 5037 * argument could also indicate the number of groups to be changed if 5038 * the calling thread hasn't chosen to apply the changes yet. A number 5039 * of 0 indicates no groups have been or to be changed because the groups' 5040 * attributes in a token are the same as the ones from NewState given by 5041 * the caller. 5042 * 5043 * @return 5044 * STATUS_SUCCESS is returned if the function has successfully completed 5045 * the operation of adjusting groups in a token. STATUS_CANT_DISABLE_MANDATORY 5046 * is returned if there was an attempt to disable a mandatory group which is 5047 * not possible. STATUS_CANT_ENABLE_DENY_ONLY is returned if there was an attempt 5048 * to enable a "use for Deny only" group which is not allowed, that is, a restricted 5049 * group. STATUS_NOT_ALL_ASSIGNED is returned if not all the groups are actually 5050 * assigned to the token. 5051 * 5052 * @remarks 5053 * Token groups adjusting can be judged to be deterministic or not based on the 5054 * NT status code value. That is, STATUS_SUCCESS indicates the function not only 5055 * has iterated over the whole groups in a token, it also has applied the changes 5056 * thoroughly without impediment and the results perfectly match with the request 5057 * desired by the caller. In this situation the condition is deemed deterministic. 5058 * In a different situation however, if the status code was STATUS_NOT_ALL_ASSIGNED, 5059 * the function would still continue looping the groups in a token and apply the 5060 * changes whenever possible where the respective groups actually exist in the 5061 * token. This kind of situation is deemed as indeterministic. 5062 * For STATUS_CANT_DISABLE_MANDATORY and STATUS_CANT_ENABLE_DENY_ONLY the scenario 5063 * is even more indeterministic as the iteration of groups comes to a halt thus 5064 * leaving all other possible groups to be adjusted. 5065 */ 5066 static 5067 NTSTATUS 5068 SepAdjustGroups( 5069 _In_ PTOKEN Token, 5070 _In_opt_ PSID_AND_ATTRIBUTES NewState, 5071 _In_ ULONG NewStateCount, 5072 _In_ BOOLEAN ApplyChanges, 5073 _In_ BOOLEAN ResetToDefaultStates, 5074 _Out_ PBOOLEAN ChangesMade, 5075 _Out_opt_ PTOKEN_GROUPS PreviousGroupsState, 5076 _Out_ PULONG ChangedGroups) 5077 { 5078 ULONG GroupsInToken, GroupsInList; 5079 ULONG ChangeCount, GroupsCount, NewAttributes; 5080 5081 PAGED_CODE(); 5082 5083 /* Ensure that the token we get is not plain garbage */ 5084 ASSERT(Token); 5085 5086 /* Initialize the counters and begin the work */ 5087 *ChangesMade = FALSE; 5088 GroupsCount = 0; 5089 ChangeCount = 0; 5090 5091 /* Begin looping all the groups in the token */ 5092 for (GroupsInToken = 0; GroupsInToken < Token->UserAndGroupCount; GroupsInToken++) 5093 { 5094 /* Does the caller want to reset groups to default states? */ 5095 if (ResetToDefaultStates) 5096 { 5097 /* 5098 * SE_GROUP_ENABLED_BY_DEFAULT is a special indicator that informs us 5099 * if a certain group has been enabled by default or not. In case 5100 * a group is enabled by default but it is not currently enabled then 5101 * at that point we must enable it back by default. For now just 5102 * assign the respective SE_GROUP_ENABLED attribute as we'll do the 5103 * eventual work later. 5104 */ 5105 if ((Token->UserAndGroups[GroupsInToken].Attributes & SE_GROUP_ENABLED_BY_DEFAULT) && 5106 (Token->UserAndGroups[GroupsInToken].Attributes & SE_GROUP_ENABLED) == 0) 5107 { 5108 NewAttributes = Token->UserAndGroups[GroupsInToken].Attributes |= SE_GROUP_ENABLED; 5109 } 5110 5111 /* 5112 * Unlike the case above, a group that hasn't been enabled by 5113 * default but it's currently enabled then we must disable 5114 * it back. 5115 */ 5116 if ((Token->UserAndGroups[GroupsInToken].Attributes & SE_GROUP_ENABLED_BY_DEFAULT) == 0 && 5117 (Token->UserAndGroups[GroupsInToken].Attributes & SE_GROUP_ENABLED)) 5118 { 5119 NewAttributes = Token->UserAndGroups[GroupsInToken].Attributes & ~SE_GROUP_ENABLED; 5120 } 5121 } 5122 else 5123 { 5124 /* Loop the provided groups in the list then */ 5125 for (GroupsInList = 0; GroupsInList < NewStateCount; GroupsInList++) 5126 { 5127 /* Does this group exist in the token? */ 5128 if (RtlEqualSid(&Token->UserAndGroups[GroupsInToken].Sid, 5129 &NewState[GroupsInList].Sid)) 5130 { 5131 /* 5132 * This is the group that we're looking for. 5133 * However, it could be that the group is a 5134 * mandatory group which we are not allowed 5135 * and cannot disable it. 5136 */ 5137 if ((Token->UserAndGroups[GroupsInToken].Attributes & SE_GROUP_MANDATORY) && 5138 (NewState[GroupsInList].Attributes & SE_GROUP_ENABLED) == 0) 5139 { 5140 /* It is mandatory, forget about this group */ 5141 DPRINT1("SepAdjustGroups(): The SID group is mandatory!\n"); 5142 return STATUS_CANT_DISABLE_MANDATORY; 5143 } 5144 5145 /* 5146 * We've to ensure that apart the group mustn't be 5147 * mandatory, it mustn't be a restricted group as 5148 * well. That is, the group is marked with 5149 * SE_GROUP_USE_FOR_DENY_ONLY flag and no one 5150 * can enable it because it's for "deny" use only. 5151 */ 5152 if ((Token->UserAndGroups[GroupsInToken].Attributes & SE_GROUP_USE_FOR_DENY_ONLY) && 5153 (NewState[GroupsInList].Attributes & SE_GROUP_ENABLED)) 5154 { 5155 /* This group is restricted, forget about it */ 5156 DPRINT1("SepAdjustGroups(): The SID group is for use deny only!\n"); 5157 return STATUS_CANT_ENABLE_DENY_ONLY; 5158 } 5159 5160 /* Copy the attributes and stop searching */ 5161 NewAttributes = NewState[GroupsInList].Attributes; 5162 NewAttributes &= SE_GROUP_ENABLED; 5163 NewAttributes = Token->UserAndGroups[GroupsInToken].Attributes & ~SE_GROUP_ENABLED; 5164 break; 5165 } 5166 5167 /* Did we find the specific group we wanted? */ 5168 if (GroupsInList == NewStateCount) 5169 { 5170 /* We didn't, continue with the next token's group */ 5171 continue; 5172 } 5173 } 5174 5175 /* Count the group that we found it */ 5176 GroupsCount++; 5177 5178 /* Does the token have the same attributes as the caller requested them? */ 5179 if (Token->UserAndGroups[GroupsInToken].Attributes != NewAttributes) 5180 { 5181 /* 5182 * No, then it's time to make some adjustment to the 5183 * token's groups. Does the caller want the previous states 5184 * of groups? 5185 */ 5186 if (PreviousGroupsState != NULL) 5187 { 5188 PreviousGroupsState->Groups[ChangeCount] = Token->UserAndGroups[GroupsInToken]; 5189 } 5190 5191 /* Time to apply the changes now? */ 5192 if (ApplyChanges) 5193 { 5194 /* The caller gave us consent, apply and report that we made changes! */ 5195 Token->UserAndGroups[GroupsInToken].Attributes = NewAttributes; 5196 *ChangesMade = TRUE; 5197 } 5198 5199 /* Increment the count change */ 5200 ChangeCount++; 5201 } 5202 } 5203 } 5204 5205 /* Report the number of previous saved groups */ 5206 if (PreviousGroupsState != NULL) 5207 { 5208 PreviousGroupsState->GroupCount = ChangeCount; 5209 } 5210 5211 /* Report the number of changed groups */ 5212 *ChangedGroups = ChangeCount; 5213 5214 /* Did we miss some groups? */ 5215 if (!ResetToDefaultStates && (GroupsCount < NewStateCount)) 5216 { 5217 /* 5218 * If we're at this stage then we are in a situation 5219 * where the adjust changes done to token's groups is 5220 * not deterministic as the caller might have wanted 5221 * as per NewState parameter. 5222 */ 5223 DPRINT1("SepAdjustGroups(): The token hasn't all the groups assigned!\n"); 5224 return STATUS_NOT_ALL_ASSIGNED; 5225 } 5226 5227 return STATUS_SUCCESS; 5228 } 5229 5230 /** 5231 * @brief 5232 * Changes the list of groups by enabling or disabling them 5233 * in an access token. Unlike NtAdjustPrivilegesToken, 5234 * this API routine does not remove groups. 5235 * 5236 * @param[in] TokenHandle 5237 * Token handle where the list of groups SID are to be adjusted. 5238 * The access token must have TOKEN_ADJUST_GROUPS access right 5239 * in order to change the groups in a token. The token must also 5240 * have TOKEN_QUERY access right if the caller requests the previous 5241 * states of groups list, that is, PreviousState is not NULL. 5242 * 5243 * @param[in] ResetToDefault 5244 * If set to TRUE, the function resets the list of groups to default 5245 * enabled and disabled states. NewState is ignored in this case. 5246 * Otherwise if the parameter is set to FALSE, the function expects 5247 * a new list of groups from NewState to be adjusted within the token. 5248 * 5249 * @param[in] NewState 5250 * A new list of groups SID that the function will use it accordingly to 5251 * modify the current list of groups SID of a token. 5252 * 5253 * @param[in] BufferLength 5254 * The length size of the buffer that is pointed by the NewState parameter 5255 * argument, in bytes. 5256 * 5257 * @param[out] PreviousState 5258 * If specified, the function will return to the caller the old list of groups 5259 * SID. If this parameter is NULL, ReturnLength must also be NULL. 5260 * 5261 * @param[out] ReturnLength 5262 * If specified, the function will return the total size length of the old list 5263 * of groups SIDs, in bytes. 5264 * 5265 * @return 5266 * STATUS_SUCCESS is returned if the function has successfully adjusted the 5267 * token's groups. STATUS_INVALID_PARAMETER is returned if the caller has 5268 * submitted one or more invalid parameters, that is, the caller didn't want 5269 * to reset the groups to default state but no NewState argument list has been 5270 * provided. STATUS_BUFFER_TOO_SMALL is returned if the buffer length given 5271 * by the caller is smaller than the required length size. A failure NTSTATUS 5272 * code is returned otherwise. 5273 */ 5274 NTSTATUS 5275 NTAPI 5276 NtAdjustGroupsToken( 5277 _In_ HANDLE TokenHandle, 5278 _In_ BOOLEAN ResetToDefault, 5279 _In_ PTOKEN_GROUPS NewState, 5280 _In_ ULONG BufferLength, 5281 _Out_writes_bytes_to_opt_(BufferLength, *ReturnLength) 5282 PTOKEN_GROUPS PreviousState, 5283 _When_(PreviousState != NULL, _Out_) PULONG ReturnLength) 5284 { 5285 PTOKEN Token; 5286 NTSTATUS Status; 5287 KPROCESSOR_MODE PreviousMode; 5288 ULONG ChangeCount, RequiredLength; 5289 ULONG CapturedCount = 0; 5290 ULONG CapturedLength = 0; 5291 ULONG NewStateSize = 0; 5292 PSID_AND_ATTRIBUTES CapturedGroups = NULL; 5293 BOOLEAN ChangesMade = FALSE; 5294 BOOLEAN LockAndReferenceAcquired = FALSE; 5295 5296 PAGED_CODE(); 5297 5298 /* 5299 * If the caller doesn't want to reset the groups of an 5300 * access token to default states then at least we must 5301 * expect a list of groups to be adjusted based on NewState 5302 * parameter. Otherwise bail out because the caller has 5303 * no idea what they're doing. 5304 */ 5305 if (!ResetToDefault && !NewState) 5306 { 5307 DPRINT1("NtAdjustGroupsToken(): The caller hasn't provided any list of groups to adjust!\n"); 5308 return STATUS_INVALID_PARAMETER; 5309 } 5310 5311 PreviousMode = ExGetPreviousMode(); 5312 5313 if (PreviousMode != KernelMode) 5314 { 5315 _SEH2_TRY 5316 { 5317 /* Probe NewState */ 5318 if (!ResetToDefault) 5319 { 5320 /* Probe the header */ 5321 ProbeForRead(NewState, sizeof(*NewState), sizeof(ULONG)); 5322 5323 CapturedCount = NewState->GroupCount; 5324 NewStateSize = FIELD_OFFSET(TOKEN_GROUPS, Groups[CapturedCount]); 5325 5326 ProbeForRead(NewState, NewStateSize, sizeof(ULONG)); 5327 } 5328 5329 if (PreviousState != NULL) 5330 { 5331 ProbeForWrite(PreviousState, BufferLength, sizeof(ULONG)); 5332 ProbeForWrite(ReturnLength, sizeof(*ReturnLength), sizeof(ULONG)); 5333 } 5334 } 5335 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 5336 { 5337 /* Return the exception code */ 5338 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 5339 } 5340 _SEH2_END; 5341 } 5342 else 5343 { 5344 /* 5345 * We're calling directly from the kernel, just retrieve 5346 * the number count of captured groups outright. 5347 */ 5348 if (!ResetToDefault) 5349 { 5350 CapturedCount = NewState->GroupCount; 5351 } 5352 } 5353 5354 /* Time to capture the NewState list */ 5355 if (!ResetToDefault) 5356 { 5357 _SEH2_TRY 5358 { 5359 Status = SeCaptureSidAndAttributesArray(NewState->Groups, 5360 CapturedCount, 5361 PreviousMode, 5362 NULL, 5363 0, 5364 PagedPool, 5365 TRUE, 5366 &CapturedGroups, 5367 &CapturedLength); 5368 } 5369 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 5370 { 5371 Status = _SEH2_GetExceptionCode(); 5372 } 5373 _SEH2_END; 5374 5375 if (!NT_SUCCESS(Status)) 5376 { 5377 DPRINT1("NtAdjustGroupsToken(): Failed to capture the NewState list of groups (Status 0x%lx)\n", Status); 5378 return Status; 5379 } 5380 } 5381 5382 /* Time to reference the token */ 5383 Status = ObReferenceObjectByHandle(TokenHandle, 5384 TOKEN_ADJUST_GROUPS | (PreviousState != NULL ? TOKEN_QUERY : 0), 5385 SeTokenObjectType, 5386 PreviousMode, 5387 (PVOID*)&Token, 5388 NULL); 5389 if (!NT_SUCCESS(Status)) 5390 { 5391 /* We couldn't reference the access token, bail out */ 5392 DPRINT1("NtAdjustGroupsToken(): Failed to reference the token (Status 0x%lx)\n", Status); 5393 5394 if (CapturedGroups != NULL) 5395 { 5396 SeReleaseSidAndAttributesArray(CapturedGroups, 5397 PreviousMode, 5398 TRUE); 5399 } 5400 5401 goto Quit; 5402 } 5403 5404 /* Lock the token */ 5405 SepAcquireTokenLockExclusive(Token); 5406 LockAndReferenceAcquired = TRUE; 5407 5408 /* Count the number of groups to be changed */ 5409 Status = SepAdjustGroups(Token, 5410 CapturedGroups, 5411 CapturedCount, 5412 FALSE, 5413 ResetToDefault, 5414 &ChangesMade, 5415 NULL, 5416 &ChangeCount); 5417 5418 /* Does the caller want the previous state of groups? */ 5419 if (PreviousState != NULL) 5420 { 5421 /* Calculate the required length */ 5422 RequiredLength = FIELD_OFFSET(TOKEN_GROUPS, Groups[ChangeCount]); 5423 5424 /* Return the required length to the caller */ 5425 _SEH2_TRY 5426 { 5427 *ReturnLength = RequiredLength; 5428 } 5429 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 5430 { 5431 /* Bail out and return the exception code */ 5432 Status = _SEH2_GetExceptionCode(); 5433 _SEH2_YIELD(goto Quit); 5434 } 5435 _SEH2_END; 5436 5437 /* The buffer length provided is smaller than the required length, bail out */ 5438 if (BufferLength < RequiredLength) 5439 { 5440 Status = STATUS_BUFFER_TOO_SMALL; 5441 goto Quit; 5442 } 5443 } 5444 5445 /* 5446 * Now it's time to apply changes. Wrap the code 5447 * in SEH as we are returning the old groups state 5448 * list to the caller since PreviousState is a 5449 * UM pointer. 5450 */ 5451 _SEH2_TRY 5452 { 5453 Status = SepAdjustGroups(Token, 5454 CapturedGroups, 5455 CapturedCount, 5456 TRUE, 5457 ResetToDefault, 5458 &ChangesMade, 5459 PreviousState, 5460 &ChangeCount); 5461 } 5462 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 5463 { 5464 /* Bail out and return the exception code */ 5465 Status = _SEH2_GetExceptionCode(); 5466 5467 /* Force the write as we touched the token still */ 5468 ChangesMade = TRUE; 5469 _SEH2_YIELD(goto Quit); 5470 } 5471 _SEH2_END; 5472 5473 Quit: 5474 /* Allocate a new ID for the token as we made changes */ 5475 if (ChangesMade) 5476 { 5477 ExAllocateLocallyUniqueId(&Token->ModifiedId); 5478 } 5479 5480 /* Have we successfully acquired the lock and referenced the token before? */ 5481 if (LockAndReferenceAcquired) 5482 { 5483 /* Unlock and dereference the token */ 5484 SepReleaseTokenLock(Token); 5485 ObDereferenceObject(Token); 5486 } 5487 5488 /* Release the captured groups */ 5489 if (CapturedGroups != NULL) 5490 { 5491 SeReleaseSidAndAttributesArray(CapturedGroups, 5492 PreviousMode, 5493 TRUE); 5494 } 5495 5496 return Status; 5497 } 5498 5499 /** 5500 * @brief 5501 * Removes a certain amount of privileges of a token based upon the request 5502 * by the caller. 5503 * 5504 * @param[in,out] Token 5505 * Token handle where the privileges are about to be modified. 5506 * 5507 * @param[in] DisableAllPrivileges 5508 * If set to TRUE, the function disables all the privileges. 5509 * 5510 * @param[in] NewState 5511 * A new list of privileges that the function will use it accordingly to 5512 * either disable or enable the said privileges and change them. 5513 * 5514 * @param[in] NewStateCount 5515 * The new total number count of privileges. 5516 * 5517 * @param[out] PreviousState 5518 * If specified, the function will return the previous state list of privileges. 5519 * 5520 * @param[in] ApplyChanges 5521 * If set to TRUE, the function will immediatelly apply the changes onto the 5522 * token's privileges. 5523 * 5524 * @param[out] ChangedPrivileges 5525 * The returned count number of changed privileges. 5526 * 5527 * @param[out] ChangesMade 5528 * If TRUE, the function has made changes to the token's privileges. FALSE 5529 * otherwise. 5530 * 5531 * @return 5532 * Returns STATUS_SUCCESS if the function has successfully changed the list 5533 * of privileges. STATUS_NOT_ALL_ASSIGNED is returned if not every privilege 5534 * has been changed. 5535 */ 5536 static 5537 NTSTATUS 5538 SepAdjustPrivileges( 5539 _Inout_ PTOKEN Token, 5540 _In_ BOOLEAN DisableAllPrivileges, 5541 _In_opt_ PLUID_AND_ATTRIBUTES NewState, 5542 _In_ ULONG NewStateCount, 5543 _Out_opt_ PTOKEN_PRIVILEGES PreviousState, 5544 _In_ BOOLEAN ApplyChanges, 5545 _Out_ PULONG ChangedPrivileges, 5546 _Out_ PBOOLEAN ChangesMade) 5547 { 5548 ULONG i, j, PrivilegeCount, ChangeCount, NewAttributes; 5549 5550 PAGED_CODE(); 5551 5552 /* Count the found privileges and those that need to be changed */ 5553 PrivilegeCount = 0; 5554 ChangeCount = 0; 5555 *ChangesMade = FALSE; 5556 5557 /* Loop all privileges in the token */ 5558 for (i = 0; i < Token->PrivilegeCount; i++) 5559 { 5560 /* Shall all of them be disabled? */ 5561 if (DisableAllPrivileges) 5562 { 5563 /* The new attributes are the old ones, but disabled */ 5564 NewAttributes = Token->Privileges[i].Attributes & ~SE_PRIVILEGE_ENABLED; 5565 } 5566 else 5567 { 5568 /* Otherwise loop all provided privileges */ 5569 for (j = 0; j < NewStateCount; j++) 5570 { 5571 /* Check if this is the LUID we are looking for */ 5572 if (RtlEqualLuid(&Token->Privileges[i].Luid, &NewState[j].Luid)) 5573 { 5574 DPRINT("Found privilege\n"); 5575 5576 /* Copy SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_REMOVED */ 5577 NewAttributes = NewState[j].Attributes; 5578 NewAttributes &= (SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_REMOVED); 5579 NewAttributes |= Token->Privileges[i].Attributes & ~SE_PRIVILEGE_ENABLED; 5580 5581 /* Stop looking */ 5582 break; 5583 } 5584 } 5585 5586 /* Check if we didn't find the privilege */ 5587 if (j == NewStateCount) 5588 { 5589 /* Continue with the token's next privilege */ 5590 continue; 5591 } 5592 } 5593 5594 /* We found a privilege, count it */ 5595 PrivilegeCount++; 5596 5597 /* Does the privilege need to be changed? */ 5598 if (Token->Privileges[i].Attributes != NewAttributes) 5599 { 5600 /* Does the caller want the old privileges? */ 5601 if (PreviousState != NULL) 5602 { 5603 /* Copy the old privilege */ 5604 PreviousState->Privileges[ChangeCount] = Token->Privileges[i]; 5605 } 5606 5607 /* Does the caller want to apply the changes? */ 5608 if (ApplyChanges) 5609 { 5610 /* Shall we remove the privilege? */ 5611 if (NewAttributes & SE_PRIVILEGE_REMOVED) 5612 { 5613 /* Set the token as disabled and update flags for it */ 5614 Token->Privileges[i].Attributes &= ~SE_PRIVILEGE_ENABLED; 5615 SepUpdateSinglePrivilegeFlagToken(Token, i); 5616 5617 /* Remove the privilege */ 5618 SepRemovePrivilegeToken(Token, i); 5619 5620 *ChangesMade = TRUE; 5621 5622 /* Fix the running index and continue with next one */ 5623 i--; 5624 continue; 5625 } 5626 5627 /* Set the new attributes and update flags */ 5628 Token->Privileges[i].Attributes = NewAttributes; 5629 SepUpdateSinglePrivilegeFlagToken(Token, i); 5630 *ChangesMade = TRUE; 5631 } 5632 5633 /* Increment the change count */ 5634 ChangeCount++; 5635 } 5636 } 5637 5638 /* Set the number of saved privileges */ 5639 if (PreviousState != NULL) 5640 PreviousState->PrivilegeCount = ChangeCount; 5641 5642 /* Return the number of changed privileges */ 5643 *ChangedPrivileges = ChangeCount; 5644 5645 /* Check if we missed some */ 5646 if (!DisableAllPrivileges && (PrivilegeCount < NewStateCount)) 5647 { 5648 return STATUS_NOT_ALL_ASSIGNED; 5649 } 5650 5651 return STATUS_SUCCESS; 5652 } 5653 5654 /** 5655 * @brief 5656 * Removes a certain amount of privileges of a token based upon the request 5657 * by the caller. 5658 * 5659 * @param[in,out] Token 5660 * Token handle where the privileges are about to be modified. 5661 * 5662 * @param[in] DisableAllPrivileges 5663 * If set to TRUE, the function disables all the privileges. 5664 * 5665 * @param[in] NewState 5666 * A new list of privileges that the function will use it accordingly to 5667 * either disable or enable the said privileges and change them. 5668 * 5669 * @param[in] NewStateCount 5670 * The new total number count of privileges. 5671 * 5672 * @param[out] PreviousState 5673 * If specified, the function will return the previous state list of privileges. 5674 * 5675 * @param[in] ApplyChanges 5676 * If set to TRUE, the function will immediatelly apply the changes onto the 5677 * token's privileges. 5678 * 5679 * @param[out] ChangedPrivileges 5680 * The returned count number of changed privileges. 5681 * 5682 * @param[out] ChangesMade 5683 * If TRUE, the function has made changes to the token's privileges. FALSE 5684 * otherwise. 5685 * 5686 * @return 5687 * Returns STATUS_SUCCESS if the function has successfully changed the list 5688 * of privileges. STATUS_NOT_ALL_ASSIGNED is returned if not every privilege 5689 * has been changed. 5690 */ 5691 _Must_inspect_result_ 5692 __kernel_entry 5693 NTSTATUS 5694 NTAPI 5695 NtAdjustPrivilegesToken( 5696 _In_ HANDLE TokenHandle, 5697 _In_ BOOLEAN DisableAllPrivileges, 5698 _In_opt_ PTOKEN_PRIVILEGES NewState, 5699 _In_ ULONG BufferLength, 5700 _Out_writes_bytes_to_opt_(BufferLength,*ReturnLength) 5701 PTOKEN_PRIVILEGES PreviousState, 5702 _When_(PreviousState!=NULL, _Out_) PULONG ReturnLength) 5703 { 5704 NTSTATUS Status; 5705 KPROCESSOR_MODE PreviousMode; 5706 PTOKEN Token; 5707 PLUID_AND_ATTRIBUTES CapturedPrivileges = NULL; 5708 ULONG CapturedCount = 0; 5709 ULONG CapturedLength = 0; 5710 ULONG NewStateSize = 0; 5711 ULONG ChangeCount; 5712 ULONG RequiredLength; 5713 BOOLEAN ChangesMade = FALSE; 5714 5715 PAGED_CODE(); 5716 5717 DPRINT("NtAdjustPrivilegesToken() called\n"); 5718 5719 /* Fail, if we do not disable all privileges but NewState is NULL */ 5720 if (DisableAllPrivileges == FALSE && NewState == NULL) 5721 return STATUS_INVALID_PARAMETER; 5722 5723 PreviousMode = KeGetPreviousMode(); 5724 if (PreviousMode != KernelMode) 5725 { 5726 _SEH2_TRY 5727 { 5728 /* Probe NewState */ 5729 if (DisableAllPrivileges == FALSE) 5730 { 5731 /* First probe the header */ 5732 ProbeForRead(NewState, sizeof(TOKEN_PRIVILEGES), sizeof(ULONG)); 5733 5734 CapturedCount = NewState->PrivilegeCount; 5735 NewStateSize = FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges[CapturedCount]); 5736 5737 ProbeForRead(NewState, NewStateSize, sizeof(ULONG)); 5738 } 5739 5740 /* Probe PreviousState and ReturnLength */ 5741 if (PreviousState != NULL) 5742 { 5743 ProbeForWrite(PreviousState, BufferLength, sizeof(ULONG)); 5744 ProbeForWrite(ReturnLength, sizeof(ULONG), sizeof(ULONG)); 5745 } 5746 } 5747 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 5748 { 5749 /* Return the exception code */ 5750 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 5751 } 5752 _SEH2_END; 5753 } 5754 else 5755 { 5756 /* This is kernel mode, we trust the caller */ 5757 if (DisableAllPrivileges == FALSE) 5758 CapturedCount = NewState->PrivilegeCount; 5759 } 5760 5761 /* Do we need to capture the new state? */ 5762 if (DisableAllPrivileges == FALSE) 5763 { 5764 _SEH2_TRY 5765 { 5766 /* Capture the new state array of privileges */ 5767 Status = SeCaptureLuidAndAttributesArray(NewState->Privileges, 5768 CapturedCount, 5769 PreviousMode, 5770 NULL, 5771 0, 5772 PagedPool, 5773 TRUE, 5774 &CapturedPrivileges, 5775 &CapturedLength); 5776 } 5777 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 5778 { 5779 /* Return the exception code */ 5780 Status = _SEH2_GetExceptionCode(); 5781 } 5782 _SEH2_END; 5783 5784 if (!NT_SUCCESS(Status)) 5785 return Status; 5786 } 5787 5788 /* Reference the token */ 5789 Status = ObReferenceObjectByHandle(TokenHandle, 5790 TOKEN_ADJUST_PRIVILEGES | (PreviousState != NULL ? TOKEN_QUERY : 0), 5791 SeTokenObjectType, 5792 PreviousMode, 5793 (PVOID*)&Token, 5794 NULL); 5795 if (!NT_SUCCESS(Status)) 5796 { 5797 DPRINT1("Failed to reference token (Status 0x%lx)\n", Status); 5798 5799 /* Release the captured privileges */ 5800 if (CapturedPrivileges != NULL) 5801 { 5802 SeReleaseLuidAndAttributesArray(CapturedPrivileges, 5803 PreviousMode, 5804 TRUE); 5805 } 5806 5807 return Status; 5808 } 5809 5810 /* Lock the token */ 5811 SepAcquireTokenLockExclusive(Token); 5812 5813 /* Count the privileges that need to be changed, do not apply them yet */ 5814 Status = SepAdjustPrivileges(Token, 5815 DisableAllPrivileges, 5816 CapturedPrivileges, 5817 CapturedCount, 5818 NULL, 5819 FALSE, 5820 &ChangeCount, 5821 &ChangesMade); 5822 5823 /* Check if the caller asked for the previous state */ 5824 if (PreviousState != NULL) 5825 { 5826 /* Calculate the required length */ 5827 RequiredLength = FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges[ChangeCount]); 5828 5829 /* Try to return the required buffer length */ 5830 _SEH2_TRY 5831 { 5832 *ReturnLength = RequiredLength; 5833 } 5834 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 5835 { 5836 /* Do cleanup and return the exception code */ 5837 Status = _SEH2_GetExceptionCode(); 5838 _SEH2_YIELD(goto Cleanup); 5839 } 5840 _SEH2_END; 5841 5842 /* Fail, if the buffer length is smaller than the required length */ 5843 if (BufferLength < RequiredLength) 5844 { 5845 Status = STATUS_BUFFER_TOO_SMALL; 5846 goto Cleanup; 5847 } 5848 } 5849 5850 /* Now enter SEH, since we might return the old privileges */ 5851 _SEH2_TRY 5852 { 5853 /* This time apply the changes */ 5854 Status = SepAdjustPrivileges(Token, 5855 DisableAllPrivileges, 5856 CapturedPrivileges, 5857 CapturedCount, 5858 PreviousState, 5859 TRUE, 5860 &ChangeCount, 5861 &ChangesMade); 5862 } 5863 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 5864 { 5865 /* Do cleanup and return the exception code */ 5866 Status = _SEH2_GetExceptionCode(); 5867 ChangesMade = TRUE; // Force write. 5868 _SEH2_YIELD(goto Cleanup); 5869 } 5870 _SEH2_END; 5871 5872 Cleanup: 5873 /* Touch the token if we made changes */ 5874 if (ChangesMade) 5875 ExAllocateLocallyUniqueId(&Token->ModifiedId); 5876 5877 /* Unlock and dereference the token */ 5878 SepReleaseTokenLock(Token); 5879 ObDereferenceObject(Token); 5880 5881 /* Release the captured privileges */ 5882 if (CapturedPrivileges != NULL) 5883 { 5884 SeReleaseLuidAndAttributesArray(CapturedPrivileges, 5885 PreviousMode, 5886 TRUE); 5887 } 5888 5889 DPRINT ("NtAdjustPrivilegesToken() done\n"); 5890 return Status; 5891 } 5892 5893 /** 5894 * @brief 5895 * Creates an access token. 5896 * 5897 * @param[out] TokenHandle 5898 * The returned created token handle to the caller. 5899 * 5900 * @param[in] DesiredAccess 5901 * The desired access rights for the token that we're creating. 5902 * 5903 * @param[in] ObjectAttributes 5904 * The object attributes for the token object that we're creating. 5905 * 5906 * @param[in] TokenType 5907 * The type of token to assign for the newly created token. 5908 * 5909 * @param[in] AuthenticationId 5910 * Authentication ID that represents the token's identity. 5911 * 5912 * @param[in] ExpirationTime 5913 * Expiration time for the token. If set to -1, the token never expires. 5914 * 5915 * @param[in] TokenUser 5916 * The main user entity for the token to assign. 5917 * 5918 * @param[in] TokenGroups 5919 * Group list of SIDs for the token to assign. 5920 * 5921 * @param[in] TokenPrivileges 5922 * Privileges for the token. 5923 * 5924 * @param[in] TokenOwner 5925 * The main user that owns the newly created token. 5926 * 5927 * @param[in] TokenPrimaryGroup 5928 * The primary group that represents as the main group of the token. 5929 * 5930 * @param[in] TokenDefaultDacl 5931 * Discretionary access control list for the token. This limits on how 5932 * the token can be used, accessed and used by whom. 5933 * 5934 * @param[in] TokenSource 5935 * The source origin of the token who creates it. 5936 * 5937 * @return 5938 * Returns STATUS_SUCCESS if the function has successfully created the token. 5939 * A failure NTSTATUS code is returned otherwise. 5940 */ 5941 __kernel_entry 5942 NTSTATUS 5943 NTAPI 5944 NtCreateToken( 5945 _Out_ PHANDLE TokenHandle, 5946 _In_ ACCESS_MASK DesiredAccess, 5947 _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, 5948 _In_ TOKEN_TYPE TokenType, 5949 _In_ PLUID AuthenticationId, 5950 _In_ PLARGE_INTEGER ExpirationTime, 5951 _In_ PTOKEN_USER TokenUser, 5952 _In_ PTOKEN_GROUPS TokenGroups, 5953 _In_ PTOKEN_PRIVILEGES TokenPrivileges, 5954 _In_opt_ PTOKEN_OWNER TokenOwner, 5955 _In_ PTOKEN_PRIMARY_GROUP TokenPrimaryGroup, 5956 _In_opt_ PTOKEN_DEFAULT_DACL TokenDefaultDacl, 5957 _In_ PTOKEN_SOURCE TokenSource) 5958 { 5959 HANDLE hToken; 5960 KPROCESSOR_MODE PreviousMode; 5961 ULONG PrivilegeCount, GroupCount; 5962 PSID OwnerSid, PrimaryGroupSid; 5963 PACL DefaultDacl; 5964 LARGE_INTEGER LocalExpirationTime = {{0, 0}}; 5965 LUID LocalAuthenticationId; 5966 TOKEN_SOURCE LocalTokenSource; 5967 SECURITY_QUALITY_OF_SERVICE LocalSecurityQos; 5968 PLUID_AND_ATTRIBUTES CapturedPrivileges = NULL; 5969 PSID_AND_ATTRIBUTES CapturedUser = NULL; 5970 PSID_AND_ATTRIBUTES CapturedGroups = NULL; 5971 PSID CapturedOwnerSid = NULL; 5972 PSID CapturedPrimaryGroupSid = NULL; 5973 PACL CapturedDefaultDacl = NULL; 5974 ULONG PrivilegesLength, UserLength, GroupsLength; 5975 NTSTATUS Status; 5976 5977 PAGED_CODE(); 5978 5979 PreviousMode = ExGetPreviousMode(); 5980 5981 if (PreviousMode != KernelMode) 5982 { 5983 _SEH2_TRY 5984 { 5985 ProbeForWriteHandle(TokenHandle); 5986 5987 if (ObjectAttributes != NULL) 5988 { 5989 ProbeForRead(ObjectAttributes, 5990 sizeof(OBJECT_ATTRIBUTES), 5991 sizeof(ULONG)); 5992 LocalSecurityQos = *(SECURITY_QUALITY_OF_SERVICE*)ObjectAttributes->SecurityQualityOfService; 5993 } 5994 5995 ProbeForRead(AuthenticationId, 5996 sizeof(LUID), 5997 sizeof(ULONG)); 5998 LocalAuthenticationId = *AuthenticationId; 5999 6000 LocalExpirationTime = ProbeForReadLargeInteger(ExpirationTime); 6001 6002 ProbeForRead(TokenUser, 6003 sizeof(TOKEN_USER), 6004 sizeof(ULONG)); 6005 6006 ProbeForRead(TokenGroups, 6007 sizeof(TOKEN_GROUPS), 6008 sizeof(ULONG)); 6009 GroupCount = TokenGroups->GroupCount; 6010 6011 ProbeForRead(TokenPrivileges, 6012 sizeof(TOKEN_PRIVILEGES), 6013 sizeof(ULONG)); 6014 PrivilegeCount = TokenPrivileges->PrivilegeCount; 6015 6016 if (TokenOwner != NULL) 6017 { 6018 ProbeForRead(TokenOwner, 6019 sizeof(TOKEN_OWNER), 6020 sizeof(ULONG)); 6021 OwnerSid = TokenOwner->Owner; 6022 } 6023 else 6024 { 6025 OwnerSid = NULL; 6026 } 6027 6028 ProbeForRead(TokenPrimaryGroup, 6029 sizeof(TOKEN_PRIMARY_GROUP), 6030 sizeof(ULONG)); 6031 PrimaryGroupSid = TokenPrimaryGroup->PrimaryGroup; 6032 6033 if (TokenDefaultDacl != NULL) 6034 { 6035 ProbeForRead(TokenDefaultDacl, 6036 sizeof(TOKEN_DEFAULT_DACL), 6037 sizeof(ULONG)); 6038 DefaultDacl = TokenDefaultDacl->DefaultDacl; 6039 } 6040 else 6041 { 6042 DefaultDacl = NULL; 6043 } 6044 6045 ProbeForRead(TokenSource, 6046 sizeof(TOKEN_SOURCE), 6047 sizeof(ULONG)); 6048 LocalTokenSource = *TokenSource; 6049 } 6050 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 6051 { 6052 /* Return the exception code */ 6053 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 6054 } 6055 _SEH2_END; 6056 } 6057 else 6058 { 6059 if (ObjectAttributes != NULL) 6060 LocalSecurityQos = *(SECURITY_QUALITY_OF_SERVICE*)ObjectAttributes->SecurityQualityOfService; 6061 LocalAuthenticationId = *AuthenticationId; 6062 LocalExpirationTime = *ExpirationTime; 6063 GroupCount = TokenGroups->GroupCount; 6064 PrivilegeCount = TokenPrivileges->PrivilegeCount; 6065 OwnerSid = TokenOwner ? TokenOwner->Owner : NULL; 6066 PrimaryGroupSid = TokenPrimaryGroup->PrimaryGroup; 6067 DefaultDacl = TokenDefaultDacl ? TokenDefaultDacl->DefaultDacl : NULL; 6068 LocalTokenSource = *TokenSource; 6069 } 6070 6071 /* Check token type */ 6072 if ((TokenType < TokenPrimary) || 6073 (TokenType > TokenImpersonation)) 6074 { 6075 return STATUS_BAD_TOKEN_TYPE; 6076 } 6077 6078 /* Check for token creation privilege */ 6079 if (!SeSinglePrivilegeCheck(SeCreateTokenPrivilege, PreviousMode)) 6080 { 6081 return STATUS_PRIVILEGE_NOT_HELD; 6082 } 6083 6084 /* Capture the user SID and attributes */ 6085 Status = SeCaptureSidAndAttributesArray(&TokenUser->User, 6086 1, 6087 PreviousMode, 6088 NULL, 6089 0, 6090 PagedPool, 6091 FALSE, 6092 &CapturedUser, 6093 &UserLength); 6094 if (!NT_SUCCESS(Status)) 6095 { 6096 goto Cleanup; 6097 } 6098 6099 /* Capture the groups SID and attributes array */ 6100 Status = SeCaptureSidAndAttributesArray(&TokenGroups->Groups[0], 6101 GroupCount, 6102 PreviousMode, 6103 NULL, 6104 0, 6105 PagedPool, 6106 FALSE, 6107 &CapturedGroups, 6108 &GroupsLength); 6109 if (!NT_SUCCESS(Status)) 6110 { 6111 goto Cleanup; 6112 } 6113 6114 /* Capture privileges */ 6115 Status = SeCaptureLuidAndAttributesArray(&TokenPrivileges->Privileges[0], 6116 PrivilegeCount, 6117 PreviousMode, 6118 NULL, 6119 0, 6120 PagedPool, 6121 FALSE, 6122 &CapturedPrivileges, 6123 &PrivilegesLength); 6124 if (!NT_SUCCESS(Status)) 6125 { 6126 goto Cleanup; 6127 } 6128 6129 /* Capture the token owner SID */ 6130 if (TokenOwner != NULL) 6131 { 6132 Status = SepCaptureSid(OwnerSid, 6133 PreviousMode, 6134 PagedPool, 6135 FALSE, 6136 &CapturedOwnerSid); 6137 if (!NT_SUCCESS(Status)) 6138 { 6139 goto Cleanup; 6140 } 6141 } 6142 6143 /* Capture the token primary group SID */ 6144 Status = SepCaptureSid(PrimaryGroupSid, 6145 PreviousMode, 6146 PagedPool, 6147 FALSE, 6148 &CapturedPrimaryGroupSid); 6149 if (!NT_SUCCESS(Status)) 6150 { 6151 goto Cleanup; 6152 } 6153 6154 /* Capture DefaultDacl */ 6155 if (DefaultDacl != NULL) 6156 { 6157 Status = SepCaptureAcl(DefaultDacl, 6158 PreviousMode, 6159 NonPagedPool, 6160 FALSE, 6161 &CapturedDefaultDacl); 6162 if (!NT_SUCCESS(Status)) 6163 { 6164 goto Cleanup; 6165 } 6166 } 6167 6168 /* Call the internal function */ 6169 Status = SepCreateToken(&hToken, 6170 PreviousMode, 6171 DesiredAccess, 6172 ObjectAttributes, 6173 TokenType, 6174 LocalSecurityQos.ImpersonationLevel, 6175 &LocalAuthenticationId, 6176 &LocalExpirationTime, 6177 CapturedUser, 6178 GroupCount, 6179 CapturedGroups, 6180 GroupsLength, 6181 PrivilegeCount, 6182 CapturedPrivileges, 6183 CapturedOwnerSid, 6184 CapturedPrimaryGroupSid, 6185 CapturedDefaultDacl, 6186 &LocalTokenSource, 6187 FALSE); 6188 if (NT_SUCCESS(Status)) 6189 { 6190 _SEH2_TRY 6191 { 6192 *TokenHandle = hToken; 6193 } 6194 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 6195 { 6196 Status = _SEH2_GetExceptionCode(); 6197 } 6198 _SEH2_END; 6199 } 6200 6201 Cleanup: 6202 6203 /* Release what we captured */ 6204 SeReleaseSidAndAttributesArray(CapturedUser, PreviousMode, FALSE); 6205 SeReleaseSidAndAttributesArray(CapturedGroups, PreviousMode, FALSE); 6206 SeReleaseLuidAndAttributesArray(CapturedPrivileges, PreviousMode, FALSE); 6207 SepReleaseSid(CapturedOwnerSid, PreviousMode, FALSE); 6208 SepReleaseSid(CapturedPrimaryGroupSid, PreviousMode, FALSE); 6209 SepReleaseAcl(CapturedDefaultDacl, PreviousMode, FALSE); 6210 6211 return Status; 6212 } 6213 6214 /** 6215 * @brief 6216 * Opens a token that is tied to a thread handle. 6217 * 6218 * @param[out] ThreadHandle 6219 * Thread handle where the token is about to be opened. 6220 * 6221 * @param[in] DesiredAccess 6222 * The request access right for the token. 6223 * 6224 * @param[in] OpenAsSelf 6225 * If set to TRUE, the access check will be made with the security context 6226 * of the process of the calling thread (opening as self). Otherwise the access 6227 * check will be made with the security context of the calling thread instead. 6228 * 6229 * @param[in] HandleAttributes 6230 * Handle attributes for the opened thread token handle. 6231 * 6232 * @param[out] TokenHandle 6233 * The opened token handle returned to the caller for use. 6234 * 6235 * @return 6236 * Returns STATUS_SUCCESS if the function has successfully opened the thread 6237 * token. STATUS_CANT_OPEN_ANONYMOUS is returned if a token has SecurityAnonymous 6238 * as impersonation level and we cannot open it. A failure NTSTATUS code is returned 6239 * otherwise. 6240 */ 6241 NTSTATUS 6242 NTAPI 6243 NtOpenThreadTokenEx( 6244 _In_ HANDLE ThreadHandle, 6245 _In_ ACCESS_MASK DesiredAccess, 6246 _In_ BOOLEAN OpenAsSelf, 6247 _In_ ULONG HandleAttributes, 6248 _Out_ PHANDLE TokenHandle) 6249 { 6250 PETHREAD Thread; 6251 HANDLE hToken; 6252 PTOKEN Token, NewToken = NULL, PrimaryToken; 6253 BOOLEAN CopyOnOpen, EffectiveOnly; 6254 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; 6255 SE_IMPERSONATION_STATE ImpersonationState; 6256 OBJECT_ATTRIBUTES ObjectAttributes; 6257 SECURITY_DESCRIPTOR SecurityDescriptor; 6258 PACL Dacl = NULL; 6259 KPROCESSOR_MODE PreviousMode; 6260 NTSTATUS Status; 6261 BOOLEAN RestoreImpersonation = FALSE; 6262 6263 PAGED_CODE(); 6264 6265 PreviousMode = ExGetPreviousMode(); 6266 6267 if (PreviousMode != KernelMode) 6268 { 6269 _SEH2_TRY 6270 { 6271 ProbeForWriteHandle(TokenHandle); 6272 } 6273 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 6274 { 6275 /* Return the exception code */ 6276 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 6277 } 6278 _SEH2_END; 6279 } 6280 6281 /* Validate object attributes */ 6282 HandleAttributes = ObpValidateAttributes(HandleAttributes, PreviousMode); 6283 6284 /* 6285 * At first open the thread token for information access and verify 6286 * that the token associated with thread is valid. 6287 */ 6288 6289 Status = ObReferenceObjectByHandle(ThreadHandle, THREAD_QUERY_INFORMATION, 6290 PsThreadType, PreviousMode, (PVOID*)&Thread, 6291 NULL); 6292 if (!NT_SUCCESS(Status)) 6293 { 6294 return Status; 6295 } 6296 6297 Token = PsReferenceImpersonationToken(Thread, &CopyOnOpen, &EffectiveOnly, 6298 &ImpersonationLevel); 6299 if (Token == NULL) 6300 { 6301 ObDereferenceObject(Thread); 6302 return STATUS_NO_TOKEN; 6303 } 6304 6305 if (ImpersonationLevel == SecurityAnonymous) 6306 { 6307 PsDereferenceImpersonationToken(Token); 6308 ObDereferenceObject(Thread); 6309 return STATUS_CANT_OPEN_ANONYMOUS; 6310 } 6311 6312 /* 6313 * Revert to self if OpenAsSelf is specified. 6314 */ 6315 6316 if (OpenAsSelf) 6317 { 6318 RestoreImpersonation = PsDisableImpersonation(PsGetCurrentThread(), 6319 &ImpersonationState); 6320 } 6321 6322 if (CopyOnOpen) 6323 { 6324 PrimaryToken = PsReferencePrimaryToken(Thread->ThreadsProcess); 6325 6326 Status = SepCreateImpersonationTokenDacl(Token, PrimaryToken, &Dacl); 6327 6328 ObFastDereferenceObject(&Thread->ThreadsProcess->Token, PrimaryToken); 6329 6330 if (NT_SUCCESS(Status)) 6331 { 6332 if (Dacl) 6333 { 6334 Status = RtlCreateSecurityDescriptor(&SecurityDescriptor, 6335 SECURITY_DESCRIPTOR_REVISION); 6336 if (!NT_SUCCESS(Status)) 6337 { 6338 DPRINT1("NtOpenThreadTokenEx(): Failed to create a security descriptor (Status 0x%lx)\n", Status); 6339 } 6340 6341 Status = RtlSetDaclSecurityDescriptor(&SecurityDescriptor, TRUE, Dacl, 6342 FALSE); 6343 if (!NT_SUCCESS(Status)) 6344 { 6345 DPRINT1("NtOpenThreadTokenEx(): Failed to set a DACL to the security descriptor (Status 0x%lx)\n", Status); 6346 } 6347 } 6348 6349 InitializeObjectAttributes(&ObjectAttributes, NULL, HandleAttributes, 6350 NULL, Dacl ? &SecurityDescriptor : NULL); 6351 6352 Status = SepDuplicateToken(Token, &ObjectAttributes, EffectiveOnly, 6353 TokenImpersonation, ImpersonationLevel, 6354 KernelMode, &NewToken); 6355 if (!NT_SUCCESS(Status)) 6356 { 6357 DPRINT1("NtOpenThreadTokenEx(): Failed to duplicate the token (Status 0x%lx)\n", Status); 6358 } 6359 6360 ObReferenceObject(NewToken); 6361 Status = ObInsertObject(NewToken, NULL, DesiredAccess, 0, NULL, 6362 &hToken); 6363 if (!NT_SUCCESS(Status)) 6364 { 6365 DPRINT1("NtOpenThreadTokenEx(): Failed to insert the token object (Status 0x%lx)\n", Status); 6366 } 6367 } 6368 else 6369 { 6370 DPRINT1("NtOpenThreadTokenEx(): Failed to impersonate token from DACL (Status 0x%lx)\n", Status); 6371 } 6372 } 6373 else 6374 { 6375 Status = ObOpenObjectByPointer(Token, HandleAttributes, 6376 NULL, DesiredAccess, SeTokenObjectType, 6377 PreviousMode, &hToken); 6378 if (!NT_SUCCESS(Status)) 6379 { 6380 DPRINT1("NtOpenThreadTokenEx(): Failed to open the object (Status 0x%lx)\n", Status); 6381 } 6382 } 6383 6384 if (Dacl) ExFreePoolWithTag(Dacl, TAG_ACL); 6385 6386 if (RestoreImpersonation) 6387 { 6388 PsRestoreImpersonation(PsGetCurrentThread(), &ImpersonationState); 6389 } 6390 6391 ObDereferenceObject(Token); 6392 6393 if (NT_SUCCESS(Status) && CopyOnOpen) 6394 { 6395 Status = PsImpersonateClient(Thread, NewToken, FALSE, EffectiveOnly, ImpersonationLevel); 6396 if (!NT_SUCCESS(Status)) 6397 { 6398 DPRINT1("NtOpenThreadTokenEx(): Failed to impersonate the client (Status 0x%lx)\n", Status); 6399 } 6400 } 6401 6402 if (NewToken) ObDereferenceObject(NewToken); 6403 6404 ObDereferenceObject(Thread); 6405 6406 if (NT_SUCCESS(Status)) 6407 { 6408 _SEH2_TRY 6409 { 6410 *TokenHandle = hToken; 6411 } 6412 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 6413 { 6414 Status = _SEH2_GetExceptionCode(); 6415 } 6416 _SEH2_END; 6417 } 6418 6419 return Status; 6420 } 6421 6422 /** 6423 * @brief 6424 * Opens a token that is tied to a thread handle. 6425 * 6426 * @param[out] ThreadHandle 6427 * Thread handle where the token is about to be opened. 6428 * 6429 * @param[in] DesiredAccess 6430 * The request access right for the token. 6431 * 6432 * @param[in] OpenAsSelf 6433 * If set to TRUE, the access check will be made with the security context 6434 * of the process of the calling thread (opening as self). Otherwise the access 6435 * check will be made with the security context of the calling thread instead. 6436 * 6437 * @param[out] TokenHandle 6438 * The opened token handle returned to the caller for use. 6439 * 6440 * @return 6441 * See NtOpenThreadTokenEx. 6442 */ 6443 NTSTATUS 6444 NTAPI 6445 NtOpenThreadToken( 6446 _In_ HANDLE ThreadHandle, 6447 _In_ ACCESS_MASK DesiredAccess, 6448 _In_ BOOLEAN OpenAsSelf, 6449 _Out_ PHANDLE TokenHandle) 6450 { 6451 return NtOpenThreadTokenEx(ThreadHandle, DesiredAccess, OpenAsSelf, 0, 6452 TokenHandle); 6453 } 6454 6455 /** 6456 * @brief 6457 * Compares tokens if they're equal or not. 6458 * 6459 * @param[in] FirstToken 6460 * The first token. 6461 * 6462 * @param[in] SecondToken 6463 * The second token. 6464 * 6465 * @param[out] Equal 6466 * The retrieved value which determines if the tokens are 6467 * equal or not. 6468 * 6469 * @return 6470 * Returns STATUS_SUCCESS, otherwise it returns a failure NTSTATUS code. 6471 */ 6472 NTSTATUS 6473 NTAPI 6474 NtCompareTokens( 6475 _In_ HANDLE FirstTokenHandle, 6476 _In_ HANDLE SecondTokenHandle, 6477 _Out_ PBOOLEAN Equal) 6478 { 6479 KPROCESSOR_MODE PreviousMode; 6480 PTOKEN FirstToken, SecondToken; 6481 BOOLEAN IsEqual; 6482 NTSTATUS Status; 6483 6484 PAGED_CODE(); 6485 6486 PreviousMode = ExGetPreviousMode(); 6487 6488 if (PreviousMode != KernelMode) 6489 { 6490 _SEH2_TRY 6491 { 6492 ProbeForWriteBoolean(Equal); 6493 } 6494 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 6495 { 6496 /* Return the exception code */ 6497 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 6498 } 6499 _SEH2_END; 6500 } 6501 6502 Status = ObReferenceObjectByHandle(FirstTokenHandle, 6503 TOKEN_QUERY, 6504 SeTokenObjectType, 6505 PreviousMode, 6506 (PVOID*)&FirstToken, 6507 NULL); 6508 if (!NT_SUCCESS(Status)) 6509 { 6510 DPRINT1("ObReferenceObjectByHandle() failed (Status 0x%lx)\n", Status); 6511 return Status; 6512 } 6513 6514 Status = ObReferenceObjectByHandle(SecondTokenHandle, 6515 TOKEN_QUERY, 6516 SeTokenObjectType, 6517 PreviousMode, 6518 (PVOID*)&SecondToken, 6519 NULL); 6520 if (!NT_SUCCESS(Status)) 6521 { 6522 DPRINT1("ObReferenceObjectByHandle() failed (Status 0x%lx)\n", Status); 6523 ObDereferenceObject(FirstToken); 6524 return Status; 6525 } 6526 6527 if (FirstToken != SecondToken) 6528 { 6529 Status = SepCompareTokens(FirstToken, 6530 SecondToken, 6531 &IsEqual); 6532 } 6533 else 6534 { 6535 IsEqual = TRUE; 6536 } 6537 6538 ObDereferenceObject(SecondToken); 6539 ObDereferenceObject(FirstToken); 6540 6541 if (NT_SUCCESS(Status)) 6542 { 6543 _SEH2_TRY 6544 { 6545 *Equal = IsEqual; 6546 } 6547 _SEH2_EXCEPT(ExSystemExceptionFilter()) 6548 { 6549 Status = _SEH2_GetExceptionCode(); 6550 } 6551 _SEH2_END; 6552 } 6553 6554 return Status; 6555 } 6556 6557 /** 6558 * @brief 6559 * Creates an access token in a restricted form 6560 * from the original existing token, that is, such 6561 * action is called filtering. 6562 * 6563 * @param[in] ExistingTokenHandle 6564 * A handle to an access token which is to be filtered. 6565 * 6566 * @param[in] Flags 6567 * Privilege flag options. This parameter argument influences how the 6568 * token's privileges are filtered. For further details see remarks. 6569 * 6570 * @param[in] SidsToDisable 6571 * Array of SIDs to disable. The action of doing so assigns the 6572 * SE_GROUP_USE_FOR_DENY_ONLY attribute to the respective group 6573 * SID and takes away SE_GROUP_ENABLED and SE_GROUP_ENABLED_BY_DEFAULT. 6574 * This parameter can be NULL. This can be a UM pointer. 6575 * 6576 * @param[in] PrivilegesToDelete 6577 * Array of privileges to delete. The function will walk within this 6578 * array to determine if the specified privileges do exist in the 6579 * access token. Any missing privileges gets ignored. This parameter 6580 * can be NULL. This can be a UM pointer. 6581 * 6582 * @param[in] RestrictedSids 6583 * An array list of restricted groups SID to be added in the access 6584 * token. A token that is already restricted the newly added restricted 6585 * SIDs are redundant information in addition to the existing restricted 6586 * SIDs in the token. This parameter can be NULL. This can be a UM pointer. 6587 * 6588 * @param[out] NewTokenHandle 6589 * A new handle to the restricted (filtered) access token. This can be a 6590 * UM pointer. 6591 * 6592 * @return 6593 * Returns STATUS_SUCCESS if the routine has successfully filtered the 6594 * access token. STATUS_INVALID_PARAMETER is returned if one or more 6595 * parameters are not valid (see SepPerformTokenFiltering routine call 6596 * for more information). A failure NTSTATUS code is returned otherwise. 6597 * 6598 * @remarks 6599 * The Flags parameter determines the final outcome of how the privileges 6600 * in an access token are filtered. This parameter can take these supported 6601 * values (these can be combined): 6602 * 6603 * 0 -- Filter the token's privileges in the usual way. The function expects 6604 * that the caller MUST PROVIDE a valid array list of privileges to be 6605 * deleted (that is, PrivilegesToDelete MUSTN'T BE NULL). 6606 * 6607 * DISABLE_MAX_PRIVILEGE -- Disables (deletes) all the privileges except SeChangeNotifyPrivilege 6608 * in the new access token. Bear in mind if this flag is specified 6609 * the routine ignores PrivilegesToDelete. 6610 * 6611 * SANDBOX_INERT -- Stores the TOKEN_SANDBOX_INERT token flag within the access token. 6612 * 6613 * LUA_TOKEN -- The newly filtered access token is a LUA token. This flag is not 6614 * supported in Windows Server 2003. 6615 * 6616 * WRITE_RESTRICTED -- The newly filtered token has the restricted SIDs that are 6617 * considered only when evaluating write access onto the token. 6618 * This value is not supported in Windows Server 2003. 6619 */ 6620 NTSTATUS 6621 NTAPI 6622 NtFilterToken( 6623 _In_ HANDLE ExistingTokenHandle, 6624 _In_ ULONG Flags, 6625 _In_opt_ PTOKEN_GROUPS SidsToDisable, 6626 _In_opt_ PTOKEN_PRIVILEGES PrivilegesToDelete, 6627 _In_opt_ PTOKEN_GROUPS RestrictedSids, 6628 _Out_ PHANDLE NewTokenHandle) 6629 { 6630 PTOKEN Token, FilteredToken; 6631 HANDLE FilteredTokenHandle; 6632 NTSTATUS Status; 6633 KPROCESSOR_MODE PreviousMode; 6634 OBJECT_HANDLE_INFORMATION HandleInfo; 6635 ULONG ResultLength; 6636 ULONG CapturedSidsCount = 0; 6637 ULONG CapturedPrivilegesCount = 0; 6638 ULONG CapturedRestrictedSidsCount = 0; 6639 ULONG ProbeSize = 0; 6640 PSID_AND_ATTRIBUTES CapturedSids = NULL; 6641 PSID_AND_ATTRIBUTES CapturedRestrictedSids = NULL; 6642 PLUID_AND_ATTRIBUTES CapturedPrivileges = NULL; 6643 6644 PAGED_CODE(); 6645 6646 PreviousMode = ExGetPreviousMode(); 6647 6648 _SEH2_TRY 6649 { 6650 /* Probe SidsToDisable */ 6651 if (SidsToDisable != NULL) 6652 { 6653 /* Probe the header */ 6654 ProbeForRead(SidsToDisable, sizeof(*SidsToDisable), sizeof(ULONG)); 6655 6656 CapturedSidsCount = SidsToDisable->GroupCount; 6657 ProbeSize = FIELD_OFFSET(TOKEN_GROUPS, Groups[CapturedSidsCount]); 6658 6659 ProbeForRead(SidsToDisable, ProbeSize, sizeof(ULONG)); 6660 } 6661 6662 /* Probe PrivilegesToDelete */ 6663 if (PrivilegesToDelete != NULL) 6664 { 6665 /* Probe the header */ 6666 ProbeForRead(PrivilegesToDelete, sizeof(*PrivilegesToDelete), sizeof(ULONG)); 6667 6668 CapturedPrivilegesCount = PrivilegesToDelete->PrivilegeCount; 6669 ProbeSize = FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges[CapturedPrivilegesCount]); 6670 6671 ProbeForRead(PrivilegesToDelete, ProbeSize, sizeof(ULONG)); 6672 } 6673 6674 /* Probe RestrictedSids */ 6675 if (RestrictedSids != NULL) 6676 { 6677 /* Probe the header */ 6678 ProbeForRead(RestrictedSids, sizeof(*RestrictedSids), sizeof(ULONG)); 6679 6680 CapturedRestrictedSidsCount = RestrictedSids->GroupCount; 6681 ProbeSize = FIELD_OFFSET(TOKEN_GROUPS, Groups[CapturedRestrictedSidsCount]); 6682 6683 ProbeForRead(RestrictedSids, ProbeSize, sizeof(ULONG)); 6684 } 6685 6686 /* Probe the handle */ 6687 ProbeForWriteHandle(NewTokenHandle); 6688 } 6689 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 6690 { 6691 /* Return the exception code */ 6692 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 6693 } 6694 _SEH2_END; 6695 6696 /* Reference the token and do the job */ 6697 Status = ObReferenceObjectByHandle(ExistingTokenHandle, 6698 TOKEN_DUPLICATE, 6699 SeTokenObjectType, 6700 PreviousMode, 6701 (PVOID*)&Token, 6702 &HandleInfo); 6703 if (!NT_SUCCESS(Status)) 6704 { 6705 DPRINT1("NtFilterToken(): Failed to reference the token (Status 0x%lx)\n", Status); 6706 return Status; 6707 } 6708 6709 /* Lock the token */ 6710 SepAcquireTokenLockExclusive(Token); 6711 6712 /* Capture the group SIDs */ 6713 if (SidsToDisable != NULL) 6714 { 6715 Status = SeCaptureSidAndAttributesArray(SidsToDisable->Groups, 6716 CapturedSidsCount, 6717 PreviousMode, 6718 NULL, 6719 0, 6720 PagedPool, 6721 TRUE, 6722 &CapturedSids, 6723 &ResultLength); 6724 if (!NT_SUCCESS(Status)) 6725 { 6726 DPRINT1("NtFilterToken(): Failed to capture the SIDs (Status 0x%lx)\n", Status); 6727 goto Quit; 6728 } 6729 } 6730 6731 /* Capture the privileges */ 6732 if (PrivilegesToDelete != NULL) 6733 { 6734 Status = SeCaptureLuidAndAttributesArray(PrivilegesToDelete->Privileges, 6735 CapturedPrivilegesCount, 6736 PreviousMode, 6737 NULL, 6738 0, 6739 PagedPool, 6740 TRUE, 6741 &CapturedPrivileges, 6742 &ResultLength); 6743 if (!NT_SUCCESS(Status)) 6744 { 6745 DPRINT1("NtFilterToken(): Failed to capture the privileges (Status 0x%lx)\n", Status); 6746 goto Quit; 6747 } 6748 } 6749 6750 /* Capture the restricted SIDs */ 6751 if (RestrictedSids != NULL) 6752 { 6753 Status = SeCaptureSidAndAttributesArray(RestrictedSids->Groups, 6754 CapturedRestrictedSidsCount, 6755 PreviousMode, 6756 NULL, 6757 0, 6758 PagedPool, 6759 TRUE, 6760 &CapturedRestrictedSids, 6761 &ResultLength); 6762 if (!NT_SUCCESS(Status)) 6763 { 6764 DPRINT1("NtFilterToken(): Failed to capture the restricted SIDs (Status 0x%lx)\n", Status); 6765 goto Quit; 6766 } 6767 } 6768 6769 /* Call the internal API so that it can filter the token for us */ 6770 Status = SepPerformTokenFiltering(Token, 6771 CapturedPrivileges, 6772 CapturedSids, 6773 CapturedRestrictedSids, 6774 CapturedPrivilegesCount, 6775 CapturedSidsCount, 6776 CapturedRestrictedSidsCount, 6777 Flags, 6778 PreviousMode, 6779 &FilteredToken); 6780 if (!NT_SUCCESS(Status)) 6781 { 6782 DPRINT1("NtFilterToken(): Failed to filter the token (Status 0x%lx)\n", Status); 6783 goto Quit; 6784 } 6785 6786 /* We got our filtered token, insert it to the handle */ 6787 Status = ObInsertObject(FilteredToken, 6788 NULL, 6789 HandleInfo.GrantedAccess, 6790 0, 6791 NULL, 6792 &FilteredTokenHandle); 6793 if (!NT_SUCCESS(Status)) 6794 { 6795 DPRINT1("NtFilterToken(): Failed to insert the filtered token object into the handle (Status 0x%lx)\n", Status); 6796 goto Quit; 6797 } 6798 6799 /* And give it to the caller once we're done */ 6800 _SEH2_TRY 6801 { 6802 *NewTokenHandle = FilteredTokenHandle; 6803 } 6804 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 6805 { 6806 Status = _SEH2_GetExceptionCode(); 6807 _SEH2_YIELD(goto Quit); 6808 } 6809 _SEH2_END; 6810 6811 Quit: 6812 /* Unlock and dereference the token */ 6813 SepReleaseTokenLock(Token); 6814 ObDereferenceObject(Token); 6815 6816 /* Release all the stuff we've captured */ 6817 if (CapturedSids != NULL) 6818 { 6819 SeReleaseSidAndAttributesArray(CapturedSids, 6820 PreviousMode, 6821 TRUE); 6822 6823 CapturedSids = NULL; 6824 } 6825 6826 if (CapturedPrivileges != NULL) 6827 { 6828 SeReleaseLuidAndAttributesArray(CapturedPrivileges, 6829 PreviousMode, 6830 TRUE); 6831 6832 CapturedPrivileges = NULL; 6833 } 6834 6835 if (CapturedRestrictedSids != NULL) 6836 { 6837 SeReleaseSidAndAttributesArray(CapturedRestrictedSids, 6838 PreviousMode, 6839 TRUE); 6840 6841 CapturedRestrictedSids = NULL; 6842 } 6843 6844 return Status; 6845 } 6846 6847 /** 6848 * @brief 6849 * Allows the calling thread to impersonate the system's anonymous 6850 * logon token. 6851 * 6852 * @param[in] ThreadHandle 6853 * A handle to the thread to start the procedure of logon token 6854 * impersonation. The thread must have the THREAD_IMPERSONATE 6855 * access right. 6856 * 6857 * @return 6858 * Returns STATUS_SUCCESS if the thread has successfully impersonated the 6859 * anonymous logon token, otherwise a failure NTSTATUS code is returned. 6860 * 6861 * @remarks 6862 * By default the system gives the opportunity to the caller to impersonate 6863 * the anonymous logon token without including the Everyone Group SID. 6864 * In cases where the caller wants to impersonate the token including such 6865 * group, the EveryoneIncludesAnonymous registry value setting has to be set 6866 * to 1, from HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa registry 6867 * path. The calling thread must invoke PsRevertToSelf when impersonation 6868 * is no longer needed or RevertToSelf if the calling execution is done 6869 * in user mode. 6870 */ 6871 NTSTATUS 6872 NTAPI 6873 NtImpersonateAnonymousToken( 6874 _In_ HANDLE ThreadHandle) 6875 { 6876 PETHREAD Thread; 6877 KPROCESSOR_MODE PreviousMode; 6878 NTSTATUS Status; 6879 PAGED_CODE(); 6880 6881 PreviousMode = ExGetPreviousMode(); 6882 6883 /* Obtain the thread object from the handle */ 6884 Status = ObReferenceObjectByHandle(ThreadHandle, 6885 THREAD_IMPERSONATE, 6886 PsThreadType, 6887 PreviousMode, 6888 (PVOID*)&Thread, 6889 NULL); 6890 if (!NT_SUCCESS(Status)) 6891 { 6892 DPRINT1("NtImpersonateAnonymousToken(): Failed to reference the object (Status 0x%lx)\n", Status); 6893 return Status; 6894 } 6895 6896 /* Call the private routine to impersonate the token */ 6897 Status = SepImpersonateAnonymousToken(Thread, PreviousMode); 6898 if (!NT_SUCCESS(Status)) 6899 { 6900 DPRINT1("NtImpersonateAnonymousToken(): Failed to impersonate the token (Status 0x%lx)\n", Status); 6901 } 6902 6903 ObDereferenceObject(Thread); 6904 return Status; 6905 } 6906 6907 /* EOF */ 6908