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
OpenCurrentToken(VOID)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
QueryTokenUserTests(_In_ HANDLE Token)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
QueryTokenGroupsTests(_In_ HANDLE Token)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
QueryTokenPrivilegesTests(_In_ HANDLE Token)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
QueryTokenOwnerTests(_In_ HANDLE Token)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
QueryTokenPrimaryGroupTests(_In_ HANDLE Token)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
QueryTokenDefaultDaclTests(_In_ HANDLE Token)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
QueryTokenSourceTests(_In_ HANDLE Token)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
QueryTokenTypeTests(_In_ HANDLE Token)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
QueryTokenImpersonationTests(_In_ HANDLE Token)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
QueryTokenStatisticsTests(_In_ HANDLE Token)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
QueryTokenPrivilegesAndGroupsTests(_In_ HANDLE Token)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
QueryTokenRestrictedSidsTest(_In_ HANDLE Token)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
QueryTokenSessionIdTests(_In_ HANDLE Token)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
QueryTokenIsSandboxInert(_In_ HANDLE Token)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
QueryTokenOriginTests(_In_ HANDLE Token)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
START_TEST(NtQueryInformationToken)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