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 = Token->DynamicAvailable; 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 = Token->DynamicAvailable; 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 and TokenDefaultDacl. 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 PSID InputSid = NULL, CapturedSid; 1231 ULONG PrimaryGroupIndex; 1232 1233 _SEH2_TRY 1234 { 1235 InputSid = tpg->PrimaryGroup; 1236 } 1237 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1238 { 1239 Status = _SEH2_GetExceptionCode(); 1240 _SEH2_YIELD(goto Cleanup); 1241 } 1242 _SEH2_END; 1243 1244 Status = SepCaptureSid(InputSid, 1245 PreviousMode, 1246 PagedPool, 1247 FALSE, 1248 &CapturedSid); 1249 if (NT_SUCCESS(Status)) 1250 { 1251 /* Lock the token */ 1252 SepAcquireTokenLockExclusive(Token); 1253 1254 /* Find the primary group amongst the existing token user and groups */ 1255 Status = SepFindPrimaryGroupAndDefaultOwner(Token, 1256 CapturedSid, 1257 NULL, 1258 &PrimaryGroupIndex, 1259 NULL); 1260 if (NT_SUCCESS(Status)) 1261 { 1262 /* Found it */ 1263 Token->PrimaryGroup = Token->UserAndGroups[PrimaryGroupIndex].Sid; 1264 ExAllocateLocallyUniqueId(&Token->ModifiedId); 1265 } 1266 1267 /* Unlock the token */ 1268 SepReleaseTokenLock(Token); 1269 1270 SepReleaseSid(CapturedSid, 1271 PreviousMode, 1272 FALSE); 1273 } 1274 } 1275 else 1276 { 1277 Status = STATUS_INFO_LENGTH_MISMATCH; 1278 } 1279 break; 1280 } 1281 1282 case TokenDefaultDacl: 1283 { 1284 if (TokenInformationLength >= sizeof(TOKEN_DEFAULT_DACL)) 1285 { 1286 PTOKEN_DEFAULT_DACL tdd = (PTOKEN_DEFAULT_DACL)TokenInformation; 1287 PACL InputAcl = NULL; 1288 1289 _SEH2_TRY 1290 { 1291 InputAcl = tdd->DefaultDacl; 1292 } 1293 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1294 { 1295 Status = _SEH2_GetExceptionCode(); 1296 _SEH2_YIELD(goto Cleanup); 1297 } 1298 _SEH2_END; 1299 1300 if (InputAcl != NULL) 1301 { 1302 PACL CapturedAcl; 1303 1304 /* Capture, validate, and copy the DACL */ 1305 Status = SepCaptureAcl(InputAcl, 1306 PreviousMode, 1307 PagedPool, 1308 TRUE, 1309 &CapturedAcl); 1310 if (NT_SUCCESS(Status)) 1311 { 1312 ULONG DynamicLength; 1313 1314 /* Lock the token */ 1315 SepAcquireTokenLockExclusive(Token); 1316 1317 // 1318 // NOTE: So far our dynamic area only contains 1319 // the default dacl, so this makes the following 1320 // code pretty simple. The day where it stores 1321 // other data, the code will require adaptations. 1322 // 1323 1324 DynamicLength = Token->DynamicAvailable; 1325 // Add here any other data length present in the dynamic area... 1326 if (Token->DefaultDacl) 1327 DynamicLength += Token->DefaultDacl->AclSize; 1328 1329 /* Reallocate the dynamic area if it is too small */ 1330 Status = STATUS_SUCCESS; 1331 if ((DynamicLength < CapturedAcl->AclSize) || 1332 (Token->DynamicPart == NULL)) 1333 { 1334 PVOID NewDynamicPart; 1335 1336 NewDynamicPart = ExAllocatePoolWithTag(PagedPool, 1337 CapturedAcl->AclSize, 1338 TAG_TOKEN_DYNAMIC); 1339 if (NewDynamicPart == NULL) 1340 { 1341 Status = STATUS_INSUFFICIENT_RESOURCES; 1342 } 1343 else 1344 { 1345 if (Token->DynamicPart != NULL) 1346 { 1347 // RtlCopyMemory(NewDynamicPart, Token->DynamicPart, DynamicLength); 1348 ExFreePoolWithTag(Token->DynamicPart, TAG_TOKEN_DYNAMIC); 1349 } 1350 Token->DynamicPart = NewDynamicPart; 1351 Token->DynamicAvailable = 0; 1352 } 1353 } 1354 else 1355 { 1356 Token->DynamicAvailable = DynamicLength - CapturedAcl->AclSize; 1357 } 1358 1359 if (NT_SUCCESS(Status)) 1360 { 1361 /* Set the new dacl */ 1362 Token->DefaultDacl = (PVOID)Token->DynamicPart; 1363 RtlCopyMemory(Token->DefaultDacl, 1364 CapturedAcl, 1365 CapturedAcl->AclSize); 1366 1367 ExAllocateLocallyUniqueId(&Token->ModifiedId); 1368 } 1369 1370 /* Unlock the token */ 1371 SepReleaseTokenLock(Token); 1372 1373 ExFreePoolWithTag(CapturedAcl, TAG_ACL); 1374 } 1375 } 1376 else 1377 { 1378 /* Lock the token */ 1379 SepAcquireTokenLockExclusive(Token); 1380 1381 /* Clear the default dacl if present */ 1382 if (Token->DefaultDacl != NULL) 1383 { 1384 Token->DynamicAvailable += Token->DefaultDacl->AclSize; 1385 RtlZeroMemory(Token->DefaultDacl, Token->DefaultDacl->AclSize); 1386 Token->DefaultDacl = NULL; 1387 1388 ExAllocateLocallyUniqueId(&Token->ModifiedId); 1389 } 1390 1391 /* Unlock the token */ 1392 SepReleaseTokenLock(Token); 1393 } 1394 } 1395 else 1396 { 1397 Status = STATUS_INFO_LENGTH_MISMATCH; 1398 } 1399 break; 1400 } 1401 1402 case TokenSessionId: 1403 { 1404 ULONG SessionId = 0; 1405 1406 _SEH2_TRY 1407 { 1408 /* Buffer size was already verified, no need to check here again */ 1409 SessionId = *(PULONG)TokenInformation; 1410 } 1411 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1412 { 1413 Status = _SEH2_GetExceptionCode(); 1414 _SEH2_YIELD(goto Cleanup); 1415 } 1416 _SEH2_END; 1417 1418 /* Check for TCB privilege */ 1419 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode)) 1420 { 1421 Status = STATUS_PRIVILEGE_NOT_HELD; 1422 break; 1423 } 1424 1425 /* Lock the token */ 1426 SepAcquireTokenLockExclusive(Token); 1427 1428 Token->SessionId = SessionId; 1429 ExAllocateLocallyUniqueId(&Token->ModifiedId); 1430 1431 /* Unlock the token */ 1432 SepReleaseTokenLock(Token); 1433 1434 break; 1435 } 1436 1437 case TokenSessionReference: 1438 { 1439 ULONG SessionReference; 1440 1441 _SEH2_TRY 1442 { 1443 /* Buffer size was already verified, no need to check here again */ 1444 SessionReference = *(PULONG)TokenInformation; 1445 } 1446 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1447 { 1448 Status = _SEH2_GetExceptionCode(); 1449 _SEH2_YIELD(goto Cleanup); 1450 } 1451 _SEH2_END; 1452 1453 /* Check for TCB privilege */ 1454 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode)) 1455 { 1456 Status = STATUS_PRIVILEGE_NOT_HELD; 1457 goto Cleanup; 1458 } 1459 1460 /* Check if it is 0 */ 1461 if (SessionReference == 0) 1462 { 1463 ULONG OldTokenFlags; 1464 1465 /* Lock the token */ 1466 SepAcquireTokenLockExclusive(Token); 1467 1468 /* Atomically set the flag in the token */ 1469 OldTokenFlags = RtlInterlockedSetBits(&Token->TokenFlags, 1470 TOKEN_SESSION_NOT_REFERENCED); 1471 /* 1472 * If the flag was already set, do not dereference again 1473 * the logon session. Use SessionReference as an indicator 1474 * to know whether to really dereference the session. 1475 */ 1476 if (OldTokenFlags == Token->TokenFlags) 1477 SessionReference = ULONG_MAX; 1478 1479 /* 1480 * Otherwise if the flag was never set but just for this first time then 1481 * remove the referenced logon session data from the token and dereference 1482 * the logon session when needed. 1483 */ 1484 if (SessionReference == 0) 1485 { 1486 SepRmRemoveLogonSessionFromToken(Token); 1487 SepRmDereferenceLogonSession(&Token->AuthenticationId); 1488 } 1489 1490 /* Unlock the token */ 1491 SepReleaseTokenLock(Token); 1492 } 1493 break; 1494 } 1495 1496 case TokenAuditPolicy: 1497 { 1498 PTOKEN_AUDIT_POLICY_INFORMATION PolicyInformation = 1499 (PTOKEN_AUDIT_POLICY_INFORMATION)TokenInformation; 1500 SEP_AUDIT_POLICY AuditPolicy; 1501 ULONG i; 1502 1503 _SEH2_TRY 1504 { 1505 ProbeForRead(PolicyInformation, 1506 FIELD_OFFSET(TOKEN_AUDIT_POLICY_INFORMATION, 1507 Policies[PolicyInformation->PolicyCount]), 1508 sizeof(ULONG)); 1509 1510 /* Loop all policies in the structure */ 1511 for (i = 0; i < PolicyInformation->PolicyCount; i++) 1512 { 1513 /* Set the corresponding bits in the packed structure */ 1514 switch (PolicyInformation->Policies[i].Category) 1515 { 1516 case AuditCategorySystem: 1517 AuditPolicy.PolicyElements.System = PolicyInformation->Policies[i].Value; 1518 break; 1519 1520 case AuditCategoryLogon: 1521 AuditPolicy.PolicyElements.Logon = PolicyInformation->Policies[i].Value; 1522 break; 1523 1524 case AuditCategoryObjectAccess: 1525 AuditPolicy.PolicyElements.ObjectAccess = PolicyInformation->Policies[i].Value; 1526 break; 1527 1528 case AuditCategoryPrivilegeUse: 1529 AuditPolicy.PolicyElements.PrivilegeUse = PolicyInformation->Policies[i].Value; 1530 break; 1531 1532 case AuditCategoryDetailedTracking: 1533 AuditPolicy.PolicyElements.DetailedTracking = PolicyInformation->Policies[i].Value; 1534 break; 1535 1536 case AuditCategoryPolicyChange: 1537 AuditPolicy.PolicyElements.PolicyChange = PolicyInformation->Policies[i].Value; 1538 break; 1539 1540 case AuditCategoryAccountManagement: 1541 AuditPolicy.PolicyElements.AccountManagement = PolicyInformation->Policies[i].Value; 1542 break; 1543 1544 case AuditCategoryDirectoryServiceAccess: 1545 AuditPolicy.PolicyElements.DirectoryServiceAccess = PolicyInformation->Policies[i].Value; 1546 break; 1547 1548 case AuditCategoryAccountLogon: 1549 AuditPolicy.PolicyElements.AccountLogon = PolicyInformation->Policies[i].Value; 1550 break; 1551 } 1552 } 1553 } 1554 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1555 { 1556 Status = _SEH2_GetExceptionCode(); 1557 _SEH2_YIELD(goto Cleanup); 1558 } 1559 _SEH2_END; 1560 1561 /* Check for TCB privilege */ 1562 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode)) 1563 { 1564 Status = STATUS_PRIVILEGE_NOT_HELD; 1565 break; 1566 } 1567 1568 /* Lock the token */ 1569 SepAcquireTokenLockExclusive(Token); 1570 1571 /* Set the new audit policy */ 1572 Token->AuditPolicy = AuditPolicy; 1573 ExAllocateLocallyUniqueId(&Token->ModifiedId); 1574 1575 /* Unlock the token */ 1576 SepReleaseTokenLock(Token); 1577 1578 break; 1579 } 1580 1581 case TokenOrigin: 1582 { 1583 TOKEN_ORIGIN TokenOrigin; 1584 1585 _SEH2_TRY 1586 { 1587 /* Copy the token origin */ 1588 TokenOrigin = *(PTOKEN_ORIGIN)TokenInformation; 1589 } 1590 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 1591 { 1592 Status = _SEH2_GetExceptionCode(); 1593 _SEH2_YIELD(goto Cleanup); 1594 } 1595 _SEH2_END; 1596 1597 /* Check for TCB privilege */ 1598 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode)) 1599 { 1600 Status = STATUS_PRIVILEGE_NOT_HELD; 1601 break; 1602 } 1603 1604 /* Lock the token */ 1605 SepAcquireTokenLockExclusive(Token); 1606 1607 /* Check if there is no token origin set yet */ 1608 if (RtlIsZeroLuid(&Token->OriginatingLogonSession)) 1609 { 1610 /* Set the token origin */ 1611 Token->OriginatingLogonSession = 1612 TokenOrigin.OriginatingLogonSession; 1613 1614 ExAllocateLocallyUniqueId(&Token->ModifiedId); 1615 } 1616 1617 /* Unlock the token */ 1618 SepReleaseTokenLock(Token); 1619 1620 break; 1621 } 1622 1623 default: 1624 { 1625 DPRINT1("Invalid TokenInformationClass: 0x%lx\n", 1626 TokenInformationClass); 1627 Status = STATUS_INVALID_INFO_CLASS; 1628 break; 1629 } 1630 } 1631 Cleanup: 1632 ObDereferenceObject(Token); 1633 } 1634 1635 if (!NT_SUCCESS(Status)) 1636 { 1637 DPRINT1("NtSetInformationToken failed with Status 0x%lx\n", Status); 1638 } 1639 1640 return Status; 1641 } 1642 1643 /* EOF */ 1644