1 /* 2 * PROJECT: ReactOS API tests 3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) 4 * PURPOSE: Tests for the NtQueryInformationToken API 5 * COPYRIGHT: Copyright 2022 George Bișoc <george.bisoc@reactos.org> 6 */ 7 8 #include "precomp.h" 9 10 static 11 HANDLE 12 OpenCurrentToken(VOID) 13 { 14 BOOL Success; 15 HANDLE Token; 16 17 Success = OpenProcessToken(GetCurrentProcess(), 18 TOKEN_READ | TOKEN_QUERY_SOURCE | TOKEN_DUPLICATE, 19 &Token); 20 if (!Success) 21 { 22 ok(FALSE, "OpenProcessToken() has failed to get the process' token (error code: %lu)!\n", GetLastError()); 23 return NULL; 24 } 25 26 return Token; 27 } 28 29 static 30 VOID 31 QueryTokenUserTests( 32 _In_ HANDLE Token) 33 { 34 NTSTATUS Status; 35 PTOKEN_USER UserToken; 36 ULONG BufferLength; 37 UNICODE_STRING SidString; 38 39 /* 40 * Query the exact buffer length to hold 41 * our stuff, STATUS_BUFFER_TOO_SMALL must 42 * be expected here. 43 */ 44 Status = NtQueryInformationToken(Token, 45 TokenUser, 46 NULL, 47 0, 48 &BufferLength); 49 ok_ntstatus(Status, STATUS_BUFFER_TOO_SMALL); 50 51 /* Allocate the buffer based on the size we got */ 52 UserToken = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength); 53 if (!UserToken) 54 { 55 ok(FALSE, "Failed to allocate from heap for token user (required buffer length %lu)!\n", BufferLength); 56 return; 57 } 58 59 /* Now do the actual query */ 60 Status = NtQueryInformationToken(Token, 61 TokenUser, 62 UserToken, 63 BufferLength, 64 &BufferLength); 65 ok_ntstatus(Status, STATUS_SUCCESS); 66 67 RtlConvertSidToUnicodeString(&SidString, UserToken->User.Sid, TRUE); 68 trace("=============== TokenUser ===============\n"); 69 trace("The SID of current token user is: %s\n", wine_dbgstr_w(SidString.Buffer)); 70 trace("=========================================\n\n"); 71 RtlFreeUnicodeString(&SidString); 72 73 RtlFreeHeap(RtlGetProcessHeap(), 0, UserToken); 74 } 75 76 static 77 VOID 78 QueryTokenGroupsTests( 79 _In_ HANDLE Token) 80 { 81 NTSTATUS Status; 82 PTOKEN_GROUPS Groups; 83 ULONG BufferLength; 84 85 /* 86 * Query the exact buffer length to hold 87 * our stuff, STATUS_BUFFER_TOO_SMALL must 88 * be expected here. 89 */ 90 Status = NtQueryInformationToken(Token, 91 TokenGroups, 92 NULL, 93 0, 94 &BufferLength); 95 ok_ntstatus(Status, STATUS_BUFFER_TOO_SMALL); 96 97 /* Allocate the buffer based on the size we got */ 98 Groups = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength); 99 if (!Groups) 100 { 101 ok(FALSE, "Failed to allocate from heap for token groups (required buffer length %lu)!\n", BufferLength); 102 return; 103 } 104 105 /* 106 * Now do the actual query and validate the 107 * number of groups. 108 */ 109 Status = NtQueryInformationToken(Token, 110 TokenGroups, 111 Groups, 112 BufferLength, 113 &BufferLength); 114 ok_ntstatus(Status, STATUS_SUCCESS); 115 ok(Groups->GroupCount == 10, "The number of groups must be 10 (current number %lu)!\n", Groups->GroupCount); 116 117 RtlFreeHeap(RtlGetProcessHeap(), 0, Groups); 118 } 119 120 static 121 VOID 122 QueryTokenPrivilegesTests( 123 _In_ HANDLE Token) 124 { 125 NTSTATUS Status; 126 PTOKEN_PRIVILEGES Privileges; 127 ULONG BufferLength; 128 129 /* 130 * Query the exact buffer length to hold 131 * our stuff, STATUS_BUFFER_TOO_SMALL must 132 * be expected here. 133 */ 134 Status = NtQueryInformationToken(Token, 135 TokenPrivileges, 136 NULL, 137 0, 138 &BufferLength); 139 ok_ntstatus(Status, STATUS_BUFFER_TOO_SMALL); 140 141 /* Allocate the buffer based on the size we got */ 142 Privileges = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength); 143 if (!Privileges) 144 { 145 ok(FALSE, "Failed to allocate from heap for token privileges (required buffer length %lu)!\n", BufferLength); 146 return; 147 } 148 149 /* 150 * Now do the actual query and validate the 151 * number of privileges. 152 */ 153 Status = NtQueryInformationToken(Token, 154 TokenPrivileges, 155 Privileges, 156 BufferLength, 157 &BufferLength); 158 ok_ntstatus(Status, STATUS_SUCCESS); 159 ok(Privileges->PrivilegeCount == 20, "The number of privileges must be 20 (current number %lu)!\n", Privileges->PrivilegeCount); 160 161 RtlFreeHeap(RtlGetProcessHeap(), 0, Privileges); 162 } 163 164 static 165 VOID 166 QueryTokenOwnerTests( 167 _In_ HANDLE Token) 168 { 169 NTSTATUS Status; 170 PTOKEN_OWNER Owner; 171 ULONG BufferLength; 172 UNICODE_STRING SidString; 173 174 /* 175 * Query the exact buffer length to hold 176 * our stuff, STATUS_BUFFER_TOO_SMALL must 177 * be expected here. 178 */ 179 Status = NtQueryInformationToken(Token, 180 TokenOwner, 181 NULL, 182 0, 183 &BufferLength); 184 ok_ntstatus(Status, STATUS_BUFFER_TOO_SMALL); 185 186 /* Allocate the buffer based on the size we got */ 187 Owner = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength); 188 if (!Owner) 189 { 190 ok(FALSE, "Failed to allocate from heap for token owner (required buffer length %lu)!\n", BufferLength); 191 return; 192 } 193 194 /* 195 * Now do the actual query and validate the 196 * token owner (must be the local admin). 197 */ 198 Status = NtQueryInformationToken(Token, 199 TokenOwner, 200 Owner, 201 BufferLength, 202 &BufferLength); 203 ok_ntstatus(Status, STATUS_SUCCESS); 204 205 RtlConvertSidToUnicodeString(&SidString, Owner->Owner, TRUE); 206 ok_wstr(SidString.Buffer, L"S-1-5-32-544"); 207 RtlFreeUnicodeString(&SidString); 208 209 RtlFreeHeap(RtlGetProcessHeap(), 0, Owner); 210 } 211 212 static 213 VOID 214 QueryTokenPrimaryGroupTests( 215 _In_ HANDLE Token) 216 { 217 NTSTATUS Status; 218 PTOKEN_PRIMARY_GROUP PrimaryGroup; 219 ULONG BufferLength; 220 UNICODE_STRING SidString; 221 222 /* 223 * Query the exact buffer length to hold 224 * our stuff, STATUS_BUFFER_TOO_SMALL must 225 * be expected here. 226 */ 227 Status = NtQueryInformationToken(Token, 228 TokenPrimaryGroup, 229 NULL, 230 0, 231 &BufferLength); 232 ok_ntstatus(Status, STATUS_BUFFER_TOO_SMALL); 233 234 /* Allocate the buffer based on the size we got */ 235 PrimaryGroup = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength); 236 if (!PrimaryGroup) 237 { 238 ok(FALSE, "Failed to allocate from heap for token primary group (required buffer length %lu)!\n", BufferLength); 239 return; 240 } 241 242 /* Now do the actual query */ 243 Status = NtQueryInformationToken(Token, 244 TokenPrimaryGroup, 245 PrimaryGroup, 246 BufferLength, 247 &BufferLength); 248 ok_ntstatus(Status, STATUS_SUCCESS); 249 250 RtlConvertSidToUnicodeString(&SidString, PrimaryGroup->PrimaryGroup, TRUE); 251 trace("=============== TokenPrimaryGroup ===============\n"); 252 trace("The primary group SID of current token is: %s\n", wine_dbgstr_w(SidString.Buffer)); 253 trace("=========================================\n\n"); 254 RtlFreeUnicodeString(&SidString); 255 256 RtlFreeHeap(RtlGetProcessHeap(), 0, PrimaryGroup); 257 } 258 259 static 260 VOID 261 QueryTokenDefaultDaclTests( 262 _In_ HANDLE Token) 263 { 264 NTSTATUS Status; 265 PTOKEN_DEFAULT_DACL Dacl; 266 ULONG BufferLength; 267 268 /* 269 * Query the exact buffer length to hold 270 * our stuff, STATUS_BUFFER_TOO_SMALL must 271 * be expected here. 272 */ 273 Status = NtQueryInformationToken(Token, 274 TokenDefaultDacl, 275 NULL, 276 0, 277 &BufferLength); 278 ok_ntstatus(Status, STATUS_BUFFER_TOO_SMALL); 279 280 /* Allocate the buffer based on the size we got */ 281 Dacl = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength); 282 if (!Dacl) 283 { 284 ok(FALSE, "Failed to allocate from heap for token default DACL (required buffer length %lu)!\n", BufferLength); 285 return; 286 } 287 288 /* 289 * Now do the actual query and validate the 290 * ACL revision and number count of ACEs. 291 */ 292 Status = NtQueryInformationToken(Token, 293 TokenDefaultDacl, 294 Dacl, 295 BufferLength, 296 &BufferLength); 297 ok_ntstatus(Status, STATUS_SUCCESS); 298 ok(Dacl->DefaultDacl->AclRevision == 2, "The ACL revision of token default DACL must be 2 (current revision %u)!\n", Dacl->DefaultDacl->AclRevision); 299 ok(Dacl->DefaultDacl->AceCount == 2, "The ACL's ACE count must be 2 (current ACE count %u)!\n", Dacl->DefaultDacl->AceCount); 300 301 RtlFreeHeap(RtlGetProcessHeap(), 0, Dacl); 302 } 303 304 static 305 VOID 306 QueryTokenSourceTests( 307 _In_ HANDLE Token) 308 { 309 NTSTATUS Status; 310 PTOKEN_SOURCE Source; 311 ULONG BufferLength; 312 CHAR SourceName[8]; 313 314 /* 315 * Query the exact buffer length to hold 316 * our stuff, STATUS_BUFFER_TOO_SMALL must 317 * be expected here. 318 */ 319 Status = NtQueryInformationToken(Token, 320 TokenSource, 321 NULL, 322 0, 323 &BufferLength); 324 ok_ntstatus(Status, STATUS_BUFFER_TOO_SMALL); 325 326 /* Allocate the buffer based on the size we got */ 327 Source = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength); 328 if (!Source) 329 { 330 ok(FALSE, "Failed to allocate from heap for token source (required buffer length %lu)!\n", BufferLength); 331 return; 332 } 333 334 /* Now do the actual query */ 335 Status = NtQueryInformationToken(Token, 336 TokenSource, 337 Source, 338 BufferLength, 339 &BufferLength); 340 ok_ntstatus(Status, STATUS_SUCCESS); 341 342 /* 343 * Subtract the source name from the queried buffer 344 * and compare it. The source name in question must be 345 * "User32" as the primary token of the current calling 346 * process is generated when the user has successfully 347 * logged in and he's into the desktop. 348 */ 349 SourceName[0] = Source->SourceName[0]; 350 SourceName[1] = Source->SourceName[1]; 351 SourceName[2] = Source->SourceName[2]; 352 SourceName[3] = Source->SourceName[3]; 353 SourceName[4] = Source->SourceName[4]; 354 SourceName[5] = Source->SourceName[5]; 355 SourceName[6] = '\0'; 356 ok_str(SourceName, "User32"); 357 358 RtlFreeHeap(RtlGetProcessHeap(), 0, Source); 359 } 360 361 static 362 VOID 363 QueryTokenTypeTests( 364 _In_ HANDLE Token) 365 { 366 NTSTATUS Status; 367 TOKEN_TYPE Type; 368 ULONG BufferLength; 369 370 /* 371 * Query the token type. The token of the 372 * current calling process must be primary 373 * since we aren't impersonating the security 374 * context of a client. 375 */ 376 Status = NtQueryInformationToken(Token, 377 TokenType, 378 &Type, 379 sizeof(TOKEN_TYPE), 380 &BufferLength); 381 ok_ntstatus(Status, STATUS_SUCCESS); 382 ok(Type == TokenPrimary, "The current token is not primary!\n"); 383 } 384 385 static 386 VOID 387 QueryTokenImpersonationTests( 388 _In_ HANDLE Token) 389 { 390 NTSTATUS Status; 391 SECURITY_IMPERSONATION_LEVEL Level; 392 ULONG BufferLength; 393 HANDLE DupToken; 394 OBJECT_ATTRIBUTES ObjectAttributes; 395 396 /* 397 * Windows throws STATUS_INVALID_INFO_CLASS here 398 * because one cannot simply query the impersonation 399 * level of a primary token. 400 */ 401 Status = NtQueryInformationToken(Token, 402 TokenImpersonationLevel, 403 &Level, 404 sizeof(SECURITY_IMPERSONATION_LEVEL), 405 &BufferLength); 406 ok_ntstatus(Status, STATUS_INVALID_INFO_CLASS); 407 408 /* 409 * Initialize the object attribute and duplicate 410 * the token into an actual impersonation one. 411 */ 412 InitializeObjectAttributes(&ObjectAttributes, 413 NULL, 414 0, 415 NULL, 416 NULL); 417 418 Status = NtDuplicateToken(Token, 419 TOKEN_QUERY, 420 &ObjectAttributes, 421 FALSE, 422 TokenImpersonation, 423 &DupToken); 424 if (!NT_SUCCESS(Status)) 425 { 426 ok(FALSE, "Failed to duplicate token (Status code %lx)!\n", Status); 427 return; 428 } 429 430 /* Now do the actual query */ 431 Status = NtQueryInformationToken(DupToken, 432 TokenImpersonationLevel, 433 &Level, 434 sizeof(SECURITY_IMPERSONATION_LEVEL), 435 &BufferLength); 436 ok_ntstatus(Status, STATUS_SUCCESS); 437 ok(Level == SecurityAnonymous, "The current token impersonation level is not anonymous!\n"); 438 NtClose(DupToken); 439 } 440 441 static 442 VOID 443 QueryTokenStatisticsTests( 444 _In_ HANDLE Token) 445 { 446 NTSTATUS Status; 447 PTOKEN_STATISTICS Statistics; 448 ULONG BufferLength; 449 450 /* 451 * Query the exact buffer length to hold 452 * our stuff, STATUS_BUFFER_TOO_SMALL must 453 * be expected here. 454 */ 455 Status = NtQueryInformationToken(Token, 456 TokenStatistics, 457 NULL, 458 0, 459 &BufferLength); 460 ok_ntstatus(Status, STATUS_BUFFER_TOO_SMALL); 461 462 /* Allocate the buffer based on the size we got */ 463 Statistics = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength); 464 if (!Statistics) 465 { 466 ok(FALSE, "Failed to allocate from heap for token statistics (required buffer length %lu)!\n", BufferLength); 467 return; 468 } 469 470 /* Do the actual query */ 471 Status = NtQueryInformationToken(Token, 472 TokenStatistics, 473 Statistics, 474 BufferLength, 475 &BufferLength); 476 ok_ntstatus(Status, STATUS_SUCCESS); 477 478 trace("=============== TokenStatistics ===============\n"); 479 trace("Token ID: %lu %lu\n", Statistics->TokenId.LowPart, Statistics->TokenId.HighPart); 480 trace("Authentication ID: %lu %lu\n", Statistics->AuthenticationId.LowPart, Statistics->AuthenticationId.HighPart); 481 trace("Dynamic Charged: %lu\n", Statistics->DynamicCharged); 482 trace("Dynamic Available: %lu\n", Statistics->DynamicAvailable); 483 trace("Modified ID: %lu %lu\n", Statistics->ModifiedId.LowPart, Statistics->ModifiedId.HighPart); 484 trace("=========================================\n\n"); 485 486 RtlFreeHeap(RtlGetProcessHeap(), 0, Statistics); 487 } 488 489 static 490 VOID 491 QueryTokenPrivilegesAndGroupsTests( 492 _In_ HANDLE Token) 493 { 494 NTSTATUS Status; 495 PTOKEN_GROUPS_AND_PRIVILEGES PrivsAndGroups; 496 TOKEN_GROUPS SidToRestrict; 497 HANDLE FilteredToken; 498 PSID WorldSid; 499 ULONG BufferLength; 500 static SID_IDENTIFIER_AUTHORITY WorldAuthority = {SECURITY_WORLD_SID_AUTHORITY}; 501 502 /* 503 * Create a World SID and filter the token 504 * by adding a restricted SID. 505 */ 506 Status = RtlAllocateAndInitializeSid(&WorldAuthority, 507 1, 508 SECURITY_WORLD_RID, 509 0, 0, 0, 0, 0, 0, 0, 510 &WorldSid); 511 if (!NT_SUCCESS(Status)) 512 { 513 ok(FALSE, "Failed to allocate World SID (Status code %lx)!\n", Status); 514 return; 515 } 516 517 SidToRestrict.GroupCount = 1; 518 SidToRestrict.Groups[0].Attributes = 0; 519 SidToRestrict.Groups[0].Sid = WorldSid; 520 521 Status = NtFilterToken(Token, 522 0, 523 NULL, 524 NULL, 525 &SidToRestrict, 526 &FilteredToken); 527 if (!NT_SUCCESS(Status)) 528 { 529 ok(FALSE, "Failed to filter the current token (Status code %lx)!\n", Status); 530 RtlFreeHeap(RtlGetProcessHeap(), 0, WorldSid); 531 return; 532 } 533 534 /* 535 * Query the exact buffer length to hold 536 * our stuff, STATUS_BUFFER_TOO_SMALL must 537 * be expected here. 538 */ 539 Status = NtQueryInformationToken(FilteredToken, 540 TokenGroupsAndPrivileges, 541 NULL, 542 0, 543 &BufferLength); 544 ok_ntstatus(Status, STATUS_BUFFER_TOO_SMALL); 545 546 /* Allocate the buffer based on the size we got */ 547 PrivsAndGroups = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength); 548 if (!PrivsAndGroups) 549 { 550 ok(FALSE, "Failed to allocate from heap for token privileges and groups (required buffer length %lu)!\n", BufferLength); 551 RtlFreeHeap(RtlGetProcessHeap(), 0, WorldSid); 552 NtClose(FilteredToken); 553 return; 554 } 555 556 /* Do the actual query */ 557 Status = NtQueryInformationToken(FilteredToken, 558 TokenGroupsAndPrivileges, 559 PrivsAndGroups, 560 BufferLength, 561 &BufferLength); 562 ok_ntstatus(Status, STATUS_SUCCESS); 563 564 trace("=============== TokenGroupsAndPrivileges ===============\n"); 565 trace("SID count: %lu\n", PrivsAndGroups->SidCount); 566 trace("SID length: %lu\n", PrivsAndGroups->SidLength); 567 trace("Restricted SID count: %lu\n", PrivsAndGroups->RestrictedSidCount); 568 trace("Restricted SID length: %lu\n", PrivsAndGroups->RestrictedSidLength); 569 trace("Privilege count: %lu\n", PrivsAndGroups->PrivilegeCount); 570 trace("Privilege length: %lu\n", PrivsAndGroups->PrivilegeLength); 571 trace("Authentication ID: %lu %lu\n", PrivsAndGroups->AuthenticationId.LowPart, PrivsAndGroups->AuthenticationId.HighPart); 572 trace("=========================================\n\n"); 573 574 RtlFreeHeap(RtlGetProcessHeap(), 0, PrivsAndGroups); 575 RtlFreeHeap(RtlGetProcessHeap(), 0, WorldSid); 576 NtClose(FilteredToken); 577 } 578 579 static 580 VOID 581 QueryTokenRestrictedSidsTest( 582 _In_ HANDLE Token) 583 { 584 NTSTATUS Status; 585 PTOKEN_GROUPS RestrictedGroups; 586 TOKEN_GROUPS SidToRestrict; 587 ULONG BufferLength; 588 HANDLE FilteredToken; 589 PSID WorldSid; 590 static SID_IDENTIFIER_AUTHORITY WorldAuthority = {SECURITY_WORLD_SID_AUTHORITY}; 591 592 /* 593 * Query the exact buffer length to hold 594 * our stuff, STATUS_BUFFER_TOO_SMALL must 595 * be expected here. 596 */ 597 Status = NtQueryInformationToken(Token, 598 TokenRestrictedSids, 599 NULL, 600 0, 601 &BufferLength); 602 ok_ntstatus(Status, STATUS_BUFFER_TOO_SMALL); 603 604 /* Allocate the buffer based on the size we got */ 605 RestrictedGroups = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength); 606 if (!RestrictedGroups) 607 { 608 ok(FALSE, "Failed to allocate from heap for restricted SIDs (required buffer length %lu)!\n", BufferLength); 609 return; 610 } 611 612 /* 613 * Query the number of restricted SIDs. Originally the token 614 * doesn't have any restricted SIDs inserted. 615 */ 616 Status = NtQueryInformationToken(Token, 617 TokenRestrictedSids, 618 RestrictedGroups, 619 BufferLength, 620 &BufferLength); 621 ok_ntstatus(Status, STATUS_SUCCESS); 622 ok(RestrictedGroups->GroupCount == 0, "There mustn't be any restricted SIDs before filtering (number of restricted SIDs %lu)!\n", RestrictedGroups->GroupCount); 623 624 RtlFreeHeap(RtlGetProcessHeap(), 0, RestrictedGroups); 625 RestrictedGroups = NULL; 626 627 Status = RtlAllocateAndInitializeSid(&WorldAuthority, 628 1, 629 SECURITY_WORLD_RID, 630 0, 0, 0, 0, 0, 0, 0, 631 &WorldSid); 632 if (!NT_SUCCESS(Status)) 633 { 634 ok(FALSE, "Failed to allocate World SID (Status code %lx)!\n", Status); 635 return; 636 } 637 638 SidToRestrict.GroupCount = 1; 639 SidToRestrict.Groups[0].Attributes = 0; 640 SidToRestrict.Groups[0].Sid = WorldSid; 641 642 Status = NtFilterToken(Token, 643 0, 644 NULL, 645 NULL, 646 &SidToRestrict, 647 &FilteredToken); 648 if (!NT_SUCCESS(Status)) 649 { 650 ok(FALSE, "Failed to filter the current token (Status code %lx)!\n", Status); 651 RtlFreeHeap(RtlGetProcessHeap(), 0, WorldSid); 652 return; 653 } 654 655 Status = NtQueryInformationToken(FilteredToken, 656 TokenRestrictedSids, 657 NULL, 658 0, 659 &BufferLength); 660 ok_ntstatus(Status, STATUS_BUFFER_TOO_SMALL); 661 662 RestrictedGroups = RtlAllocateHeap(RtlGetProcessHeap(), 0, BufferLength); 663 if (!RestrictedGroups) 664 { 665 ok(FALSE, "Failed to allocate from heap for restricted SIDs (required buffer length %lu)!\n", BufferLength); 666 RtlFreeHeap(RtlGetProcessHeap(), 0, WorldSid); 667 return; 668 } 669 670 /* 671 * Do a query again, this time we must have a 672 * restricted SID inserted into the token. 673 */ 674 Status = NtQueryInformationToken(FilteredToken, 675 TokenRestrictedSids, 676 RestrictedGroups, 677 BufferLength, 678 &BufferLength); 679 ok_ntstatus(Status, STATUS_SUCCESS); 680 ok(RestrictedGroups->GroupCount == 1, "There must be only one restricted SID added in token (number of restricted SIDs %lu)!\n", RestrictedGroups->GroupCount); 681 682 RtlFreeHeap(RtlGetProcessHeap(), 0, RestrictedGroups); 683 RtlFreeHeap(RtlGetProcessHeap(), 0, WorldSid); 684 NtClose(FilteredToken); 685 } 686 687 static 688 VOID 689 QueryTokenSessionIdTests( 690 _In_ HANDLE Token) 691 { 692 NTSTATUS Status; 693 ULONG SessionId; 694 ULONG BufferLength; 695 696 /* 697 * Query the session ID. Generally the current 698 * process token is not under any terminal service 699 * so the ID must be 0. 700 */ 701 Status = NtQueryInformationToken(Token, 702 TokenSessionId, 703 &SessionId, 704 sizeof(ULONG), 705 &BufferLength); 706 ok_ntstatus(Status, STATUS_SUCCESS); 707 ok(SessionId == 0, "The session ID of current token must be 0 (current session %lu)!\n", SessionId); 708 } 709 710 static 711 VOID 712 QueryTokenIsSandboxInert( 713 _In_ HANDLE Token) 714 { 715 NTSTATUS Status; 716 ULONG IsTokenInert; 717 ULONG BufferLength; 718 HANDLE FilteredToken; 719 720 /* 721 * Query the sandbox inert token information, 722 * it must not be inert. 723 */ 724 Status = NtQueryInformationToken(Token, 725 TokenSandBoxInert, 726 &IsTokenInert, 727 sizeof(ULONG), 728 &BufferLength); 729 ok_ntstatus(Status, STATUS_SUCCESS); 730 ok(IsTokenInert == FALSE, "The token must not be a sandbox inert one!\n"); 731 732 /* 733 * Try to turn the token into an inert 734 * one by filtering it. 735 */ 736 Status = NtFilterToken(Token, 737 SANDBOX_INERT, 738 NULL, 739 NULL, 740 NULL, 741 &FilteredToken); 742 if (!NT_SUCCESS(Status)) 743 { 744 ok(FALSE, "Failed to filter the current token (Status code %lx)!\n", Status); 745 return; 746 } 747 748 /* 749 * Now do a query again, this time 750 * the token should be inert. 751 */ 752 Status = NtQueryInformationToken(FilteredToken, 753 TokenSandBoxInert, 754 &IsTokenInert, 755 sizeof(ULONG), 756 &BufferLength); 757 ok_ntstatus(Status, STATUS_SUCCESS); 758 ok(IsTokenInert == TRUE, "The token must be a sandbox inert one after filtering!\n"); 759 760 NtClose(FilteredToken); 761 } 762 763 static 764 VOID 765 QueryTokenOriginTests( 766 _In_ HANDLE Token) 767 { 768 NTSTATUS Status; 769 TOKEN_ORIGIN Origin; 770 ULONG BufferLength; 771 772 /* Query the token origin */ 773 Status = NtQueryInformationToken(Token, 774 TokenOrigin, 775 &Origin, 776 sizeof(TOKEN_ORIGIN), 777 &BufferLength); 778 ok_ntstatus(Status, STATUS_SUCCESS); 779 ok(Origin.OriginatingLogonSession.LowPart == 0x3e7, "The LowPart field of the originating logon session must be SYSTEM_LUID (current value %lu)!\n", 780 Origin.OriginatingLogonSession.LowPart); 781 ok(Origin.OriginatingLogonSession.HighPart == 0x0, "The HighPart field of the logon session must be 0 (current value %lu)!\n", 782 Origin.OriginatingLogonSession.HighPart); 783 } 784 785 START_TEST(NtQueryInformationToken) 786 { 787 NTSTATUS Status; 788 HANDLE Token; 789 PVOID Dummy; 790 ULONG DummyReturnLength; 791 792 /* ReturnLength is NULL */ 793 Status = NtQueryInformationToken(NULL, 794 TokenUser, 795 NULL, 796 0, 797 NULL); 798 ok_ntstatus(Status, STATUS_ACCESS_VIOLATION); 799 800 /* We don't give any token here */ 801 Status = NtQueryInformationToken(NULL, 802 TokenUser, 803 &Dummy, 804 0, 805 &DummyReturnLength); 806 ok_ntstatus(Status, STATUS_INVALID_HANDLE); 807 808 Token = OpenCurrentToken(); 809 810 /* Class 0 is unused on Windows */ 811 Status = NtQueryInformationToken(Token, 812 0, 813 &Dummy, 814 0, 815 &DummyReturnLength); 816 ok_ntstatus(Status, STATUS_INVALID_INFO_CLASS); 817 818 /* We give a bogus info class */ 819 Status = NtQueryInformationToken(Token, 820 0xa0a, 821 &Dummy, 822 0, 823 &DummyReturnLength); 824 ok_ntstatus(Status, STATUS_INVALID_INFO_CLASS); 825 826 /* Now perform tests for each class */ 827 QueryTokenUserTests(Token); 828 QueryTokenGroupsTests(Token); 829 QueryTokenPrivilegesTests(Token); 830 QueryTokenOwnerTests(Token); 831 QueryTokenPrimaryGroupTests(Token); 832 QueryTokenDefaultDaclTests(Token); 833 QueryTokenSourceTests(Token); 834 QueryTokenTypeTests(Token); 835 QueryTokenImpersonationTests(Token); 836 QueryTokenStatisticsTests(Token); 837 QueryTokenPrivilegesAndGroupsTests(Token); 838 QueryTokenRestrictedSidsTest(Token); 839 QueryTokenSessionIdTests(Token); 840 QueryTokenIsSandboxInert(Token); 841 QueryTokenOriginTests(Token); 842 843 NtClose(Token); 844 } 845