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 NtDuplicateToken API 5 * COPYRIGHT: Copyright 2021 George Bișoc <george.bisoc@reactos.org> 6 */ 7 8 #include "precomp.h" 9 10 static 11 HANDLE 12 OpenTokenFromProcess(VOID) 13 { 14 BOOL Success; 15 HANDLE Token; 16 17 Success = OpenProcessToken(GetCurrentProcess(), 18 TOKEN_READ | TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS | TOKEN_DUPLICATE | TOKEN_QUERY, 19 &Token); 20 if (!Success) 21 { 22 skip("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 DisablePrivilege( 32 _In_ HANDLE Token, 33 _In_ LPCWSTR PrivilegeName) 34 { 35 TOKEN_PRIVILEGES TokenPriv; 36 LUID PrivLuid; 37 BOOL Success; 38 39 Success = LookupPrivilegeValueW(NULL, PrivilegeName, &PrivLuid); 40 if (!Success) 41 { 42 skip("LookupPrivilegeValueW() has failed to locate the privilege value (error code: %lu)!\n", GetLastError()); 43 return; 44 } 45 46 TokenPriv.PrivilegeCount = 1; 47 TokenPriv.Privileges[0].Luid = PrivLuid; 48 TokenPriv.Privileges[0].Attributes = 0; 49 50 Success = AdjustTokenPrivileges(Token, 51 FALSE, 52 &TokenPriv, 53 0, 54 NULL, 55 NULL); 56 if (!Success) 57 { 58 skip("AdjustTokenPrivileges() has failed to adjust privileges of token (error code: %lu)!\n", GetLastError()); 59 return; 60 } 61 } 62 63 static 64 VOID 65 DuplicateTokenAsEffective(VOID) 66 { 67 NTSTATUS Status; 68 ULONG Size; 69 HANDLE TokenHandle; 70 HANDLE DuplicatedTokenHandle; 71 OBJECT_ATTRIBUTES ObjectAttributes; 72 PTOKEN_STATISTICS TokenStats; 73 74 /* Initialize the object attributes for token duplication */ 75 InitializeObjectAttributes(&ObjectAttributes, 76 NULL, 77 0, 78 NULL, 79 NULL); 80 81 /* Get the token from process and begin the tests */ 82 TokenHandle = OpenTokenFromProcess(); 83 84 /* We give a bogus invalid handle */ 85 Status = NtDuplicateToken(NULL, 86 0, 87 NULL, 88 TRUE, 89 TokenPrimary, 90 NULL); 91 ok_hex(Status, STATUS_ACCESS_VIOLATION); 92 93 /* 94 * Disable a privilege, the impersonation privilege for example. 95 * Why we're doing this is because such privilege is enabled 96 * by default and we'd want to know what the kernel does 97 * at the moment of removing disabled privileges during making 98 * the token effective, with this potential privilege being 99 * disabled by ourselves. 100 */ 101 DisablePrivilege(TokenHandle, L"SeImpersonatePrivilege"); 102 103 /* Query the total size of the token statistics structure */ 104 Status = NtQueryInformationToken(TokenHandle, TokenStatistics, NULL, 0, &Size); 105 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL) 106 { 107 skip("Failed to query the total size for token statistics structure! (Status -> 0x%lx)\n", Status); 108 return; 109 } 110 111 /* Total size queried, time to allocate our buffer based on that size */ 112 TokenStats = RtlAllocateHeap(RtlGetProcessHeap(), 0, Size); 113 if (TokenStats == NULL) 114 { 115 skip("Failed to allocate our token statistics buffer!\n"); 116 return; 117 } 118 119 /* Time to query our token statistics, prior duplicating the token as effective */ 120 Status = NtQueryInformationToken(TokenHandle, TokenStatistics, TokenStats, Size, &Size); 121 if (!NT_SUCCESS(Status)) 122 { 123 skip("Failed to query the token statistics! (Status -> 0x%lx)\n", Status); 124 return; 125 } 126 127 trace("Number of privileges of regular token -- %lu\n", TokenStats->PrivilegeCount); 128 trace("Number of groups of regular token -- %lu\n", TokenStats->GroupCount); 129 130 /* Duplicate the token as effective only */ 131 Status = NtDuplicateToken(TokenHandle, 132 0, 133 &ObjectAttributes, 134 TRUE, 135 TokenPrimary, 136 &DuplicatedTokenHandle); 137 ok_hex(Status, STATUS_SUCCESS); 138 139 /* 140 * Query the token statistics again, but now this time of 141 * the duplicated effective token. On this moment this token 142 * should have the disabled privileges (including the one we 143 * disabled ourselves) removed as well as the disabled groups 144 * that the duplicated token includes, whatever that is. 145 */ 146 Status = NtQueryInformationToken(DuplicatedTokenHandle, TokenStatistics, TokenStats, Size, &Size); 147 if (!NT_SUCCESS(Status)) 148 { 149 skip("Failed to query the token statistics! (Status -> 0x%lx)\n", Status); 150 return; 151 } 152 153 trace("Number of privileges of effective only token -- %lu\n", TokenStats->PrivilegeCount); 154 trace("Number of groups of effective only token -- %lu\n", TokenStats->GroupCount); 155 156 /* 157 * We finished our tests, free the memory 158 * block and close the handles now. 159 */ 160 RtlFreeHeap(RtlGetProcessHeap(), 0, TokenStats); 161 CloseHandle(TokenHandle), 162 CloseHandle(DuplicatedTokenHandle); 163 } 164 165 START_TEST(NtDuplicateToken) 166 { 167 DuplicateTokenAsEffective(); 168 } 169