1 /*
2 * PROJECT:         ReactOS kernel-mode tests
3 * LICENSE:         GPLv2+ - See COPYING in the top level directory
4 * PURPOSE:         Kernel-Mode Test Suite Process Notification Routines test
5 * PROGRAMMER:      Constantine Belev (Moscow State Technical University)
6 *                  Denis Grishin (Moscow State Technical University)
7 *                  Egor Sinitsyn (Moscow State Technical University)
8 */
9 
10 #include <kmt_test.h>
11 #include <ntifs.h>
12 
13 #define NDEBUG
14 #include <debug.h>
15 
16 //------------------------------------------------------------------------------//
17 //      Testing Functions                                                       //
18 //------------------------------------------------------------------------------//
19 
20 // Testing function for SQIT
21 
22 void TestsSeQueryInformationToken(PACCESS_TOKEN Token)
23 {
24     NTSTATUS Status;
25     PVOID Buffer = NULL;
26     PSID sid;
27     PTOKEN_OWNER Towner;
28     PTOKEN_DEFAULT_DACL TDefDacl;
29     PTOKEN_GROUPS TGroups;
30     ULONG GroupCount;
31     PACL acl;
32     PTOKEN_STATISTICS TStats;
33     PTOKEN_TYPE TType;
34     PTOKEN_USER TUser;
35     BOOLEAN Flag;
36     ULONG i;
37 
38     //----------------------------------------------------------------//
39     // Testing SeQueryInformationToken with various args              //
40     //----------------------------------------------------------------//
41 
42     ok(Token != NULL, "Token is not captured. Testing SQIT interrupted\n\n");
43 
44     if (Token == NULL) return;
45 
46     Status = SeQueryInformationToken(Token, TokenOwner, &Buffer);
47     ok((Status == STATUS_SUCCESS), "SQIT with TokenOwner arg fails with status 0x%08X\n", Status);
48     if (Status == STATUS_SUCCESS)
49     {
50         ok(Buffer != NULL, "Wrong. SQIT call was successful with TokenOwner arg. But Buffer == NULL\n");
51 
52         if (Buffer)
53         {
54             Towner = (TOKEN_OWNER *)Buffer;
55             sid = Towner->Owner;
56             ok((RtlValidSid(sid) == TRUE), "TokenOwner's SID is not a valid SID\n");
57             ExFreePool(Buffer);
58         }
59     }
60 
61     //----------------------------------------------------------------//
62 
63     Buffer = NULL;
64     Status = SeQueryInformationToken(Token, TokenDefaultDacl, &Buffer);
65     ok(Status == STATUS_SUCCESS, "SQIT with TokenDefaultDacl fails with status 0x%08X\n", Status);
66     if (Status == STATUS_SUCCESS)
67     {
68         ok(Buffer != NULL, "Wrong. SQIT call was successful with TokenDefaultDacl arg. But Buffer == NULL\n");
69         if (Buffer)
70         {
71             TDefDacl = (PTOKEN_DEFAULT_DACL)Buffer;
72             acl = TDefDacl->DefaultDacl;
73             ok(((acl->AclRevision == ACL_REVISION || acl->AclRevision == ACL_REVISION_DS) == TRUE), "DACL is invalid\n");
74             ExFreePool(Buffer);
75         }
76     }
77 
78     //----------------------------------------------------------------//
79 
80     Buffer = NULL;
81     Status = SeQueryInformationToken(Token, TokenGroups, &Buffer);
82     ok(Status == STATUS_SUCCESS, "SQIT with TokenGroups fails with status 0x%08X\n", Status);
83     if (Status == STATUS_SUCCESS)
84     {
85         ok(Buffer != NULL, "Wrong. SQIT call was successful with TokenGroups arg. But Buffer == NULL\n");
86         if (Buffer)
87         {
88             TGroups = (PTOKEN_GROUPS)Buffer;
89             GroupCount = TGroups->GroupCount;
90             Flag = TRUE;
91             for (i = 0; i < GroupCount; i++)
92             {
93                 sid = TGroups->Groups[i].Sid;
94                 if (!RtlValidSid(sid))
95                 {
96                     Flag = FALSE;
97                     break;
98                 }
99             }
100             ok((Flag == TRUE), "TokenGroup's SIDs are not valid\n");
101             ExFreePool(Buffer);
102         }
103     }
104 
105     //----------------------------------------------------------------//
106 
107     // Call SQIT with TokenImpersonationLevel argument. Although our token
108     // is not an impersonation token, the call will outright fail.
109 
110     Buffer = NULL;
111     Status = SeQueryInformationToken(Token, TokenImpersonationLevel, &Buffer);
112     ok(Status == STATUS_INVALID_INFO_CLASS, "SQIT with TokenImpersonationLevel must return STATUS_INVALID_INFO_CLASS but got 0x%08X\n", Status);
113     ok(Buffer == NULL, "SQIT has failed to query the impersonation level but buffer is not NULL!\n");
114 
115     //----------------------------------------------------------------//
116 
117     // Call SQIT with the 4 classes (TokenOrigin, TokenGroupsAndPrivileges,
118     // TokenRestrictedSids and TokenSandBoxInert) are not supported by
119     // SeQueryInformationToken (only NtQueryInformationToken supports them).
120     //
121 
122     Buffer = NULL;
123     Status = SeQueryInformationToken(Token, TokenOrigin, &Buffer);
124     ok(Status == STATUS_INVALID_INFO_CLASS, "SQIT with TokenOrigin failed with Status 0x%08X; expected STATUS_INVALID_INFO_CLASS\n", Status);
125     ok(Buffer == NULL, "Wrong. SQIT call failed. But Buffer != NULL\n");
126 
127     Buffer = NULL;
128     Status = SeQueryInformationToken(Token, TokenGroupsAndPrivileges, &Buffer);
129     ok(Status == STATUS_INVALID_INFO_CLASS, "SQIT with TokenGroupsAndPrivileges failed with Status 0x%08X; expected STATUS_INVALID_INFO_CLASS\n", Status);
130     ok(Buffer == NULL, "Wrong. SQIT call failed. But Buffer != NULL\n");
131 
132     Buffer = NULL;
133     Status = SeQueryInformationToken(Token, TokenRestrictedSids, &Buffer);
134     ok(Status == STATUS_INVALID_INFO_CLASS, "SQIT with TokenRestrictedSids failed with Status 0x%08X; expected STATUS_INVALID_INFO_CLASS\n", Status);
135     ok(Buffer == NULL, "Wrong. SQIT call failed. But Buffer != NULL\n");
136 
137     Buffer = NULL;
138     Status = SeQueryInformationToken(Token, TokenSandBoxInert, &Buffer);
139     ok(Status == STATUS_INVALID_INFO_CLASS, "SQIT with TokenSandBoxInert failed with Status 0x%08X; expected STATUS_INVALID_INFO_CLASS\n", Status);
140     ok(Buffer == NULL, "Wrong. SQIT call failed. But Buffer != NULL\n");
141 
142     //----------------------------------------------------------------//
143 
144     Buffer = NULL;
145     Status = SeQueryInformationToken(Token, TokenStatistics, &Buffer);
146     ok(Status == STATUS_SUCCESS, "SQIT with TokenStatistics fails with status 0x%08X\n", Status);
147     if (Status == STATUS_SUCCESS)
148     {
149         ok(Buffer != NULL, "Wrong. SQIT call was successful with TokenStatistics arg. But Buffer == NULL\n");
150         if (Buffer)
151         {
152             TStats = (PTOKEN_STATISTICS)Buffer;
153             // just put 0 into 1st arg or use trace to print TokenStatistics
154             ok(1, "print statistics:\n\tTokenID = %u_%d\n\tSecurityImperLevel = %d\n\tPrivCount = %d\n\tGroupCount = %d\n\n", TStats->TokenId.LowPart,
155                 TStats->TokenId.HighPart,
156                 TStats->ImpersonationLevel,
157                 TStats->PrivilegeCount,
158                 TStats->GroupCount
159                 );
160             ExFreePool(Buffer);
161         }
162     } else {
163         ok(Buffer == NULL, "Wrong. SQIT call failed. But Buffer != NULL\n");
164     }
165 
166     //----------------------------------------------------------------//
167 
168     Buffer = NULL;
169     Status = SeQueryInformationToken(Token, TokenType, &Buffer);
170     ok(Status == STATUS_SUCCESS, "SQIT with TokenType fails with status 0x%08X\n", Status);
171     if (Status == STATUS_SUCCESS)
172     {
173         ok(Buffer != NULL, "Wrong. SQIT call was successful with TokenType arg. But Buffer == NULL\n");
174         if (Buffer)
175         {
176             TType = (PTOKEN_TYPE)Buffer;
177             ok((*TType == TokenPrimary || *TType == TokenImpersonation), "TokenType in not a primary nor impersonation. FAILED\n");
178             ExFreePool(Buffer);
179         }
180     }
181 
182     //----------------------------------------------------------------//
183 
184     Buffer = NULL;
185     Status = SeQueryInformationToken(Token, TokenUser, &Buffer);
186     ok(Status == STATUS_SUCCESS, "SQIT with TokenUser fails\n");
187     if (Status == STATUS_SUCCESS)
188     {
189         ok(Buffer != NULL, "Wrong. SQIT call was successful with TokenUser arg. But Buffer == NULL\n");
190         if (Buffer)
191         {
192             TUser = (PTOKEN_USER)Buffer;
193             ok(RtlValidSid(TUser->User.Sid), "TokenUser has an invalid Sid\n");
194             ExFreePool(Buffer);
195         }
196     }
197 
198     //----------------------------------------------------------------//
199 
200     Buffer = NULL;
201     Status = SeQueryInformationToken(Token, TokenSandBoxInert, &Buffer);
202     ok(Status != STATUS_SUCCESS, "SQIT must fail with wrong TOKEN_INFORMATION_CLASS arg\n");
203 }
204 
205 //------------------------------------------------------------------------------//
206 
207 //------------------------------------------------------------------------------//
208 //      Body of the main test                                                   //
209 //------------------------------------------------------------------------------//
210 
211 START_TEST(SeQueryInfoToken)
212 {
213     PACCESS_STATE AccessState;
214     ACCESS_MASK AccessMask = MAXIMUM_ALLOWED;
215     ACCESS_MASK DesiredAccess = MAXIMUM_ALLOWED;
216     NTSTATUS Status = STATUS_SUCCESS;
217     PAUX_ACCESS_DATA AuxData = NULL;
218     PPRIVILEGE_SET NewPrivilegeSet;
219     BOOLEAN Checker;
220     PPRIVILEGE_SET Privileges = NULL;
221     PSECURITY_SUBJECT_CONTEXT SubjectContext = NULL;
222     PACCESS_TOKEN Token = NULL;
223     PTOKEN_PRIVILEGES TPrivileges;
224     PVOID Buffer;
225     POBJECT_TYPE PsProcessType = NULL;
226     PGENERIC_MAPPING GenericMapping;
227     ULONG i;
228 
229     SubjectContext = ExAllocatePool(PagedPool, sizeof(SECURITY_SUBJECT_CONTEXT));
230 
231     SeCaptureSubjectContext(SubjectContext);
232     SeLockSubjectContext(SubjectContext);
233     Token = SeQuerySubjectContextToken(SubjectContext);
234 
235     // Testing SQIT with current Token
236     TestsSeQueryInformationToken(Token);
237 
238     //----------------------------------------------------------------//
239     //      Creating an ACCESS_STATE structure                        //
240     //----------------------------------------------------------------//
241 
242     AccessState = ExAllocatePool(PagedPool, sizeof(ACCESS_STATE));
243     PsProcessType = ExAllocatePool(PagedPool, sizeof(OBJECT_TYPE));
244     AuxData = ExAllocatePool(PagedPool, 0xC8);
245     GenericMapping = ExAllocatePool(PagedPool, sizeof(GENERIC_MAPPING));
246 
247     Status = SeCreateAccessState(AccessState,
248                                  (PVOID)AuxData,
249                                  DesiredAccess,
250                                  GenericMapping
251                                 );
252 
253     ok((Status == STATUS_SUCCESS), "SeCreateAccessState failed with Status 0x%08X\n", Status);
254 
255     SeCaptureSubjectContext(&AccessState->SubjectSecurityContext);
256     SeLockSubjectContext(&AccessState->SubjectSecurityContext);
257     Token = SeQuerySubjectContextToken(&AccessState->SubjectSecurityContext);
258 
259     // Testing SQIT with AccessState Token
260     TestsSeQueryInformationToken(Token);
261 
262     //----------------------------------------------------------------//
263     //      Testing other functions                                   //
264     //----------------------------------------------------------------//
265 
266     //----------------------------------------------------------------//
267     //      Testing SeAppendPrivileges                                //
268     //----------------------------------------------------------------//
269 
270     AuxData->PrivilegeSet->PrivilegeCount = 1;
271 
272     //  Testing SeAppendPrivileges. Must change PrivilegeCount to 2 (1 + 1)
273 
274     NewPrivilegeSet = ExAllocatePool(PagedPool, sizeof(PRIVILEGE_SET));
275     NewPrivilegeSet->PrivilegeCount = 1;
276 
277     Status = SeAppendPrivileges(AccessState, NewPrivilegeSet);
278     ok(Status == STATUS_SUCCESS, "SeAppendPrivileges failed\n");
279     ok((AuxData->PrivilegeSet->PrivilegeCount == 2),"PrivelegeCount must be 2, but it is %d\n", AuxData->PrivilegeSet->PrivilegeCount);
280     ExFreePool(NewPrivilegeSet);
281 
282     //----------------------------------------------------------------//
283 
284     // Testing SeAppendPrivileges. Must change PrivilegeCount to 6 (2 + 4)
285 
286     NewPrivilegeSet = ExAllocatePool(PagedPool, 4*sizeof(PRIVILEGE_SET));
287     NewPrivilegeSet->PrivilegeCount = 4;
288 
289     Status = SeAppendPrivileges(AccessState, NewPrivilegeSet);
290     ok(Status == STATUS_SUCCESS, "SeAppendPrivileges failed\n");
291     ok((AuxData->PrivilegeSet->PrivilegeCount == 6),"PrivelegeCount must be 6, but it is %d\n", AuxData->PrivilegeSet->PrivilegeCount);
292     ExFreePool(NewPrivilegeSet);
293 
294     //----------------------------------------------------------------//
295     //      Testing SePrivilegeCheck                                  //
296     //----------------------------------------------------------------//
297 
298     // KPROCESSOR_MODE is set to KernelMode ===> Always return TRUE
299     ok(SePrivilegeCheck(AuxData->PrivilegeSet, &(AccessState->SubjectSecurityContext), KernelMode), "SePrivilegeCheck failed with KernelMode mode arg\n");
300     // and call it again
301     ok(SePrivilegeCheck(AuxData->PrivilegeSet, &(AccessState->SubjectSecurityContext), KernelMode), "SePrivilegeCheck failed with KernelMode mode arg\n");
302 
303     //----------------------------------------------------------------//
304 
305     // KPROCESSOR_MODE is set to UserMode. Expect false
306     ok(!SePrivilegeCheck(AuxData->PrivilegeSet, &(AccessState->SubjectSecurityContext), UserMode), "SePrivilegeCheck unexpected success with UserMode arg\n");
307 
308     //----------------------------------------------------------------//
309 
310     //----------------------------------------------------------------//
311     //      Testing SeFreePrivileges                                  //
312     //----------------------------------------------------------------//
313 
314     Privileges = NULL;
315     Checker = SeAccessCheck(
316         AccessState->SecurityDescriptor,
317         &AccessState->SubjectSecurityContext,
318         FALSE,
319         AccessState->OriginalDesiredAccess,
320         AccessState->PreviouslyGrantedAccess,
321         &Privileges,
322         (PGENERIC_MAPPING)((PCHAR*)PsProcessType + 52),
323         KernelMode,
324         &AccessMask,
325         &Status
326         );
327     ok(Checker, "Checker is NULL\n");
328     ok((Privileges != NULL), "Privileges is NULL\n");
329     if (Privileges)
330     {
331         trace("AuxData->PrivilegeSet->PrivilegeCount = %d ; Privileges->PrivilegeCount = %d\n",
332               AuxData->PrivilegeSet->PrivilegeCount, Privileges->PrivilegeCount);
333     }
334     if (Privileges) SeFreePrivileges(Privileges);
335 
336 
337     //----------------------------------------------------------------//
338     //      Testing SePrivilegeCheck                                  //
339     //----------------------------------------------------------------//
340     // I'm trying to make success call of SePrivilegeCheck from UserMode
341     // If we sets Privileges properly, can we expect true from SePrivilegeCheck?
342     // answer: yes
343     // This test demonstrates it
344 
345     Buffer = NULL;
346     Status = SeQueryInformationToken(Token, TokenPrivileges, &Buffer);
347     if (Status == STATUS_SUCCESS)
348     {
349         ok(Buffer != NULL, "Wrong. SQIT call was successful with TokenPrivileges arg. But Buffer == NULL\n");
350         if (Buffer)
351         {
352             TPrivileges = (PTOKEN_PRIVILEGES)(Buffer);
353             //trace("TPCount = %u\n\n", TPrivileges->PrivilegeCount);
354 
355             NewPrivilegeSet = ExAllocatePool(PagedPool, 14*sizeof(PRIVILEGE_SET));
356             NewPrivilegeSet->PrivilegeCount = 14;
357 
358             ok((SeAppendPrivileges(AccessState, NewPrivilegeSet)) == STATUS_SUCCESS, "SeAppendPrivileges failed\n");
359             ok((AuxData->PrivilegeSet->PrivilegeCount == 20),"PrivelegeCount must be 20, but it is %d\n", AuxData->PrivilegeSet->PrivilegeCount);
360             ExFreePool(NewPrivilegeSet);
361             for (i = 0; i < AuxData->PrivilegeSet->PrivilegeCount; i++)
362             {
363                 AuxData->PrivilegeSet->Privilege[i].Attributes = TPrivileges->Privileges[i].Attributes;
364                 AuxData->PrivilegeSet->Privilege[i].Luid = TPrivileges->Privileges[i].Luid;
365             }
366             //trace("AccessState->privCount = %u\n\n", ((PAUX_ACCESS_DATA)(AccessState->AuxData))->PrivilegeSet->PrivilegeCount);
367 
368             ok(SePrivilegeCheck(AuxData->PrivilegeSet, &(AccessState->SubjectSecurityContext), UserMode), "SePrivilegeCheck fails in UserMode, but I wish it will success\n");
369         }
370     }
371 
372     // Call SeFreePrivileges again
373 
374     Privileges = NULL;
375     Checker = SeAccessCheck(
376         AccessState->SecurityDescriptor,
377         &AccessState->SubjectSecurityContext,
378         TRUE,
379         AccessState->OriginalDesiredAccess,
380         AccessState->PreviouslyGrantedAccess,
381         &Privileges,
382         (PGENERIC_MAPPING)((PCHAR*)PsProcessType + 52),
383         KernelMode,
384         &AccessMask,
385         &Status
386         );
387     ok(Checker, "Checker is NULL\n");
388     ok((Privileges != NULL), "Privileges is NULL\n");
389     if (Privileges)
390     {
391         trace("AuxData->PrivilegeSet->PrivilegeCount = %d ; Privileges->PrivilegeCount = %d\n",
392               AuxData->PrivilegeSet->PrivilegeCount, Privileges->PrivilegeCount);
393     }
394     if (Privileges) SeFreePrivileges(Privileges);
395 
396     //----------------------------------------------------------------//
397     //      Missing for now                                           //
398     //----------------------------------------------------------------//
399 
400     SeUnlockSubjectContext(&AccessState->SubjectSecurityContext);
401     SeUnlockSubjectContext(SubjectContext);
402 
403     SeDeleteAccessState(AccessState);
404 
405     if (GenericMapping) ExFreePool(GenericMapping);
406     if (PsProcessType) ExFreePool(PsProcessType);
407     if (SubjectContext) ExFreePool(SubjectContext);
408     if (AuxData) ExFreePool(AuxData);
409     if (AccessState) ExFreePool(AccessState);
410 }
411