1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Access token Query/Set information classes implementation 5 * COPYRIGHT: Copyright David Welch <welch@cwcom.net> 6 * Copyright 2021-2022 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 /* INFORMATION CLASSES ********************************************************/ 18 19 static const INFORMATION_CLASS_INFO SeTokenInformationClass[] = { 20 21 /* Class 0 not used, blame MS! */ 22 IQS_NONE, 23 24 /* TokenUser */ 25 IQS_SAME(TOKEN_USER, ULONG, ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE), 26 /* TokenGroups */ 27 IQS_SAME(TOKEN_GROUPS, ULONG, ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE), 28 /* TokenPrivileges */ 29 IQS_SAME(TOKEN_PRIVILEGES, ULONG, ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE), 30 /* TokenOwner */ 31 IQS_SAME(TOKEN_OWNER, ULONG, ICIF_QUERY | ICIF_SET | ICIF_SIZE_VARIABLE), 32 /* TokenPrimaryGroup */ 33 IQS_SAME(TOKEN_PRIMARY_GROUP, ULONG, ICIF_QUERY | ICIF_SET | ICIF_SIZE_VARIABLE), 34 /* TokenDefaultDacl */ 35 IQS_SAME(TOKEN_DEFAULT_DACL, ULONG, ICIF_QUERY | ICIF_SET | ICIF_SIZE_VARIABLE), 36 /* TokenSource */ 37 IQS_SAME(TOKEN_SOURCE, ULONG, ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE), 38 /* TokenType */ 39 IQS_SAME(TOKEN_TYPE, ULONG, ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE), 40 /* TokenImpersonationLevel */ 41 IQS_SAME(SECURITY_IMPERSONATION_LEVEL, ULONG, ICIF_QUERY), 42 /* TokenStatistics */ 43 IQS_SAME(TOKEN_STATISTICS, ULONG, ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE), 44 /* TokenRestrictedSids */ 45 IQS_SAME(TOKEN_GROUPS, ULONG, ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE), 46 /* TokenSessionId */ 47 IQS_SAME(ULONG, ULONG, ICIF_QUERY | ICIF_SET), 48 /* TokenGroupsAndPrivileges */ 49 IQS_SAME(TOKEN_GROUPS_AND_PRIVILEGES, ULONG, ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE), 50 /* TokenSessionReference */ 51 IQS_SAME(ULONG, ULONG, ICIF_SET), 52 /* TokenSandBoxInert */ 53 IQS_SAME(ULONG, ULONG, ICIF_QUERY), 54 /* TokenAuditPolicy */ 55 IQS_SAME(TOKEN_AUDIT_POLICY_INFORMATION, ULONG, ICIF_SET | ICIF_SET_SIZE_VARIABLE), 56 /* TokenOrigin */ 57 IQS_SAME(TOKEN_ORIGIN, ULONG, ICIF_QUERY | ICIF_SET), 58 }; 59 60 /* PUBLIC FUNCTIONS *****************************************************************/ 61 62 /** 63 * @brief 64 * Queries information details about the given token to the call. The difference 65 * between NtQueryInformationToken and this routine is that the system call has 66 * user mode buffer data probing and additional protection checks whereas this 67 * routine doesn't have any of these. The routine is used exclusively in kernel 68 * mode. 69 * 70 * @param[in] AccessToken 71 * An access token to be given. 72 * 73 * @param[in] TokenInformationClass 74 * Token information class. 75 * 76 * @param[out] TokenInformation 77 * Buffer with retrieved information. Such information is arbitrary, depending 78 * on the requested information class. 79 * 80 * @return 81 * Returns STATUS_SUCCESS if the operation to query the desired information 82 * has completed successfully. STATUS_INSUFFICIENT_RESOURCES is returned if 83 * pool memory allocation has failed to satisfy an operation. Otherwise 84 * STATUS_INVALID_INFO_CLASS is returned indicating that the information 85 * class provided is not supported by the routine. 86 * 87 * @remarks 88 * Only certain information classes are not implemented in this function and 89 * these are TokenOrigin, TokenGroupsAndPrivileges, TokenRestrictedSids and 90 * TokenSandBoxInert. The following classes are implemented in NtQueryInformationToken 91 * only. 92 */ 93 NTSTATUS 94 NTAPI 95 SeQueryInformationToken( 96 _In_ PACCESS_TOKEN AccessToken, 97 _In_ TOKEN_INFORMATION_CLASS TokenInformationClass, 98 _Outptr_result_buffer_(_Inexpressible_(token-dependent)) PVOID *TokenInformation) 99 { 100 NTSTATUS Status; 101 PTOKEN Token = (PTOKEN)AccessToken; 102 ULONG RequiredLength; 103 union 104 { 105 PSID PSid; 106 ULONG Ulong; 107 } Unused; 108 109 PAGED_CODE(); 110 111 /* Lock the token */ 112 SepAcquireTokenLockShared(Token); 113 114 switch (TokenInformationClass) 115 { 116 case TokenUser: 117 { 118 PTOKEN_USER tu; 119 120 DPRINT("SeQueryInformationToken(TokenUser)\n"); 121 RequiredLength = sizeof(TOKEN_USER) + 122 RtlLengthSid(Token->UserAndGroups[0].Sid); 123 124 /* Allocate the output buffer */ 125 tu = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE); 126 if (tu == NULL) 127 { 128 Status = STATUS_INSUFFICIENT_RESOURCES; 129 break; 130 } 131 132 Status = RtlCopySidAndAttributesArray(1, 133 &Token->UserAndGroups[0], 134 RequiredLength - sizeof(TOKEN_USER), 135 &tu->User, 136 (PSID)(tu + 1), 137 &Unused.PSid, 138 &Unused.Ulong); 139 140 /* Return the structure */ 141 *TokenInformation = tu; 142 Status = STATUS_SUCCESS; 143 break; 144 } 145 146 case TokenGroups: 147 { 148 PTOKEN_GROUPS tg; 149 ULONG SidLen; 150 PSID Sid; 151 152 DPRINT("SeQueryInformationToken(TokenGroups)\n"); 153 RequiredLength = sizeof(tg->GroupCount) + 154 RtlLengthSidAndAttributes(Token->UserAndGroupCount - 1, &Token->UserAndGroups[1]); 155 156 SidLen = RequiredLength - sizeof(tg->GroupCount) - 157 ((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES)); 158 159 /* Allocate the output buffer */ 160 tg = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE); 161 if (tg == NULL) 162 { 163 Status = STATUS_INSUFFICIENT_RESOURCES; 164 break; 165 } 166 167 Sid = (PSID)((ULONG_PTR)tg + sizeof(tg->GroupCount) + 168 ((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES))); 169 170 tg->GroupCount = Token->UserAndGroupCount - 1; 171 Status = RtlCopySidAndAttributesArray(Token->UserAndGroupCount - 1, 172 &Token->UserAndGroups[1], 173 SidLen, 174 &tg->Groups[0], 175 Sid, 176 &Unused.PSid, 177 &Unused.Ulong); 178 179 /* Return the structure */ 180 *TokenInformation = tg; 181 Status = STATUS_SUCCESS; 182 break; 183 } 184 185 case TokenPrivileges: 186 { 187 PTOKEN_PRIVILEGES tp; 188 189 DPRINT("SeQueryInformationToken(TokenPrivileges)\n"); 190 RequiredLength = sizeof(tp->PrivilegeCount) + 191 (Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES)); 192 193 /* Allocate the output buffer */ 194 tp = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE); 195 if (tp == NULL) 196 { 197 Status = STATUS_INSUFFICIENT_RESOURCES; 198 break; 199 } 200 201 tp->PrivilegeCount = Token->PrivilegeCount; 202 RtlCopyLuidAndAttributesArray(Token->PrivilegeCount, 203 Token->Privileges, 204 &tp->Privileges[0]); 205 206 /* Return the structure */ 207 *TokenInformation = tp; 208 Status = STATUS_SUCCESS; 209 break; 210 } 211 212 case TokenOwner: 213 { 214 PTOKEN_OWNER to; 215 ULONG SidLen; 216 217 DPRINT("SeQueryInformationToken(TokenOwner)\n"); 218 SidLen = RtlLengthSid(Token->UserAndGroups[Token->DefaultOwnerIndex].Sid); 219 RequiredLength = sizeof(TOKEN_OWNER) + SidLen; 220 221 /* Allocate the output buffer */ 222 to = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE); 223 if (to == NULL) 224 { 225 Status = STATUS_INSUFFICIENT_RESOURCES; 226 break; 227 } 228 229 to->Owner = (PSID)(to + 1); 230 Status = RtlCopySid(SidLen, 231 to->Owner, 232 Token->UserAndGroups[Token->DefaultOwnerIndex].Sid); 233 234 /* Return the structure */ 235 *TokenInformation = to; 236 Status = STATUS_SUCCESS; 237 break; 238 } 239 240 case TokenPrimaryGroup: 241 { 242 PTOKEN_PRIMARY_GROUP tpg; 243 ULONG SidLen; 244 245 DPRINT("SeQueryInformationToken(TokenPrimaryGroup)\n"); 246 SidLen = RtlLengthSid(Token->PrimaryGroup); 247 RequiredLength = sizeof(TOKEN_PRIMARY_GROUP) + SidLen; 248 249 /* Allocate the output buffer */ 250 tpg = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE); 251 if (tpg == NULL) 252 { 253 Status = STATUS_INSUFFICIENT_RESOURCES; 254 break; 255 } 256 257 tpg->PrimaryGroup = (PSID)(tpg + 1); 258 Status = RtlCopySid(SidLen, 259 tpg->PrimaryGroup, 260 Token->PrimaryGroup); 261 262 /* Return the structure */ 263 *TokenInformation = tpg; 264 Status = STATUS_SUCCESS; 265 break; 266 } 267 268 case TokenDefaultDacl: 269 { 270 PTOKEN_DEFAULT_DACL tdd; 271 272 DPRINT("SeQueryInformationToken(TokenDefaultDacl)\n"); 273 RequiredLength = sizeof(TOKEN_DEFAULT_DACL); 274 275 if (Token->DefaultDacl != NULL) 276 RequiredLength += Token->DefaultDacl->AclSize; 277 278 /* Allocate the output buffer */ 279 tdd = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE); 280 if (tdd == NULL) 281 { 282 Status = STATUS_INSUFFICIENT_RESOURCES; 283 break; 284 } 285 286 if (Token->DefaultDacl != NULL) 287 { 288 tdd->DefaultDacl = (PACL)(tdd + 1); 289 RtlCopyMemory(tdd->DefaultDacl, 290 Token->DefaultDacl, 291 Token->DefaultDacl->AclSize); 292 } 293 else 294 { 295 tdd->DefaultDacl = NULL; 296 } 297 298 /* Return the structure */ 299 *TokenInformation = tdd; 300 Status = STATUS_SUCCESS; 301 break; 302 } 303 304 case TokenSource: 305 { 306 PTOKEN_SOURCE ts; 307 308 DPRINT("SeQueryInformationToken(TokenSource)\n"); 309 RequiredLength = sizeof(TOKEN_SOURCE); 310 311 /* Allocate the output buffer */ 312 ts = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE); 313 if (ts == NULL) 314 { 315 Status = STATUS_INSUFFICIENT_RESOURCES; 316 break; 317 } 318 319 *ts = Token->TokenSource; 320 321 /* Return the structure */ 322 *TokenInformation = ts; 323 Status = STATUS_SUCCESS; 324 break; 325 } 326 327 case TokenType: 328 { 329 PTOKEN_TYPE tt; 330 331 DPRINT("SeQueryInformationToken(TokenType)\n"); 332 RequiredLength = sizeof(TOKEN_TYPE); 333 334 /* Allocate the output buffer */ 335 tt = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE); 336 if (tt == NULL) 337 { 338 Status = STATUS_INSUFFICIENT_RESOURCES; 339 break; 340 } 341 342 *tt = Token->TokenType; 343 344 /* Return the structure */ 345 *TokenInformation = tt; 346 Status = STATUS_SUCCESS; 347 break; 348 } 349 350 case TokenImpersonationLevel: 351 { 352 PSECURITY_IMPERSONATION_LEVEL sil; 353 354 DPRINT("SeQueryInformationToken(TokenImpersonationLevel)\n"); 355 RequiredLength = sizeof(SECURITY_IMPERSONATION_LEVEL); 356 357 /* Fail if the token is not an impersonation token */ 358 if (Token->TokenType != TokenImpersonation) 359 { 360 Status = STATUS_INVALID_INFO_CLASS; 361 break; 362 } 363 364 /* Allocate the output buffer */ 365 sil = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE); 366 if (sil == NULL) 367 { 368 Status = STATUS_INSUFFICIENT_RESOURCES; 369 break; 370 } 371 372 *sil = Token->ImpersonationLevel; 373 374 /* Return the structure */ 375 *TokenInformation = sil; 376 Status = STATUS_SUCCESS; 377 break; 378 } 379 380 case TokenStatistics: 381 { 382 PTOKEN_STATISTICS ts; 383 384 DPRINT("SeQueryInformationToken(TokenStatistics)\n"); 385 RequiredLength = sizeof(TOKEN_STATISTICS); 386 387 /* Allocate the output buffer */ 388 ts = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE); 389 if (ts == NULL) 390 { 391 Status = STATUS_INSUFFICIENT_RESOURCES; 392 break; 393 } 394 395 ts->TokenId = Token->TokenId; 396 ts->AuthenticationId = Token->AuthenticationId; 397 ts->ExpirationTime = Token->ExpirationTime; 398 ts->TokenType = Token->TokenType; 399 ts->ImpersonationLevel = Token->ImpersonationLevel; 400 ts->DynamicCharged = Token->DynamicCharged; 401 ts->DynamicAvailable = SepComputeAvailableDynamicSpace(Token->DynamicCharged, Token->PrimaryGroup, Token->DefaultDacl); 402 ts->GroupCount = Token->UserAndGroupCount - 1; 403 ts->PrivilegeCount = Token->PrivilegeCount; 404 ts->ModifiedId = Token->ModifiedId; 405 406 /* Return the structure */ 407 *TokenInformation = ts; 408 Status = STATUS_SUCCESS; 409 break; 410 } 411 412 case TokenSessionId: 413 { 414 DPRINT("SeQueryInformationToken(TokenSessionId)\n"); 415 Status = SeQuerySessionIdToken(Token, (PULONG)TokenInformation); 416 break; 417 } 418 419 default: 420 DPRINT1("SeQueryInformationToken(%d) invalid information class\n", TokenInformationClass); 421 Status = STATUS_INVALID_INFO_CLASS; 422 break; 423 } 424 425 /* Release the lock of the token */ 426 SepReleaseTokenLock(Token); 427 428 return Status; 429 } 430 431 /* SYSTEM CALLS ***************************************************************/ 432 433 /** 434 * @brief 435 * Queries a specific type of information in regard of an access token based upon 436 * the information class. The calling thread must have specific access rights in order 437 * to obtain specific information about the token. 438 * 439 * @param[in] TokenHandle 440 * A handle of a token where information is to be gathered. 441 * 442 * @param[in] TokenInformationClass 443 * Token information class. 444 * 445 * @param[out] TokenInformation 446 * A returned output buffer with token information, which information is arbitrarily upon 447 * the information class chosen. 448 * 449 * @param[in] TokenInformationLength 450 * Length of the token information buffer, in bytes. 451 * 452 * @param[out] ReturnLength 453 * A pointer to a variable provided by the caller that receives the actual length 454 * of the buffer pointed by TokenInformation, in bytes. If TokenInformation is NULL 455 * and TokenInformationLength is 0, this parameter receives the required length 456 * needed to store the buffer information in memory. This parameter must not 457 * be NULL! 458 * 459 * @return 460 * Returns STATUS_SUCCESS if information querying has completed successfully. 461 * STATUS_BUFFER_TOO_SMALL is returned if the information length that represents 462 * the token information buffer is not greater than the required length. 463 * STATUS_INVALID_HANDLE is returned if the token handle is not a valid one. 464 * STATUS_INVALID_INFO_CLASS is returned if the information class is not a valid 465 * one (that is, the class doesn't belong to TOKEN_INFORMATION_CLASS). 466 * STATUS_ACCESS_VIOLATION is returned if ReturnLength is NULL. A failure NTSTATUS 467 * code is returned otherwise. 468 */ 469 _Must_inspect_result_ 470 __kernel_entry 471 NTSTATUS 472 NTAPI 473 NtQueryInformationToken( 474 _In_ HANDLE TokenHandle, 475 _In_ TOKEN_INFORMATION_CLASS TokenInformationClass, 476 _Out_writes_bytes_to_opt_(TokenInformationLength, *ReturnLength) 477 PVOID TokenInformation, 478 _In_ ULONG TokenInformationLength, 479 _Out_ PULONG ReturnLength) 480 { 481 NTSTATUS Status; 482 KPROCESSOR_MODE PreviousMode; 483 PTOKEN Token; 484 ULONG RequiredLength = 0; 485 union 486 { 487 PSID PSid; 488 ULONG Ulong; 489 } Unused; 490 491 PAGED_CODE(); 492 493 PreviousMode = ExGetPreviousMode(); 494 495 /* Check buffers and class validity */ 496 Status = DefaultQueryInfoBufferCheck(TokenInformationClass, 497 SeTokenInformationClass, 498 RTL_NUMBER_OF(SeTokenInformationClass), 499 ICIF_PROBE_READ_WRITE | ICIF_FORCE_RETURN_LENGTH_PROBE, 500 TokenInformation, 501 TokenInformationLength, 502 ReturnLength, 503 NULL, 504 PreviousMode); 505 if (!NT_SUCCESS(Status)) 506 { 507 DPRINT("NtQueryInformationToken() failed, Status: 0x%x\n", Status); 508 return Status; 509 } 510 511 Status = ObReferenceObjectByHandle(TokenHandle, 512 (TokenInformationClass == TokenSource) ? TOKEN_QUERY_SOURCE : TOKEN_QUERY, 513 SeTokenObjectType, 514 PreviousMode, 515 (PVOID*)&Token, 516 NULL); 517 if (NT_SUCCESS(Status)) 518 { 519 /* Lock the token */ 520 SepAcquireTokenLockShared(Token); 521 522 switch (TokenInformationClass) 523 { 524 case TokenUser: 525 { 526 PTOKEN_USER tu = (PTOKEN_USER)TokenInformation; 527 528 DPRINT("NtQueryInformationToken(TokenUser)\n"); 529 RequiredLength = sizeof(TOKEN_USER) + 530 RtlLengthSid(Token->UserAndGroups[0].Sid); 531 532 _SEH2_TRY 533 { 534 if (TokenInformationLength >= RequiredLength) 535 { 536 Status = RtlCopySidAndAttributesArray(1, 537 &Token->UserAndGroups[0], 538 RequiredLength - sizeof(TOKEN_USER), 539 &tu->User, 540 (PSID)(tu + 1), 541 &Unused.PSid, 542 &Unused.Ulong); 543 } 544 else 545 { 546 Status = STATUS_BUFFER_TOO_SMALL; 547 } 548 549 *ReturnLength = RequiredLength; 550 } 551 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 552 { 553 Status = _SEH2_GetExceptionCode(); 554 } 555 _SEH2_END; 556 557 break; 558 } 559 560 case TokenGroups: 561 { 562 PTOKEN_GROUPS tg = (PTOKEN_GROUPS)TokenInformation; 563 564 DPRINT("NtQueryInformationToken(TokenGroups)\n"); 565 RequiredLength = sizeof(tg->GroupCount) + 566 RtlLengthSidAndAttributes(Token->UserAndGroupCount - 1, &Token->UserAndGroups[1]); 567 568 _SEH2_TRY 569 { 570 if (TokenInformationLength >= RequiredLength) 571 { 572 ULONG SidLen = RequiredLength - sizeof(tg->GroupCount) - 573 ((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES)); 574 PSID Sid = (PSID_AND_ATTRIBUTES)((ULONG_PTR)tg + sizeof(tg->GroupCount) + 575 ((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES))); 576 577 tg->GroupCount = Token->UserAndGroupCount - 1; 578 Status = RtlCopySidAndAttributesArray(Token->UserAndGroupCount - 1, 579 &Token->UserAndGroups[1], 580 SidLen, 581 &tg->Groups[0], 582 Sid, 583 &Unused.PSid, 584 &Unused.Ulong); 585 } 586 else 587 { 588 Status = STATUS_BUFFER_TOO_SMALL; 589 } 590 591 *ReturnLength = RequiredLength; 592 } 593 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 594 { 595 Status = _SEH2_GetExceptionCode(); 596 } 597 _SEH2_END; 598 599 break; 600 } 601 602 case TokenPrivileges: 603 { 604 PTOKEN_PRIVILEGES tp = (PTOKEN_PRIVILEGES)TokenInformation; 605 606 DPRINT("NtQueryInformationToken(TokenPrivileges)\n"); 607 RequiredLength = sizeof(tp->PrivilegeCount) + 608 (Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES)); 609 610 _SEH2_TRY 611 { 612 if (TokenInformationLength >= RequiredLength) 613 { 614 tp->PrivilegeCount = Token->PrivilegeCount; 615 RtlCopyLuidAndAttributesArray(Token->PrivilegeCount, 616 Token->Privileges, 617 &tp->Privileges[0]); 618 } 619 else 620 { 621 Status = STATUS_BUFFER_TOO_SMALL; 622 } 623 624 *ReturnLength = RequiredLength; 625 } 626 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 627 { 628 Status = _SEH2_GetExceptionCode(); 629 } 630 _SEH2_END; 631 632 break; 633 } 634 635 case TokenOwner: 636 { 637 PTOKEN_OWNER to = (PTOKEN_OWNER)TokenInformation; 638 ULONG SidLen; 639 640 DPRINT("NtQueryInformationToken(TokenOwner)\n"); 641 SidLen = RtlLengthSid(Token->UserAndGroups[Token->DefaultOwnerIndex].Sid); 642 RequiredLength = sizeof(TOKEN_OWNER) + SidLen; 643 644 _SEH2_TRY 645 { 646 if (TokenInformationLength >= RequiredLength) 647 { 648 to->Owner = (PSID)(to + 1); 649 Status = RtlCopySid(SidLen, 650 to->Owner, 651 Token->UserAndGroups[Token->DefaultOwnerIndex].Sid); 652 } 653 else 654 { 655 Status = STATUS_BUFFER_TOO_SMALL; 656 } 657 658 *ReturnLength = RequiredLength; 659 } 660 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 661 { 662 Status = _SEH2_GetExceptionCode(); 663 } 664 _SEH2_END; 665 666 break; 667 } 668 669 case TokenPrimaryGroup: 670 { 671 PTOKEN_PRIMARY_GROUP tpg = (PTOKEN_PRIMARY_GROUP)TokenInformation; 672 ULONG SidLen; 673 674 DPRINT("NtQueryInformationToken(TokenPrimaryGroup)\n"); 675 SidLen = RtlLengthSid(Token->PrimaryGroup); 676 RequiredLength = sizeof(TOKEN_PRIMARY_GROUP) + SidLen; 677 678 _SEH2_TRY 679 { 680 if (TokenInformationLength >= RequiredLength) 681 { 682 tpg->PrimaryGroup = (PSID)(tpg + 1); 683 Status = RtlCopySid(SidLen, 684 tpg->PrimaryGroup, 685 Token->PrimaryGroup); 686 } 687 else 688 { 689 Status = STATUS_BUFFER_TOO_SMALL; 690 } 691 692 *ReturnLength = RequiredLength; 693 } 694 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 695 { 696 Status = _SEH2_GetExceptionCode(); 697 } 698 _SEH2_END; 699 700 break; 701 } 702 703 case TokenDefaultDacl: 704 { 705 PTOKEN_DEFAULT_DACL tdd = (PTOKEN_DEFAULT_DACL)TokenInformation; 706 707 DPRINT("NtQueryInformationToken(TokenDefaultDacl)\n"); 708 RequiredLength = sizeof(TOKEN_DEFAULT_DACL); 709 710 if (Token->DefaultDacl != NULL) 711 RequiredLength += Token->DefaultDacl->AclSize; 712 713 _SEH2_TRY 714 { 715 if (TokenInformationLength >= RequiredLength) 716 { 717 if (Token->DefaultDacl != NULL) 718 { 719 tdd->DefaultDacl = (PACL)(tdd + 1); 720 RtlCopyMemory(tdd->DefaultDacl, 721 Token->DefaultDacl, 722 Token->DefaultDacl->AclSize); 723 } 724 else 725 { 726 tdd->DefaultDacl = NULL; 727 } 728 } 729 else 730 { 731 Status = STATUS_BUFFER_TOO_SMALL; 732 } 733 734 *ReturnLength = RequiredLength; 735 } 736 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 737 { 738 Status = _SEH2_GetExceptionCode(); 739 } 740 _SEH2_END; 741 742 break; 743 } 744 745 case TokenSource: 746 { 747 PTOKEN_SOURCE ts = (PTOKEN_SOURCE)TokenInformation; 748 749 DPRINT("NtQueryInformationToken(TokenSource)\n"); 750 RequiredLength = sizeof(TOKEN_SOURCE); 751 752 _SEH2_TRY 753 { 754 if (TokenInformationLength >= RequiredLength) 755 { 756 *ts = Token->TokenSource; 757 } 758 else 759 { 760 Status = STATUS_BUFFER_TOO_SMALL; 761 } 762 763 *ReturnLength = RequiredLength; 764 } 765 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 766 { 767 Status = _SEH2_GetExceptionCode(); 768 } 769 _SEH2_END; 770 771 break; 772 } 773 774 case TokenType: 775 { 776 PTOKEN_TYPE tt = (PTOKEN_TYPE)TokenInformation; 777 778 DPRINT("NtQueryInformationToken(TokenType)\n"); 779 RequiredLength = sizeof(TOKEN_TYPE); 780 781 _SEH2_TRY 782 { 783 if (TokenInformationLength >= RequiredLength) 784 { 785 *tt = Token->TokenType; 786 } 787 else 788 { 789 Status = STATUS_BUFFER_TOO_SMALL; 790 } 791 792 *ReturnLength = RequiredLength; 793 } 794 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 795 { 796 Status = _SEH2_GetExceptionCode(); 797 } 798 _SEH2_END; 799 800 break; 801 } 802 803 case TokenImpersonationLevel: 804 { 805 PSECURITY_IMPERSONATION_LEVEL sil = (PSECURITY_IMPERSONATION_LEVEL)TokenInformation; 806 807 DPRINT("NtQueryInformationToken(TokenImpersonationLevel)\n"); 808 809 /* Fail if the token is not an impersonation token */ 810 if (Token->TokenType != TokenImpersonation) 811 { 812 Status = STATUS_INVALID_INFO_CLASS; 813 break; 814 } 815 816 RequiredLength = sizeof(SECURITY_IMPERSONATION_LEVEL); 817 818 _SEH2_TRY 819 { 820 if (TokenInformationLength >= RequiredLength) 821 { 822 *sil = Token->ImpersonationLevel; 823 } 824 else 825 { 826 Status = STATUS_BUFFER_TOO_SMALL; 827 } 828 829 *ReturnLength = RequiredLength; 830 } 831 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 832 { 833 Status = _SEH2_GetExceptionCode(); 834 } 835 _SEH2_END; 836 837 break; 838 } 839 840 case TokenStatistics: 841 { 842 PTOKEN_STATISTICS ts = (PTOKEN_STATISTICS)TokenInformation; 843 844 DPRINT("NtQueryInformationToken(TokenStatistics)\n"); 845 RequiredLength = sizeof(TOKEN_STATISTICS); 846 847 _SEH2_TRY 848 { 849 if (TokenInformationLength >= RequiredLength) 850 { 851 ts->TokenId = Token->TokenId; 852 ts->AuthenticationId = Token->AuthenticationId; 853 ts->ExpirationTime = Token->ExpirationTime; 854 ts->TokenType = Token->TokenType; 855 ts->ImpersonationLevel = Token->ImpersonationLevel; 856 ts->DynamicCharged = Token->DynamicCharged; 857 ts->DynamicAvailable = SepComputeAvailableDynamicSpace(Token->DynamicCharged, Token->PrimaryGroup, Token->DefaultDacl); 858 ts->GroupCount = Token->UserAndGroupCount - 1; 859 ts->PrivilegeCount = Token->PrivilegeCount; 860 ts->ModifiedId = Token->ModifiedId; 861 } 862 else 863 { 864 Status = STATUS_BUFFER_TOO_SMALL; 865 } 866 867 *ReturnLength = RequiredLength; 868 } 869 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 870 { 871 Status = _SEH2_GetExceptionCode(); 872 } 873 _SEH2_END; 874 875 break; 876 } 877 878 case TokenOrigin: 879 { 880 PTOKEN_ORIGIN to = (PTOKEN_ORIGIN)TokenInformation; 881 882 DPRINT("NtQueryInformationToken(TokenOrigin)\n"); 883 RequiredLength = sizeof(TOKEN_ORIGIN); 884 885 _SEH2_TRY 886 { 887 if (TokenInformationLength >= RequiredLength) 888 { 889 to->OriginatingLogonSession = Token->AuthenticationId; 890 } 891 else 892 { 893 Status = STATUS_BUFFER_TOO_SMALL; 894 } 895 896 *ReturnLength = RequiredLength; 897 } 898 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 899 { 900 Status = _SEH2_GetExceptionCode(); 901 } 902 _SEH2_END; 903 904 break; 905 } 906 907 case TokenGroupsAndPrivileges: 908 { 909 PSID Sid, RestrictedSid; 910 ULONG SidLen, RestrictedSidLen; 911 ULONG UserGroupLength, RestrictedSidLength, PrivilegeLength; 912 PTOKEN_GROUPS_AND_PRIVILEGES GroupsAndPrivs = (PTOKEN_GROUPS_AND_PRIVILEGES)TokenInformation; 913 914 DPRINT("NtQueryInformationToken(TokenGroupsAndPrivileges)\n"); 915 UserGroupLength = RtlLengthSidAndAttributes(Token->UserAndGroupCount, Token->UserAndGroups); 916 RestrictedSidLength = RtlLengthSidAndAttributes(Token->RestrictedSidCount, Token->RestrictedSids); 917 PrivilegeLength = Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES); 918 919 RequiredLength = sizeof(TOKEN_GROUPS_AND_PRIVILEGES) + 920 UserGroupLength + RestrictedSidLength + PrivilegeLength; 921 922 _SEH2_TRY 923 { 924 if (TokenInformationLength >= RequiredLength) 925 { 926 GroupsAndPrivs->SidCount = Token->UserAndGroupCount; 927 GroupsAndPrivs->SidLength = UserGroupLength; 928 GroupsAndPrivs->Sids = (PSID_AND_ATTRIBUTES)(GroupsAndPrivs + 1); 929 930 Sid = (PSID)((ULONG_PTR)GroupsAndPrivs->Sids + (Token->UserAndGroupCount * sizeof(SID_AND_ATTRIBUTES))); 931 SidLen = UserGroupLength - (Token->UserAndGroupCount * sizeof(SID_AND_ATTRIBUTES)); 932 Status = RtlCopySidAndAttributesArray(Token->UserAndGroupCount, 933 Token->UserAndGroups, 934 SidLen, 935 GroupsAndPrivs->Sids, 936 Sid, 937 &Unused.PSid, 938 &Unused.Ulong); 939 NT_ASSERT(NT_SUCCESS(Status)); 940 941 GroupsAndPrivs->RestrictedSidCount = Token->RestrictedSidCount; 942 GroupsAndPrivs->RestrictedSidLength = RestrictedSidLength; 943 GroupsAndPrivs->RestrictedSids = NULL; 944 if (SeTokenIsRestricted(Token)) 945 { 946 GroupsAndPrivs->RestrictedSids = (PSID_AND_ATTRIBUTES)((ULONG_PTR)GroupsAndPrivs->Sids + UserGroupLength); 947 948 RestrictedSid = (PSID)((ULONG_PTR)GroupsAndPrivs->RestrictedSids + (Token->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES))); 949 RestrictedSidLen = RestrictedSidLength - (Token->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES)); 950 Status = RtlCopySidAndAttributesArray(Token->RestrictedSidCount, 951 Token->RestrictedSids, 952 RestrictedSidLen, 953 GroupsAndPrivs->RestrictedSids, 954 RestrictedSid, 955 &Unused.PSid, 956 &Unused.Ulong); 957 NT_ASSERT(NT_SUCCESS(Status)); 958 } 959 960 GroupsAndPrivs->PrivilegeCount = Token->PrivilegeCount; 961 GroupsAndPrivs->PrivilegeLength = PrivilegeLength; 962 GroupsAndPrivs->Privileges = (PLUID_AND_ATTRIBUTES)((ULONG_PTR)(GroupsAndPrivs + 1) + 963 UserGroupLength + RestrictedSidLength); 964 RtlCopyLuidAndAttributesArray(Token->PrivilegeCount, 965 Token->Privileges, 966 GroupsAndPrivs->Privileges); 967 968 GroupsAndPrivs->AuthenticationId = Token->AuthenticationId; 969 } 970 else 971 { 972 Status = STATUS_BUFFER_TOO_SMALL; 973 } 974 975 *ReturnLength = RequiredLength; 976 } 977 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 978 { 979 Status = _SEH2_GetExceptionCode(); 980 } 981 _SEH2_END; 982 983 break; 984 } 985 986 case TokenRestrictedSids: 987 { 988 PTOKEN_GROUPS tg = (PTOKEN_GROUPS)TokenInformation; 989 990 DPRINT("NtQueryInformationToken(TokenRestrictedSids)\n"); 991 RequiredLength = sizeof(tg->GroupCount) + 992 RtlLengthSidAndAttributes(Token->RestrictedSidCount, Token->RestrictedSids); 993 994 _SEH2_TRY 995 { 996 if (TokenInformationLength >= RequiredLength) 997 { 998 ULONG SidLen = RequiredLength - sizeof(tg->GroupCount) - 999 (Token->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES)); 1000 PSID Sid = (PSID)((ULONG_PTR)tg + sizeof(tg->GroupCount) + 1001 (Token->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES))); 1002 1003 tg->GroupCount = Token->RestrictedSidCount; 1004 Status = RtlCopySidAndAttributesArray(Token->RestrictedSidCount, 1005 Token->RestrictedSids, 1006 SidLen, 1007 &tg->Groups[0], 1008 Sid, 1009 &Unused.PSid, 1010 &Unused.Ulong); 1011 } 1012 else 1013 { 1014 Status = STATUS_BUFFER_TOO_SMALL; 1015 } 1016 1017 *ReturnLength = RequiredLength; 1018 } 1019 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1020 { 1021 Status = _SEH2_GetExceptionCode(); 1022 } 1023 _SEH2_END; 1024 1025 break; 1026 } 1027 1028 case TokenSandBoxInert: 1029 { 1030 ULONG IsTokenSandBoxInert; 1031 1032 DPRINT("NtQueryInformationToken(TokenSandBoxInert)\n"); 1033 1034 IsTokenSandBoxInert = SeTokenIsInert(Token); 1035 _SEH2_TRY 1036 { 1037 /* Buffer size was already verified, no need to check here again */ 1038 *(PULONG)TokenInformation = IsTokenSandBoxInert; 1039 *ReturnLength = sizeof(ULONG); 1040 } 1041 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1042 { 1043 Status = _SEH2_GetExceptionCode(); 1044 } 1045 _SEH2_END; 1046 1047 break; 1048 } 1049 1050 case TokenSessionId: 1051 { 1052 ULONG SessionId = 0; 1053 1054 DPRINT("NtQueryInformationToken(TokenSessionId)\n"); 1055 1056 Status = SeQuerySessionIdToken(Token, &SessionId); 1057 if (NT_SUCCESS(Status)) 1058 { 1059 _SEH2_TRY 1060 { 1061 /* Buffer size was already verified, no need to check here again */ 1062 *(PULONG)TokenInformation = SessionId; 1063 *ReturnLength = RequiredLength; 1064 } 1065 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1066 { 1067 Status = _SEH2_GetExceptionCode(); 1068 } 1069 _SEH2_END; 1070 } 1071 1072 break; 1073 } 1074 1075 default: 1076 DPRINT1("NtQueryInformationToken(%d) invalid information class\n", TokenInformationClass); 1077 Status = STATUS_INVALID_INFO_CLASS; 1078 break; 1079 } 1080 1081 /* Unlock and dereference the token */ 1082 SepReleaseTokenLock(Token); 1083 ObDereferenceObject(Token); 1084 } 1085 1086 return Status; 1087 } 1088 1089 /** 1090 * @unimplemented 1091 * @brief 1092 * Sets (modifies) some specific information in regard of an access token. The 1093 * calling thread must have specific access rights in order to modify token's 1094 * information data. 1095 * 1096 * @param[in] TokenHandle 1097 * A handle of a token where information is to be modified. 1098 * 1099 * @param[in] TokenInformationClass 1100 * Token information class. 1101 * 1102 * @param[in] TokenInformation 1103 * An arbitrary pointer to a buffer with token information to set. Such 1104 * arbitrary buffer depends on the information class chosen that the caller 1105 * wants to modify such information data of a token. 1106 * 1107 * @param[in] TokenInformationLength 1108 * Length of the token information buffer, in bytes. 1109 * 1110 * @return 1111 * Returns STATUS_SUCCESS if information setting has completed successfully. 1112 * STATUS_INFO_LENGTH_MISMATCH is returned if the information length of the 1113 * buffer is less than the required length. STATUS_INSUFFICIENT_RESOURCES is 1114 * returned if memory pool allocation has failed. STATUS_PRIVILEGE_NOT_HELD 1115 * is returned if the calling thread hasn't the required privileges to perform 1116 * the operation in question. A failure NTSTATUS code is returned otherwise. 1117 * 1118 * @remarks 1119 * The function is partly implemented, mainly TokenOrigin. 1120 */ 1121 _Must_inspect_result_ 1122 __kernel_entry 1123 NTSTATUS 1124 NTAPI 1125 NtSetInformationToken( 1126 _In_ HANDLE TokenHandle, 1127 _In_ TOKEN_INFORMATION_CLASS TokenInformationClass, 1128 _In_reads_bytes_(TokenInformationLength) PVOID TokenInformation, 1129 _In_ ULONG TokenInformationLength) 1130 { 1131 NTSTATUS Status; 1132 PTOKEN Token; 1133 KPROCESSOR_MODE PreviousMode; 1134 ULONG NeededAccess = TOKEN_ADJUST_DEFAULT; 1135 1136 PAGED_CODE(); 1137 1138 PreviousMode = ExGetPreviousMode(); 1139 1140 Status = DefaultSetInfoBufferCheck(TokenInformationClass, 1141 SeTokenInformationClass, 1142 RTL_NUMBER_OF(SeTokenInformationClass), 1143 TokenInformation, 1144 TokenInformationLength, 1145 PreviousMode); 1146 if (!NT_SUCCESS(Status)) 1147 { 1148 /* Invalid buffers */ 1149 DPRINT("NtSetInformationToken() failed, Status: 0x%x\n", Status); 1150 return Status; 1151 } 1152 1153 if (TokenInformationClass == TokenSessionId) 1154 { 1155 NeededAccess |= TOKEN_ADJUST_SESSIONID; 1156 } 1157 1158 Status = ObReferenceObjectByHandle(TokenHandle, 1159 NeededAccess, 1160 SeTokenObjectType, 1161 PreviousMode, 1162 (PVOID*)&Token, 1163 NULL); 1164 if (NT_SUCCESS(Status)) 1165 { 1166 switch (TokenInformationClass) 1167 { 1168 case TokenOwner: 1169 { 1170 if (TokenInformationLength >= sizeof(TOKEN_OWNER)) 1171 { 1172 PTOKEN_OWNER to = (PTOKEN_OWNER)TokenInformation; 1173 PSID InputSid = NULL, CapturedSid; 1174 ULONG DefaultOwnerIndex; 1175 1176 _SEH2_TRY 1177 { 1178 InputSid = to->Owner; 1179 } 1180 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1181 { 1182 Status = _SEH2_GetExceptionCode(); 1183 _SEH2_YIELD(goto Cleanup); 1184 } 1185 _SEH2_END; 1186 1187 Status = SepCaptureSid(InputSid, 1188 PreviousMode, 1189 PagedPool, 1190 FALSE, 1191 &CapturedSid); 1192 if (NT_SUCCESS(Status)) 1193 { 1194 /* Lock the token */ 1195 SepAcquireTokenLockExclusive(Token); 1196 1197 /* Find the owner amongst the existing token user and groups */ 1198 Status = SepFindPrimaryGroupAndDefaultOwner(Token, 1199 NULL, 1200 CapturedSid, 1201 NULL, 1202 &DefaultOwnerIndex); 1203 if (NT_SUCCESS(Status)) 1204 { 1205 /* Found it */ 1206 Token->DefaultOwnerIndex = DefaultOwnerIndex; 1207 ExAllocateLocallyUniqueId(&Token->ModifiedId); 1208 } 1209 1210 /* Unlock the token */ 1211 SepReleaseTokenLock(Token); 1212 1213 SepReleaseSid(CapturedSid, 1214 PreviousMode, 1215 FALSE); 1216 } 1217 } 1218 else 1219 { 1220 Status = STATUS_INFO_LENGTH_MISMATCH; 1221 } 1222 break; 1223 } 1224 1225 case TokenPrimaryGroup: 1226 { 1227 if (TokenInformationLength >= sizeof(TOKEN_PRIMARY_GROUP)) 1228 { 1229 PTOKEN_PRIMARY_GROUP tpg = (PTOKEN_PRIMARY_GROUP)TokenInformation; 1230 ULONG AclSize; 1231 ULONG_PTR PrimaryGroup; 1232 PSID InputSid = NULL, CapturedSid; 1233 ULONG PrimaryGroupIndex, NewDynamicLength; 1234 1235 _SEH2_TRY 1236 { 1237 InputSid = tpg->PrimaryGroup; 1238 } 1239 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1240 { 1241 Status = _SEH2_GetExceptionCode(); 1242 _SEH2_YIELD(goto Cleanup); 1243 } 1244 _SEH2_END; 1245 1246 Status = SepCaptureSid(InputSid, 1247 PreviousMode, 1248 PagedPool, 1249 FALSE, 1250 &CapturedSid); 1251 if (NT_SUCCESS(Status)) 1252 { 1253 /* Lock the token */ 1254 SepAcquireTokenLockExclusive(Token); 1255 1256 /* 1257 * We can whack the token's primary group only if 1258 * the charged dynamic space boundary allows us 1259 * to do so. Exceeding this boundary and we're 1260 * busted out. 1261 */ 1262 AclSize = Token->DefaultDacl ? Token->DefaultDacl->AclSize : 0; 1263 NewDynamicLength = RtlLengthSid(CapturedSid) + AclSize; 1264 if (NewDynamicLength > Token->DynamicCharged) 1265 { 1266 SepReleaseTokenLock(Token); 1267 SepReleaseSid(CapturedSid, PreviousMode, FALSE); 1268 Status = STATUS_ALLOTTED_SPACE_EXCEEDED; 1269 DPRINT1("NtSetInformationToken(): Couldn't assign new primary group, space exceeded (current length %u, new length %lu)\n", 1270 Token->DynamicCharged, NewDynamicLength); 1271 goto Cleanup; 1272 } 1273 1274 /* 1275 * The dynamic part of the token may require a rebuild 1276 * if the current dynamic area is too small. If not then 1277 * we're pretty much good as is. 1278 */ 1279 Status = SepRebuildDynamicPartOfToken(Token, NewDynamicLength); 1280 if (NT_SUCCESS(Status)) 1281 { 1282 /* Find the primary group amongst the existing token user and groups */ 1283 Status = SepFindPrimaryGroupAndDefaultOwner(Token, 1284 CapturedSid, 1285 NULL, 1286 &PrimaryGroupIndex, 1287 NULL); 1288 if (NT_SUCCESS(Status)) 1289 { 1290 /* 1291 * We have found it. Add the length of 1292 * the previous primary group SID to the 1293 * available dynamic area. 1294 */ 1295 Token->DynamicAvailable += RtlLengthSid(Token->PrimaryGroup); 1296 1297 /* 1298 * Move the default DACL if it's not at the 1299 * head of the dynamic part. 1300 */ 1301 if ((Token->DefaultDacl) && 1302 ((PULONG)(Token->DefaultDacl) != Token->DynamicPart)) 1303 { 1304 RtlMoveMemory(Token->DynamicPart, 1305 Token->DefaultDacl, 1306 RtlLengthSid(Token->PrimaryGroup)); 1307 Token->DefaultDacl = (PACL)(Token->DynamicPart); 1308 } 1309 1310 /* Take away available space from the dynamic area */ 1311 Token->DynamicAvailable -= RtlLengthSid(Token->UserAndGroups[PrimaryGroupIndex].Sid); 1312 1313 /* 1314 * And assign the new primary group. For that 1315 * we have to make sure where the primary group 1316 * is going to stay in memory, so if this token 1317 * has a default DACL then add up its size with 1318 * the address of the dynamic part. 1319 */ 1320 PrimaryGroup = (ULONG_PTR)(Token->DynamicPart) + AclSize; 1321 RtlCopySid(RtlLengthSid(Token->UserAndGroups[PrimaryGroupIndex].Sid), 1322 (PVOID)PrimaryGroup, 1323 Token->UserAndGroups[PrimaryGroupIndex].Sid); 1324 Token->PrimaryGroup = (PSID)PrimaryGroup; 1325 1326 ExAllocateLocallyUniqueId(&Token->ModifiedId); 1327 } 1328 } 1329 1330 /* Unlock the token */ 1331 SepReleaseTokenLock(Token); 1332 1333 SepReleaseSid(CapturedSid, 1334 PreviousMode, 1335 FALSE); 1336 } 1337 } 1338 else 1339 { 1340 Status = STATUS_INFO_LENGTH_MISMATCH; 1341 } 1342 break; 1343 } 1344 1345 case TokenDefaultDacl: 1346 { 1347 if (TokenInformationLength >= sizeof(TOKEN_DEFAULT_DACL)) 1348 { 1349 PTOKEN_DEFAULT_DACL tdd = (PTOKEN_DEFAULT_DACL)TokenInformation; 1350 PACL InputAcl = NULL; 1351 1352 _SEH2_TRY 1353 { 1354 InputAcl = tdd->DefaultDacl; 1355 } 1356 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1357 { 1358 Status = _SEH2_GetExceptionCode(); 1359 _SEH2_YIELD(goto Cleanup); 1360 } 1361 _SEH2_END; 1362 1363 if (InputAcl != NULL) 1364 { 1365 PACL CapturedAcl; 1366 1367 /* Capture, validate, and copy the DACL */ 1368 Status = SepCaptureAcl(InputAcl, 1369 PreviousMode, 1370 PagedPool, 1371 TRUE, 1372 &CapturedAcl); 1373 if (NT_SUCCESS(Status)) 1374 { 1375 ULONG NewDynamicLength; 1376 ULONG_PTR Acl; 1377 1378 /* Lock the token */ 1379 SepAcquireTokenLockExclusive(Token); 1380 1381 /* 1382 * We can whack the token's default DACL only if 1383 * the charged dynamic space boundary allows us 1384 * to do so. Exceeding this boundary and we're 1385 * busted out. 1386 */ 1387 NewDynamicLength = CapturedAcl->AclSize + RtlLengthSid(Token->PrimaryGroup); 1388 if (NewDynamicLength > Token->DynamicCharged) 1389 { 1390 SepReleaseTokenLock(Token); 1391 SepReleaseAcl(CapturedAcl, PreviousMode, TRUE); 1392 Status = STATUS_ALLOTTED_SPACE_EXCEEDED; 1393 DPRINT1("NtSetInformationToken(): Couldn't assign new default DACL, space exceeded (current length %u, new length %lu)\n", 1394 Token->DynamicCharged, NewDynamicLength); 1395 goto Cleanup; 1396 } 1397 1398 /* 1399 * The dynamic part of the token may require a rebuild 1400 * if the current dynamic area is too small. If not then 1401 * we're pretty much good as is. 1402 */ 1403 Status = SepRebuildDynamicPartOfToken(Token, NewDynamicLength); 1404 if (NT_SUCCESS(Status)) 1405 { 1406 /* 1407 * Before setting up a new DACL for the 1408 * token object we add up the size of 1409 * the old DACL to the available dynamic 1410 * area 1411 */ 1412 if (Token->DefaultDacl) 1413 { 1414 Token->DynamicAvailable += Token->DefaultDacl->AclSize; 1415 } 1416 1417 /* 1418 * Move the primary group if it's not at the 1419 * head of the dynamic part. 1420 */ 1421 if ((PULONG)(Token->PrimaryGroup) != Token->DynamicPart) 1422 { 1423 RtlMoveMemory(Token->DynamicPart, 1424 Token->PrimaryGroup, 1425 RtlLengthSid(Token->PrimaryGroup)); 1426 Token->PrimaryGroup = (PSID)(Token->DynamicPart); 1427 } 1428 1429 /* Take away available space from the dynamic area */ 1430 Token->DynamicAvailable -= CapturedAcl->AclSize; 1431 1432 /* Set the new dacl */ 1433 Acl = (ULONG_PTR)(Token->DynamicPart) + RtlLengthSid(Token->PrimaryGroup); 1434 RtlCopyMemory((PVOID)Acl, 1435 CapturedAcl, 1436 CapturedAcl->AclSize); 1437 Token->DefaultDacl = (PACL)Acl; 1438 1439 ExAllocateLocallyUniqueId(&Token->ModifiedId); 1440 } 1441 1442 /* Unlock the token and release the ACL */ 1443 SepReleaseTokenLock(Token); 1444 SepReleaseAcl(CapturedAcl, PreviousMode, TRUE); 1445 } 1446 } 1447 else 1448 { 1449 /* Lock the token */ 1450 SepAcquireTokenLockExclusive(Token); 1451 1452 /* Clear the default dacl if present */ 1453 if (Token->DefaultDacl != NULL) 1454 { 1455 Token->DynamicAvailable += Token->DefaultDacl->AclSize; 1456 RtlZeroMemory(Token->DefaultDacl, Token->DefaultDacl->AclSize); 1457 Token->DefaultDacl = NULL; 1458 1459 ExAllocateLocallyUniqueId(&Token->ModifiedId); 1460 } 1461 1462 /* Unlock the token */ 1463 SepReleaseTokenLock(Token); 1464 } 1465 } 1466 else 1467 { 1468 Status = STATUS_INFO_LENGTH_MISMATCH; 1469 } 1470 break; 1471 } 1472 1473 case TokenSessionId: 1474 { 1475 ULONG SessionId = 0; 1476 1477 _SEH2_TRY 1478 { 1479 /* Buffer size was already verified, no need to check here again */ 1480 SessionId = *(PULONG)TokenInformation; 1481 } 1482 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1483 { 1484 Status = _SEH2_GetExceptionCode(); 1485 _SEH2_YIELD(goto Cleanup); 1486 } 1487 _SEH2_END; 1488 1489 /* Check for TCB privilege */ 1490 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode)) 1491 { 1492 Status = STATUS_PRIVILEGE_NOT_HELD; 1493 break; 1494 } 1495 1496 /* Lock the token */ 1497 SepAcquireTokenLockExclusive(Token); 1498 1499 Token->SessionId = SessionId; 1500 ExAllocateLocallyUniqueId(&Token->ModifiedId); 1501 1502 /* Unlock the token */ 1503 SepReleaseTokenLock(Token); 1504 1505 break; 1506 } 1507 1508 case TokenSessionReference: 1509 { 1510 ULONG SessionReference; 1511 1512 _SEH2_TRY 1513 { 1514 /* Buffer size was already verified, no need to check here again */ 1515 SessionReference = *(PULONG)TokenInformation; 1516 } 1517 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1518 { 1519 Status = _SEH2_GetExceptionCode(); 1520 _SEH2_YIELD(goto Cleanup); 1521 } 1522 _SEH2_END; 1523 1524 /* Check for TCB privilege */ 1525 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode)) 1526 { 1527 Status = STATUS_PRIVILEGE_NOT_HELD; 1528 goto Cleanup; 1529 } 1530 1531 /* Check if it is 0 */ 1532 if (SessionReference == 0) 1533 { 1534 ULONG OldTokenFlags; 1535 1536 /* Lock the token */ 1537 SepAcquireTokenLockExclusive(Token); 1538 1539 /* Atomically set the flag in the token */ 1540 OldTokenFlags = RtlInterlockedSetBits(&Token->TokenFlags, 1541 TOKEN_SESSION_NOT_REFERENCED); 1542 /* 1543 * If the flag was already set, do not dereference again 1544 * the logon session. Use SessionReference as an indicator 1545 * to know whether to really dereference the session. 1546 */ 1547 if (OldTokenFlags == Token->TokenFlags) 1548 SessionReference = ULONG_MAX; 1549 1550 /* 1551 * Otherwise if the flag was never set but just for this first time then 1552 * remove the referenced logon session data from the token and dereference 1553 * the logon session when needed. 1554 */ 1555 if (SessionReference == 0) 1556 { 1557 SepRmRemoveLogonSessionFromToken(Token); 1558 SepRmDereferenceLogonSession(&Token->AuthenticationId); 1559 } 1560 1561 /* Unlock the token */ 1562 SepReleaseTokenLock(Token); 1563 } 1564 break; 1565 } 1566 1567 case TokenAuditPolicy: 1568 { 1569 PTOKEN_AUDIT_POLICY_INFORMATION PolicyInformation = 1570 (PTOKEN_AUDIT_POLICY_INFORMATION)TokenInformation; 1571 SEP_AUDIT_POLICY AuditPolicy; 1572 ULONG i; 1573 1574 _SEH2_TRY 1575 { 1576 ProbeForRead(PolicyInformation, 1577 FIELD_OFFSET(TOKEN_AUDIT_POLICY_INFORMATION, 1578 Policies[PolicyInformation->PolicyCount]), 1579 sizeof(ULONG)); 1580 1581 /* Loop all policies in the structure */ 1582 for (i = 0; i < PolicyInformation->PolicyCount; i++) 1583 { 1584 /* Set the corresponding bits in the packed structure */ 1585 switch (PolicyInformation->Policies[i].Category) 1586 { 1587 case AuditCategorySystem: 1588 AuditPolicy.PolicyElements.System = PolicyInformation->Policies[i].Value; 1589 break; 1590 1591 case AuditCategoryLogon: 1592 AuditPolicy.PolicyElements.Logon = PolicyInformation->Policies[i].Value; 1593 break; 1594 1595 case AuditCategoryObjectAccess: 1596 AuditPolicy.PolicyElements.ObjectAccess = PolicyInformation->Policies[i].Value; 1597 break; 1598 1599 case AuditCategoryPrivilegeUse: 1600 AuditPolicy.PolicyElements.PrivilegeUse = PolicyInformation->Policies[i].Value; 1601 break; 1602 1603 case AuditCategoryDetailedTracking: 1604 AuditPolicy.PolicyElements.DetailedTracking = PolicyInformation->Policies[i].Value; 1605 break; 1606 1607 case AuditCategoryPolicyChange: 1608 AuditPolicy.PolicyElements.PolicyChange = PolicyInformation->Policies[i].Value; 1609 break; 1610 1611 case AuditCategoryAccountManagement: 1612 AuditPolicy.PolicyElements.AccountManagement = PolicyInformation->Policies[i].Value; 1613 break; 1614 1615 case AuditCategoryDirectoryServiceAccess: 1616 AuditPolicy.PolicyElements.DirectoryServiceAccess = PolicyInformation->Policies[i].Value; 1617 break; 1618 1619 case AuditCategoryAccountLogon: 1620 AuditPolicy.PolicyElements.AccountLogon = PolicyInformation->Policies[i].Value; 1621 break; 1622 } 1623 } 1624 } 1625 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1626 { 1627 Status = _SEH2_GetExceptionCode(); 1628 _SEH2_YIELD(goto Cleanup); 1629 } 1630 _SEH2_END; 1631 1632 /* Check for TCB privilege */ 1633 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode)) 1634 { 1635 Status = STATUS_PRIVILEGE_NOT_HELD; 1636 break; 1637 } 1638 1639 /* Lock the token */ 1640 SepAcquireTokenLockExclusive(Token); 1641 1642 /* Set the new audit policy */ 1643 Token->AuditPolicy = AuditPolicy; 1644 ExAllocateLocallyUniqueId(&Token->ModifiedId); 1645 1646 /* Unlock the token */ 1647 SepReleaseTokenLock(Token); 1648 1649 break; 1650 } 1651 1652 case TokenOrigin: 1653 { 1654 TOKEN_ORIGIN TokenOrigin; 1655 1656 _SEH2_TRY 1657 { 1658 /* Copy the token origin */ 1659 TokenOrigin = *(PTOKEN_ORIGIN)TokenInformation; 1660 } 1661 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1662 { 1663 Status = _SEH2_GetExceptionCode(); 1664 _SEH2_YIELD(goto Cleanup); 1665 } 1666 _SEH2_END; 1667 1668 /* Check for TCB privilege */ 1669 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode)) 1670 { 1671 Status = STATUS_PRIVILEGE_NOT_HELD; 1672 break; 1673 } 1674 1675 /* Lock the token */ 1676 SepAcquireTokenLockExclusive(Token); 1677 1678 /* Check if there is no token origin set yet */ 1679 if (RtlIsZeroLuid(&Token->OriginatingLogonSession)) 1680 { 1681 /* Set the token origin */ 1682 Token->OriginatingLogonSession = 1683 TokenOrigin.OriginatingLogonSession; 1684 1685 ExAllocateLocallyUniqueId(&Token->ModifiedId); 1686 } 1687 1688 /* Unlock the token */ 1689 SepReleaseTokenLock(Token); 1690 1691 break; 1692 } 1693 1694 default: 1695 { 1696 DPRINT1("Invalid TokenInformationClass: 0x%lx\n", 1697 TokenInformationClass); 1698 Status = STATUS_INVALID_INFO_CLASS; 1699 break; 1700 } 1701 } 1702 Cleanup: 1703 ObDereferenceObject(Token); 1704 } 1705 1706 if (!NT_SUCCESS(Status)) 1707 { 1708 DPRINT1("NtSetInformationToken failed with Status 0x%lx\n", Status); 1709 } 1710 1711 return Status; 1712 } 1713 1714 /* EOF */ 1715