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