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 NtFilterToken API
5 * COPYRIGHT: Copyright 2021 George Bișoc <george.bisoc@reactos.org>
6 */
7
8 #include "precomp.h"
9
10 static
11 HANDLE
GetTokenProcess(VOID)12 GetTokenProcess(VOID)
13 {
14 BOOL Success;
15 HANDLE Token;
16
17 Success = OpenProcessToken(GetCurrentProcess(),
18 TOKEN_DUPLICATE | TOKEN_QUERY,
19 &Token);
20 if (!Success)
21 {
22 skip("GetTokenProcess() has failed to get the process' token (error code: %lu)!\n", GetLastError());
23 return NULL;
24 }
25
26 return Token;
27 }
28
START_TEST(NtFilterToken)29 START_TEST(NtFilterToken)
30 {
31 NTSTATUS Status;
32 HANDLE FilteredToken, Token;
33 TOKEN_PRIVILEGES Priv;
34 ULONG Size;
35 PTOKEN_STATISTICS TokenStats;
36
37 /* We don't give a token */
38 Status = NtFilterToken(NULL,
39 0,
40 NULL,
41 NULL,
42 NULL,
43 &FilteredToken);
44 ok_hex(Status, STATUS_INVALID_HANDLE);
45
46 /* Get the token from process now */
47 Token = GetTokenProcess();
48
49 /* We don't give any privileges to delete */
50 Status = NtFilterToken(Token,
51 0,
52 NULL,
53 NULL,
54 NULL,
55 &FilteredToken);
56 ok_hex(Status, STATUS_SUCCESS);
57
58 /* Query the total size to hold the statistics */
59 Status = NtQueryInformationToken(Token, TokenStatistics, NULL, 0, &Size);
60 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL)
61 {
62 skip("Failed to query the total size for token statistics structure! (Status -> 0x%lx)\n", Status);
63 return;
64 }
65
66 /* Total size queried, time to allocate our buffer based on that size */
67 TokenStats = RtlAllocateHeap(RtlGetProcessHeap(), 0, Size);
68 if (TokenStats == NULL)
69 {
70 skip("Failed to allocate our token statistics buffer!\n");
71 return;
72 }
73
74 /* Time to query our token statistics, prior disabling token's privileges */
75 Status = NtQueryInformationToken(Token, TokenStatistics, TokenStats, Size, &Size);
76 if (!NT_SUCCESS(Status))
77 {
78 skip("Failed to query the token statistics! (Status -> 0x%lx)\n", Status);
79 return;
80 }
81
82 trace("Number of privileges before token filtering -- %lu\n\n", TokenStats->PrivilegeCount);
83
84 /* Disable the privileges and make the token a safer inert one */
85 Status = NtFilterToken(Token,
86 DISABLE_MAX_PRIVILEGE | SANDBOX_INERT,
87 NULL,
88 NULL,
89 NULL,
90 &FilteredToken);
91 ok_hex(Status, STATUS_SUCCESS);
92
93 /* We've disabled privileges, query the stats again */
94 Status = NtQueryInformationToken(FilteredToken, TokenStatistics, TokenStats, Size, &Size);
95 if (!NT_SUCCESS(Status))
96 {
97 skip("Failed to query the token statistics! (Status -> 0x%lx)\n", Status);
98 return;
99 }
100
101 trace("Number of privileges after token filtering (privileges disabled with DISABLE_MAX_PRIVILEGE) -- %lu\n\n", TokenStats->PrivilegeCount);
102
103 /* Close the filtered token and do another test */
104 CloseHandle(FilteredToken);
105
106 /* Fill in a privilege to delete */
107 Priv.PrivilegeCount = 1;
108
109 Priv.Privileges[0].Luid = RtlConvertUlongToLuid(SE_BACKUP_PRIVILEGE);
110 Priv.Privileges[0].Attributes = 0;
111
112 /* Delete the privileges */
113 Status = NtFilterToken(Token,
114 0,
115 NULL,
116 &Priv,
117 NULL,
118 &FilteredToken);
119 ok_hex(Status, STATUS_SUCCESS);
120
121 /* We've deleted a privilege, query the stats again */
122 Status = NtQueryInformationToken(FilteredToken, TokenStatistics, TokenStats, Size, &Size);
123 if (!NT_SUCCESS(Status))
124 {
125 skip("Failed to query the token statistics! (Status -> 0x%lx)\n", Status);
126 return;
127 }
128
129 trace("Number of privileges after token filtering (manually deleted privilege) -- %lu\n\n", TokenStats->PrivilegeCount);
130
131 /* We're done */
132 RtlFreeHeap(RtlGetProcessHeap(), 0, TokenStats);
133 CloseHandle(Token);
134 CloseHandle(FilteredToken);
135 }
136