xref: /reactos/ntoskrnl/se/tokencls.c (revision bbccad0e)
1 /*
2  * PROJECT:         ReactOS Kernel
3  * LICENSE:         GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:         Access token Query/Set information classes implementation
5  * COPYRIGHT:       Copyright David Welch <welch@cwcom.net>
6  *                  Copyright 2021-2022 George Bișoc <george.bisoc@reactos.org>
7  */
8 
9 /* INCLUDES *******************************************************************/
10 
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14 
15 #include <ntlsa.h>
16 
17 /* INFORMATION CLASSES ********************************************************/
18 
19 static const INFORMATION_CLASS_INFO SeTokenInformationClass[] = {
20 
21     /* Class 0 not used, blame MS! */
22     IQS_NONE,
23 
24     /* TokenUser */
25     IQS_SAME(TOKEN_USER, ULONG, ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE),
26     /* TokenGroups */
27     IQS_SAME(TOKEN_GROUPS, ULONG, ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE),
28     /* TokenPrivileges */
29     IQS_SAME(TOKEN_PRIVILEGES, ULONG, ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE),
30     /* TokenOwner */
31     IQS_SAME(TOKEN_OWNER, ULONG, ICIF_QUERY | ICIF_SET | ICIF_SIZE_VARIABLE),
32     /* TokenPrimaryGroup */
33     IQS_SAME(TOKEN_PRIMARY_GROUP, ULONG, ICIF_QUERY | ICIF_SET | ICIF_SIZE_VARIABLE),
34     /* TokenDefaultDacl */
35     IQS_SAME(TOKEN_DEFAULT_DACL, ULONG, ICIF_QUERY | ICIF_SET | ICIF_SIZE_VARIABLE),
36     /* TokenSource */
37     IQS_SAME(TOKEN_SOURCE, ULONG, ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE),
38     /* TokenType */
39     IQS_SAME(TOKEN_TYPE, ULONG, ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE),
40     /* TokenImpersonationLevel */
41     IQS_SAME(SECURITY_IMPERSONATION_LEVEL, ULONG, ICIF_QUERY),
42     /* TokenStatistics */
43     IQS_SAME(TOKEN_STATISTICS, ULONG, ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE),
44     /* TokenRestrictedSids */
45     IQS_SAME(TOKEN_GROUPS, ULONG, ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE),
46     /* TokenSessionId */
47     IQS_SAME(ULONG, ULONG, ICIF_QUERY | ICIF_SET),
48     /* TokenGroupsAndPrivileges */
49     IQS_SAME(TOKEN_GROUPS_AND_PRIVILEGES, ULONG, ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE),
50     /* TokenSessionReference */
51     IQS_SAME(ULONG, ULONG, ICIF_SET),
52     /* TokenSandBoxInert */
53     IQS_SAME(ULONG, ULONG, ICIF_QUERY),
54     /* TokenAuditPolicy */
55     IQS_SAME(TOKEN_AUDIT_POLICY_INFORMATION, ULONG, ICIF_SET | ICIF_SET_SIZE_VARIABLE),
56     /* TokenOrigin */
57     IQS_SAME(TOKEN_ORIGIN, ULONG, ICIF_QUERY | ICIF_SET),
58 };
59 
60 /* PUBLIC FUNCTIONS *****************************************************************/
61 
62 /**
63  * @brief
64  * Queries information details about the given token to the call. The difference
65  * between NtQueryInformationToken and this routine is that the system call has
66  * user mode buffer data probing and additional protection checks whereas this
67  * routine doesn't have any of these. The routine is used exclusively in kernel
68  * mode.
69  *
70  * @param[in] AccessToken
71  * An access token to be given.
72  *
73  * @param[in] TokenInformationClass
74  * Token information class.
75  *
76  * @param[out] TokenInformation
77  * Buffer with retrieved information. Such information is arbitrary, depending
78  * on the requested information class.
79  *
80  * @return
81  * Returns STATUS_SUCCESS if the operation to query the desired information
82  * has completed successfully. STATUS_INSUFFICIENT_RESOURCES is returned if
83  * pool memory allocation has failed to satisfy an operation. Otherwise
84  * STATUS_INVALID_INFO_CLASS is returned indicating that the information
85  * class provided is not supported by the routine.
86  *
87  * @remarks
88  * Only certain information classes are not implemented in this function and
89  * these are TokenOrigin, TokenGroupsAndPrivileges, TokenRestrictedSids and
90  * TokenSandBoxInert. The following classes are implemented in NtQueryInformationToken
91  * only.
92  */
93 NTSTATUS
94 NTAPI
95 SeQueryInformationToken(
96     _In_ PACCESS_TOKEN AccessToken,
97     _In_ TOKEN_INFORMATION_CLASS TokenInformationClass,
98     _Outptr_result_buffer_(_Inexpressible_(token-dependent)) PVOID *TokenInformation)
99 {
100     NTSTATUS Status;
101     PTOKEN Token = (PTOKEN)AccessToken;
102     ULONG RequiredLength;
103     union
104     {
105         PSID PSid;
106         ULONG Ulong;
107     } Unused;
108 
109     PAGED_CODE();
110 
111     /* Lock the token */
112     SepAcquireTokenLockShared(Token);
113 
114     switch (TokenInformationClass)
115     {
116         case TokenUser:
117         {
118             PTOKEN_USER tu;
119 
120             DPRINT("SeQueryInformationToken(TokenUser)\n");
121             RequiredLength = sizeof(TOKEN_USER) +
122                 RtlLengthSid(Token->UserAndGroups[0].Sid);
123 
124             /* Allocate the output buffer */
125             tu = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
126             if (tu == NULL)
127             {
128                 Status = STATUS_INSUFFICIENT_RESOURCES;
129                 break;
130             }
131 
132             Status = RtlCopySidAndAttributesArray(1,
133                                                   &Token->UserAndGroups[0],
134                                                   RequiredLength - sizeof(TOKEN_USER),
135                                                   &tu->User,
136                                                   (PSID)(tu + 1),
137                                                   &Unused.PSid,
138                                                   &Unused.Ulong);
139 
140             /* Return the structure */
141             *TokenInformation = tu;
142             Status = STATUS_SUCCESS;
143             break;
144         }
145 
146         case TokenGroups:
147         {
148             PTOKEN_GROUPS tg;
149             ULONG SidLen;
150             PSID Sid;
151 
152             DPRINT("SeQueryInformationToken(TokenGroups)\n");
153             RequiredLength = sizeof(tg->GroupCount) +
154                 RtlLengthSidAndAttributes(Token->UserAndGroupCount - 1, &Token->UserAndGroups[1]);
155 
156             SidLen = RequiredLength - sizeof(tg->GroupCount) -
157                 ((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES));
158 
159             /* Allocate the output buffer */
160             tg = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
161             if (tg == NULL)
162             {
163                 Status = STATUS_INSUFFICIENT_RESOURCES;
164                 break;
165             }
166 
167             Sid = (PSID)((ULONG_PTR)tg + sizeof(tg->GroupCount) +
168                          ((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES)));
169 
170             tg->GroupCount = Token->UserAndGroupCount - 1;
171             Status = RtlCopySidAndAttributesArray(Token->UserAndGroupCount - 1,
172                                                   &Token->UserAndGroups[1],
173                                                   SidLen,
174                                                   &tg->Groups[0],
175                                                   Sid,
176                                                   &Unused.PSid,
177                                                   &Unused.Ulong);
178 
179             /* Return the structure */
180             *TokenInformation = tg;
181             Status = STATUS_SUCCESS;
182             break;
183         }
184 
185         case TokenPrivileges:
186         {
187             PTOKEN_PRIVILEGES tp;
188 
189             DPRINT("SeQueryInformationToken(TokenPrivileges)\n");
190             RequiredLength = sizeof(tp->PrivilegeCount) +
191                 (Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
192 
193             /* Allocate the output buffer */
194             tp = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
195             if (tp == NULL)
196             {
197                 Status = STATUS_INSUFFICIENT_RESOURCES;
198                 break;
199             }
200 
201             tp->PrivilegeCount = Token->PrivilegeCount;
202             RtlCopyLuidAndAttributesArray(Token->PrivilegeCount,
203                                           Token->Privileges,
204                                           &tp->Privileges[0]);
205 
206             /* Return the structure */
207             *TokenInformation = tp;
208             Status = STATUS_SUCCESS;
209             break;
210         }
211 
212         case TokenOwner:
213         {
214             PTOKEN_OWNER to;
215             ULONG SidLen;
216 
217             DPRINT("SeQueryInformationToken(TokenOwner)\n");
218             SidLen = RtlLengthSid(Token->UserAndGroups[Token->DefaultOwnerIndex].Sid);
219             RequiredLength = sizeof(TOKEN_OWNER) + SidLen;
220 
221             /* Allocate the output buffer */
222             to = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
223             if (to == NULL)
224             {
225                 Status = STATUS_INSUFFICIENT_RESOURCES;
226                 break;
227             }
228 
229             to->Owner = (PSID)(to + 1);
230             Status = RtlCopySid(SidLen,
231                                 to->Owner,
232                                 Token->UserAndGroups[Token->DefaultOwnerIndex].Sid);
233 
234             /* Return the structure */
235             *TokenInformation = to;
236             Status = STATUS_SUCCESS;
237             break;
238         }
239 
240         case TokenPrimaryGroup:
241         {
242             PTOKEN_PRIMARY_GROUP tpg;
243             ULONG SidLen;
244 
245             DPRINT("SeQueryInformationToken(TokenPrimaryGroup)\n");
246             SidLen = RtlLengthSid(Token->PrimaryGroup);
247             RequiredLength = sizeof(TOKEN_PRIMARY_GROUP) + SidLen;
248 
249             /* Allocate the output buffer */
250             tpg = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
251             if (tpg == NULL)
252             {
253                 Status = STATUS_INSUFFICIENT_RESOURCES;
254                 break;
255             }
256 
257             tpg->PrimaryGroup = (PSID)(tpg + 1);
258             Status = RtlCopySid(SidLen,
259                                 tpg->PrimaryGroup,
260                                 Token->PrimaryGroup);
261 
262             /* Return the structure */
263             *TokenInformation = tpg;
264             Status = STATUS_SUCCESS;
265             break;
266         }
267 
268         case TokenDefaultDacl:
269         {
270             PTOKEN_DEFAULT_DACL tdd;
271 
272             DPRINT("SeQueryInformationToken(TokenDefaultDacl)\n");
273             RequiredLength = sizeof(TOKEN_DEFAULT_DACL);
274 
275             if (Token->DefaultDacl != NULL)
276                 RequiredLength += Token->DefaultDacl->AclSize;
277 
278             /* Allocate the output buffer */
279             tdd = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
280             if (tdd == NULL)
281             {
282                 Status = STATUS_INSUFFICIENT_RESOURCES;
283                 break;
284             }
285 
286             if (Token->DefaultDacl != NULL)
287             {
288                 tdd->DefaultDacl = (PACL)(tdd + 1);
289                 RtlCopyMemory(tdd->DefaultDacl,
290                               Token->DefaultDacl,
291                               Token->DefaultDacl->AclSize);
292             }
293             else
294             {
295                 tdd->DefaultDacl = NULL;
296             }
297 
298             /* Return the structure */
299             *TokenInformation = tdd;
300             Status = STATUS_SUCCESS;
301             break;
302         }
303 
304         case TokenSource:
305         {
306             PTOKEN_SOURCE ts;
307 
308             DPRINT("SeQueryInformationToken(TokenSource)\n");
309             RequiredLength = sizeof(TOKEN_SOURCE);
310 
311             /* Allocate the output buffer */
312             ts = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
313             if (ts == NULL)
314             {
315                 Status = STATUS_INSUFFICIENT_RESOURCES;
316                 break;
317             }
318 
319             *ts = Token->TokenSource;
320 
321             /* Return the structure */
322             *TokenInformation = ts;
323             Status = STATUS_SUCCESS;
324             break;
325         }
326 
327         case TokenType:
328         {
329             PTOKEN_TYPE tt;
330 
331             DPRINT("SeQueryInformationToken(TokenType)\n");
332             RequiredLength = sizeof(TOKEN_TYPE);
333 
334             /* Allocate the output buffer */
335             tt = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
336             if (tt == NULL)
337             {
338                 Status = STATUS_INSUFFICIENT_RESOURCES;
339                 break;
340             }
341 
342             *tt = Token->TokenType;
343 
344             /* Return the structure */
345             *TokenInformation = tt;
346             Status = STATUS_SUCCESS;
347             break;
348         }
349 
350         case TokenImpersonationLevel:
351         {
352             PSECURITY_IMPERSONATION_LEVEL sil;
353 
354             DPRINT("SeQueryInformationToken(TokenImpersonationLevel)\n");
355             RequiredLength = sizeof(SECURITY_IMPERSONATION_LEVEL);
356 
357             /* Fail if the token is not an impersonation token */
358             if (Token->TokenType != TokenImpersonation)
359             {
360                 Status = STATUS_INVALID_INFO_CLASS;
361                 break;
362             }
363 
364             /* Allocate the output buffer */
365             sil = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
366             if (sil == NULL)
367             {
368                 Status = STATUS_INSUFFICIENT_RESOURCES;
369                 break;
370             }
371 
372             *sil = Token->ImpersonationLevel;
373 
374             /* Return the structure */
375             *TokenInformation = sil;
376             Status = STATUS_SUCCESS;
377             break;
378         }
379 
380         case TokenStatistics:
381         {
382             PTOKEN_STATISTICS ts;
383 
384             DPRINT("SeQueryInformationToken(TokenStatistics)\n");
385             RequiredLength = sizeof(TOKEN_STATISTICS);
386 
387             /* Allocate the output buffer */
388             ts = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
389             if (ts == NULL)
390             {
391                 Status = STATUS_INSUFFICIENT_RESOURCES;
392                 break;
393             }
394 
395             ts->TokenId = Token->TokenId;
396             ts->AuthenticationId = Token->AuthenticationId;
397             ts->ExpirationTime = Token->ExpirationTime;
398             ts->TokenType = Token->TokenType;
399             ts->ImpersonationLevel = Token->ImpersonationLevel;
400             ts->DynamicCharged = Token->DynamicCharged;
401             ts->DynamicAvailable = Token->DynamicAvailable;
402             ts->GroupCount = Token->UserAndGroupCount - 1;
403             ts->PrivilegeCount = Token->PrivilegeCount;
404             ts->ModifiedId = Token->ModifiedId;
405 
406             /* Return the structure */
407             *TokenInformation = ts;
408             Status = STATUS_SUCCESS;
409             break;
410         }
411 
412         case TokenSessionId:
413         {
414             DPRINT("SeQueryInformationToken(TokenSessionId)\n");
415             Status = SeQuerySessionIdToken(Token, (PULONG)TokenInformation);
416             break;
417         }
418 
419         default:
420             DPRINT1("SeQueryInformationToken(%d) invalid information class\n", TokenInformationClass);
421             Status = STATUS_INVALID_INFO_CLASS;
422             break;
423     }
424 
425     /* Release the lock of the token */
426     SepReleaseTokenLock(Token);
427 
428     return Status;
429 }
430 
431 /* SYSTEM CALLS ***************************************************************/
432 
433 /**
434  * @brief
435  * Queries a specific type of information in regard of an access token based upon
436  * the information class. The calling thread must have specific access rights in order
437  * to obtain specific information about the token.
438  *
439  * @param[in] TokenHandle
440  * A handle of a token where information is to be gathered.
441  *
442  * @param[in] TokenInformationClass
443  * Token information class.
444  *
445  * @param[out] TokenInformation
446  * A returned output buffer with token information, which information is arbitrarily upon
447  * the information class chosen.
448  *
449  * @param[in] TokenInformationLength
450  * Length of the token information buffer, in bytes.
451  *
452  * @param[out] ReturnLength
453  * A pointer to a variable provided by the caller that receives the actual length
454  * of the buffer pointed by TokenInformation, in bytes. If TokenInformation is NULL
455  * and TokenInformationLength is 0, this parameter receives the required length
456  * needed to store the buffer information in memory. This parameter must not
457  * be NULL!
458  *
459  * @return
460  * Returns STATUS_SUCCESS if information querying has completed successfully.
461  * STATUS_BUFFER_TOO_SMALL is returned if the information length that represents
462  * the token information buffer is not greater than the required length.
463  * STATUS_INVALID_HANDLE is returned if the token handle is not a valid one.
464  * STATUS_INVALID_INFO_CLASS is returned if the information class is not a valid
465  * one (that is, the class doesn't belong to TOKEN_INFORMATION_CLASS).
466  * STATUS_ACCESS_VIOLATION is returned if ReturnLength is NULL. A failure NTSTATUS
467  * code is returned otherwise.
468  */
469 _Must_inspect_result_
470 __kernel_entry
471 NTSTATUS
472 NTAPI
473 NtQueryInformationToken(
474     _In_ HANDLE TokenHandle,
475     _In_ TOKEN_INFORMATION_CLASS TokenInformationClass,
476     _Out_writes_bytes_to_opt_(TokenInformationLength, *ReturnLength)
477         PVOID TokenInformation,
478     _In_ ULONG TokenInformationLength,
479     _Out_ PULONG ReturnLength)
480 {
481     NTSTATUS Status;
482     KPROCESSOR_MODE PreviousMode;
483     PTOKEN Token;
484     ULONG RequiredLength = 0;
485     union
486     {
487         PSID PSid;
488         ULONG Ulong;
489     } Unused;
490 
491     PAGED_CODE();
492 
493     PreviousMode = ExGetPreviousMode();
494 
495     /* Check buffers and class validity */
496     Status = DefaultQueryInfoBufferCheck(TokenInformationClass,
497                                          SeTokenInformationClass,
498                                          RTL_NUMBER_OF(SeTokenInformationClass),
499                                          ICIF_PROBE_READ_WRITE | ICIF_FORCE_RETURN_LENGTH_PROBE,
500                                          TokenInformation,
501                                          TokenInformationLength,
502                                          ReturnLength,
503                                          NULL,
504                                          PreviousMode);
505     if (!NT_SUCCESS(Status))
506     {
507         DPRINT("NtQueryInformationToken() failed, Status: 0x%x\n", Status);
508         return Status;
509     }
510 
511     Status = ObReferenceObjectByHandle(TokenHandle,
512                                        (TokenInformationClass == TokenSource) ? TOKEN_QUERY_SOURCE : TOKEN_QUERY,
513                                        SeTokenObjectType,
514                                        PreviousMode,
515                                        (PVOID*)&Token,
516                                        NULL);
517     if (NT_SUCCESS(Status))
518     {
519         /* Lock the token */
520         SepAcquireTokenLockShared(Token);
521 
522         switch (TokenInformationClass)
523         {
524             case TokenUser:
525             {
526                 PTOKEN_USER tu = (PTOKEN_USER)TokenInformation;
527 
528                 DPRINT("NtQueryInformationToken(TokenUser)\n");
529                 RequiredLength = sizeof(TOKEN_USER) +
530                     RtlLengthSid(Token->UserAndGroups[0].Sid);
531 
532                 _SEH2_TRY
533                 {
534                     if (TokenInformationLength >= RequiredLength)
535                     {
536                         Status = RtlCopySidAndAttributesArray(1,
537                                                               &Token->UserAndGroups[0],
538                                                               RequiredLength - sizeof(TOKEN_USER),
539                                                               &tu->User,
540                                                               (PSID)(tu + 1),
541                                                               &Unused.PSid,
542                                                               &Unused.Ulong);
543                     }
544                     else
545                     {
546                         Status = STATUS_BUFFER_TOO_SMALL;
547                     }
548 
549                     *ReturnLength = RequiredLength;
550                 }
551                 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
552                 {
553                     Status = _SEH2_GetExceptionCode();
554                 }
555                 _SEH2_END;
556 
557                 break;
558             }
559 
560             case TokenGroups:
561             {
562                 PTOKEN_GROUPS tg = (PTOKEN_GROUPS)TokenInformation;
563 
564                 DPRINT("NtQueryInformationToken(TokenGroups)\n");
565                 RequiredLength = sizeof(tg->GroupCount) +
566                     RtlLengthSidAndAttributes(Token->UserAndGroupCount - 1, &Token->UserAndGroups[1]);
567 
568                 _SEH2_TRY
569                 {
570                     if (TokenInformationLength >= RequiredLength)
571                     {
572                         ULONG SidLen = RequiredLength - sizeof(tg->GroupCount) -
573                             ((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES));
574                         PSID Sid = (PSID_AND_ATTRIBUTES)((ULONG_PTR)tg + sizeof(tg->GroupCount) +
575                                                          ((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES)));
576 
577                         tg->GroupCount = Token->UserAndGroupCount - 1;
578                         Status = RtlCopySidAndAttributesArray(Token->UserAndGroupCount - 1,
579                                                               &Token->UserAndGroups[1],
580                                                               SidLen,
581                                                               &tg->Groups[0],
582                                                               Sid,
583                                                               &Unused.PSid,
584                                                               &Unused.Ulong);
585                     }
586                     else
587                     {
588                         Status = STATUS_BUFFER_TOO_SMALL;
589                     }
590 
591                     *ReturnLength = RequiredLength;
592                 }
593                 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
594                 {
595                     Status = _SEH2_GetExceptionCode();
596                 }
597                 _SEH2_END;
598 
599                 break;
600             }
601 
602             case TokenPrivileges:
603             {
604                 PTOKEN_PRIVILEGES tp = (PTOKEN_PRIVILEGES)TokenInformation;
605 
606                 DPRINT("NtQueryInformationToken(TokenPrivileges)\n");
607                 RequiredLength = sizeof(tp->PrivilegeCount) +
608                     (Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
609 
610                 _SEH2_TRY
611                 {
612                     if (TokenInformationLength >= RequiredLength)
613                     {
614                         tp->PrivilegeCount = Token->PrivilegeCount;
615                         RtlCopyLuidAndAttributesArray(Token->PrivilegeCount,
616                                                       Token->Privileges,
617                                                       &tp->Privileges[0]);
618                     }
619                     else
620                     {
621                         Status = STATUS_BUFFER_TOO_SMALL;
622                     }
623 
624                     *ReturnLength = RequiredLength;
625                 }
626                 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
627                 {
628                     Status = _SEH2_GetExceptionCode();
629                 }
630                 _SEH2_END;
631 
632                 break;
633             }
634 
635             case TokenOwner:
636             {
637                 PTOKEN_OWNER to = (PTOKEN_OWNER)TokenInformation;
638                 ULONG SidLen;
639 
640                 DPRINT("NtQueryInformationToken(TokenOwner)\n");
641                 SidLen = RtlLengthSid(Token->UserAndGroups[Token->DefaultOwnerIndex].Sid);
642                 RequiredLength = sizeof(TOKEN_OWNER) + SidLen;
643 
644                 _SEH2_TRY
645                 {
646                     if (TokenInformationLength >= RequiredLength)
647                     {
648                         to->Owner = (PSID)(to + 1);
649                         Status = RtlCopySid(SidLen,
650                                             to->Owner,
651                                             Token->UserAndGroups[Token->DefaultOwnerIndex].Sid);
652                     }
653                     else
654                     {
655                         Status = STATUS_BUFFER_TOO_SMALL;
656                     }
657 
658                    *ReturnLength = RequiredLength;
659                 }
660                 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
661                 {
662                     Status = _SEH2_GetExceptionCode();
663                 }
664                 _SEH2_END;
665 
666                 break;
667             }
668 
669             case TokenPrimaryGroup:
670             {
671                 PTOKEN_PRIMARY_GROUP tpg = (PTOKEN_PRIMARY_GROUP)TokenInformation;
672                 ULONG SidLen;
673 
674                 DPRINT("NtQueryInformationToken(TokenPrimaryGroup)\n");
675                 SidLen = RtlLengthSid(Token->PrimaryGroup);
676                 RequiredLength = sizeof(TOKEN_PRIMARY_GROUP) + SidLen;
677 
678                 _SEH2_TRY
679                 {
680                     if (TokenInformationLength >= RequiredLength)
681                     {
682                         tpg->PrimaryGroup = (PSID)(tpg + 1);
683                         Status = RtlCopySid(SidLen,
684                                             tpg->PrimaryGroup,
685                                             Token->PrimaryGroup);
686                     }
687                     else
688                     {
689                         Status = STATUS_BUFFER_TOO_SMALL;
690                     }
691 
692                     *ReturnLength = RequiredLength;
693                 }
694                 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
695                 {
696                     Status = _SEH2_GetExceptionCode();
697                 }
698                 _SEH2_END;
699 
700                 break;
701             }
702 
703             case TokenDefaultDacl:
704             {
705                 PTOKEN_DEFAULT_DACL tdd = (PTOKEN_DEFAULT_DACL)TokenInformation;
706 
707                 DPRINT("NtQueryInformationToken(TokenDefaultDacl)\n");
708                 RequiredLength = sizeof(TOKEN_DEFAULT_DACL);
709 
710                 if (Token->DefaultDacl != NULL)
711                     RequiredLength += Token->DefaultDacl->AclSize;
712 
713                 _SEH2_TRY
714                 {
715                     if (TokenInformationLength >= RequiredLength)
716                     {
717                         if (Token->DefaultDacl != NULL)
718                         {
719                             tdd->DefaultDacl = (PACL)(tdd + 1);
720                             RtlCopyMemory(tdd->DefaultDacl,
721                                           Token->DefaultDacl,
722                                           Token->DefaultDacl->AclSize);
723                         }
724                         else
725                         {
726                             tdd->DefaultDacl = NULL;
727                         }
728                     }
729                     else
730                     {
731                         Status = STATUS_BUFFER_TOO_SMALL;
732                     }
733 
734                     *ReturnLength = RequiredLength;
735                 }
736                 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
737                 {
738                     Status = _SEH2_GetExceptionCode();
739                 }
740                 _SEH2_END;
741 
742                 break;
743             }
744 
745             case TokenSource:
746             {
747                 PTOKEN_SOURCE ts = (PTOKEN_SOURCE)TokenInformation;
748 
749                 DPRINT("NtQueryInformationToken(TokenSource)\n");
750                 RequiredLength = sizeof(TOKEN_SOURCE);
751 
752                 _SEH2_TRY
753                 {
754                     if (TokenInformationLength >= RequiredLength)
755                     {
756                         *ts = Token->TokenSource;
757                     }
758                     else
759                     {
760                         Status = STATUS_BUFFER_TOO_SMALL;
761                     }
762 
763                    *ReturnLength = RequiredLength;
764                 }
765                 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
766                 {
767                     Status = _SEH2_GetExceptionCode();
768                 }
769                 _SEH2_END;
770 
771                 break;
772             }
773 
774             case TokenType:
775             {
776                 PTOKEN_TYPE tt = (PTOKEN_TYPE)TokenInformation;
777 
778                 DPRINT("NtQueryInformationToken(TokenType)\n");
779                 RequiredLength = sizeof(TOKEN_TYPE);
780 
781                 _SEH2_TRY
782                 {
783                     if (TokenInformationLength >= RequiredLength)
784                     {
785                         *tt = Token->TokenType;
786                     }
787                     else
788                     {
789                         Status = STATUS_BUFFER_TOO_SMALL;
790                     }
791 
792                     *ReturnLength = RequiredLength;
793                 }
794                 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
795                 {
796                     Status = _SEH2_GetExceptionCode();
797                 }
798                 _SEH2_END;
799 
800                 break;
801             }
802 
803             case TokenImpersonationLevel:
804             {
805                 PSECURITY_IMPERSONATION_LEVEL sil = (PSECURITY_IMPERSONATION_LEVEL)TokenInformation;
806 
807                 DPRINT("NtQueryInformationToken(TokenImpersonationLevel)\n");
808 
809                 /* Fail if the token is not an impersonation token */
810                 if (Token->TokenType != TokenImpersonation)
811                 {
812                     Status = STATUS_INVALID_INFO_CLASS;
813                     break;
814                 }
815 
816                 RequiredLength = sizeof(SECURITY_IMPERSONATION_LEVEL);
817 
818                 _SEH2_TRY
819                 {
820                     if (TokenInformationLength >= RequiredLength)
821                     {
822                         *sil = Token->ImpersonationLevel;
823                     }
824                     else
825                     {
826                         Status = STATUS_BUFFER_TOO_SMALL;
827                     }
828 
829                     *ReturnLength = RequiredLength;
830                 }
831                 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
832                 {
833                     Status = _SEH2_GetExceptionCode();
834                 }
835                 _SEH2_END;
836 
837                 break;
838             }
839 
840             case TokenStatistics:
841             {
842                 PTOKEN_STATISTICS ts = (PTOKEN_STATISTICS)TokenInformation;
843 
844                 DPRINT("NtQueryInformationToken(TokenStatistics)\n");
845                 RequiredLength = sizeof(TOKEN_STATISTICS);
846 
847                 _SEH2_TRY
848                 {
849                     if (TokenInformationLength >= RequiredLength)
850                     {
851                         ts->TokenId = Token->TokenId;
852                         ts->AuthenticationId = Token->AuthenticationId;
853                         ts->ExpirationTime = Token->ExpirationTime;
854                         ts->TokenType = Token->TokenType;
855                         ts->ImpersonationLevel = Token->ImpersonationLevel;
856                         ts->DynamicCharged = Token->DynamicCharged;
857                         ts->DynamicAvailable = Token->DynamicAvailable;
858                         ts->GroupCount = Token->UserAndGroupCount - 1;
859                         ts->PrivilegeCount = Token->PrivilegeCount;
860                         ts->ModifiedId = Token->ModifiedId;
861                     }
862                     else
863                     {
864                         Status = STATUS_BUFFER_TOO_SMALL;
865                     }
866 
867                     *ReturnLength = RequiredLength;
868                 }
869                 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
870                 {
871                     Status = _SEH2_GetExceptionCode();
872                 }
873                 _SEH2_END;
874 
875                 break;
876             }
877 
878             case TokenOrigin:
879             {
880                 PTOKEN_ORIGIN to = (PTOKEN_ORIGIN)TokenInformation;
881 
882                 DPRINT("NtQueryInformationToken(TokenOrigin)\n");
883                 RequiredLength = sizeof(TOKEN_ORIGIN);
884 
885                 _SEH2_TRY
886                 {
887                     if (TokenInformationLength >= RequiredLength)
888                     {
889                         to->OriginatingLogonSession = Token->AuthenticationId;
890                     }
891                     else
892                     {
893                         Status = STATUS_BUFFER_TOO_SMALL;
894                     }
895 
896                     *ReturnLength = RequiredLength;
897                 }
898                 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
899                 {
900                     Status = _SEH2_GetExceptionCode();
901                 }
902                 _SEH2_END;
903 
904                 break;
905             }
906 
907             case TokenGroupsAndPrivileges:
908             {
909                 PSID Sid, RestrictedSid;
910                 ULONG SidLen, RestrictedSidLen;
911                 ULONG UserGroupLength, RestrictedSidLength, PrivilegeLength;
912                 PTOKEN_GROUPS_AND_PRIVILEGES GroupsAndPrivs = (PTOKEN_GROUPS_AND_PRIVILEGES)TokenInformation;
913 
914                 DPRINT("NtQueryInformationToken(TokenGroupsAndPrivileges)\n");
915                 UserGroupLength = RtlLengthSidAndAttributes(Token->UserAndGroupCount, Token->UserAndGroups);
916                 RestrictedSidLength = RtlLengthSidAndAttributes(Token->RestrictedSidCount, Token->RestrictedSids);
917                 PrivilegeLength = Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
918 
919                 RequiredLength = sizeof(TOKEN_GROUPS_AND_PRIVILEGES) +
920                                  UserGroupLength + RestrictedSidLength + PrivilegeLength;
921 
922                 _SEH2_TRY
923                 {
924                     if (TokenInformationLength >= RequiredLength)
925                     {
926                         GroupsAndPrivs->SidCount = Token->UserAndGroupCount;
927                         GroupsAndPrivs->SidLength = UserGroupLength;
928                         GroupsAndPrivs->Sids = (PSID_AND_ATTRIBUTES)(GroupsAndPrivs + 1);
929 
930                         Sid = (PSID)((ULONG_PTR)GroupsAndPrivs->Sids + (Token->UserAndGroupCount * sizeof(SID_AND_ATTRIBUTES)));
931                         SidLen = UserGroupLength - (Token->UserAndGroupCount * sizeof(SID_AND_ATTRIBUTES));
932                         Status = RtlCopySidAndAttributesArray(Token->UserAndGroupCount,
933                                                               Token->UserAndGroups,
934                                                               SidLen,
935                                                               GroupsAndPrivs->Sids,
936                                                               Sid,
937                                                               &Unused.PSid,
938                                                               &Unused.Ulong);
939                         NT_ASSERT(NT_SUCCESS(Status));
940 
941                         GroupsAndPrivs->RestrictedSidCount = Token->RestrictedSidCount;
942                         GroupsAndPrivs->RestrictedSidLength = RestrictedSidLength;
943                         GroupsAndPrivs->RestrictedSids = NULL;
944                         if (SeTokenIsRestricted(Token))
945                         {
946                             GroupsAndPrivs->RestrictedSids = (PSID_AND_ATTRIBUTES)((ULONG_PTR)GroupsAndPrivs->Sids + UserGroupLength);
947 
948                             RestrictedSid = (PSID)((ULONG_PTR)GroupsAndPrivs->RestrictedSids + (Token->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES)));
949                             RestrictedSidLen = RestrictedSidLength - (Token->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES));
950                             Status = RtlCopySidAndAttributesArray(Token->RestrictedSidCount,
951                                                                   Token->RestrictedSids,
952                                                                   RestrictedSidLen,
953                                                                   GroupsAndPrivs->RestrictedSids,
954                                                                   RestrictedSid,
955                                                                   &Unused.PSid,
956                                                                   &Unused.Ulong);
957                             NT_ASSERT(NT_SUCCESS(Status));
958                         }
959 
960                         GroupsAndPrivs->PrivilegeCount = Token->PrivilegeCount;
961                         GroupsAndPrivs->PrivilegeLength = PrivilegeLength;
962                         GroupsAndPrivs->Privileges = (PLUID_AND_ATTRIBUTES)((ULONG_PTR)(GroupsAndPrivs + 1) +
963                                                      UserGroupLength + RestrictedSidLength);
964                         RtlCopyLuidAndAttributesArray(Token->PrivilegeCount,
965                                                       Token->Privileges,
966                                                       GroupsAndPrivs->Privileges);
967 
968                         GroupsAndPrivs->AuthenticationId = Token->AuthenticationId;
969                     }
970                     else
971                     {
972                         Status = STATUS_BUFFER_TOO_SMALL;
973                     }
974 
975                     *ReturnLength = RequiredLength;
976                 }
977                 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
978                 {
979                     Status = _SEH2_GetExceptionCode();
980                 }
981                 _SEH2_END;
982 
983                 break;
984             }
985 
986             case TokenRestrictedSids:
987             {
988                 PTOKEN_GROUPS tg = (PTOKEN_GROUPS)TokenInformation;
989 
990                 DPRINT("NtQueryInformationToken(TokenRestrictedSids)\n");
991                 RequiredLength = sizeof(tg->GroupCount) +
992                 RtlLengthSidAndAttributes(Token->RestrictedSidCount, Token->RestrictedSids);
993 
994                 _SEH2_TRY
995                 {
996                     if (TokenInformationLength >= RequiredLength)
997                     {
998                         ULONG SidLen = RequiredLength - sizeof(tg->GroupCount) -
999                             (Token->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES));
1000                         PSID Sid = (PSID)((ULONG_PTR)tg + sizeof(tg->GroupCount) +
1001                                           (Token->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES)));
1002 
1003                         tg->GroupCount = Token->RestrictedSidCount;
1004                         Status = RtlCopySidAndAttributesArray(Token->RestrictedSidCount,
1005                                                               Token->RestrictedSids,
1006                                                               SidLen,
1007                                                               &tg->Groups[0],
1008                                                               Sid,
1009                                                               &Unused.PSid,
1010                                                               &Unused.Ulong);
1011                     }
1012                     else
1013                     {
1014                         Status = STATUS_BUFFER_TOO_SMALL;
1015                     }
1016 
1017                     *ReturnLength = RequiredLength;
1018                 }
1019                 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1020                 {
1021                     Status = _SEH2_GetExceptionCode();
1022                 }
1023                 _SEH2_END;
1024 
1025                 break;
1026             }
1027 
1028             case TokenSandBoxInert:
1029             {
1030                 ULONG IsTokenSandBoxInert;
1031 
1032                 DPRINT("NtQueryInformationToken(TokenSandBoxInert)\n");
1033 
1034                 IsTokenSandBoxInert = SeTokenIsInert(Token);
1035                 _SEH2_TRY
1036                 {
1037                     /* Buffer size was already verified, no need to check here again */
1038                     *(PULONG)TokenInformation = IsTokenSandBoxInert;
1039                     *ReturnLength = sizeof(ULONG);
1040                 }
1041                 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1042                 {
1043                     Status = _SEH2_GetExceptionCode();
1044                 }
1045                 _SEH2_END;
1046 
1047                 break;
1048             }
1049 
1050             case TokenSessionId:
1051             {
1052                 ULONG SessionId = 0;
1053 
1054                 DPRINT("NtQueryInformationToken(TokenSessionId)\n");
1055 
1056                 Status = SeQuerySessionIdToken(Token, &SessionId);
1057                 if (NT_SUCCESS(Status))
1058                 {
1059                     _SEH2_TRY
1060                     {
1061                         /* Buffer size was already verified, no need to check here again */
1062                         *(PULONG)TokenInformation = SessionId;
1063                         *ReturnLength = RequiredLength;
1064                     }
1065                     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1066                     {
1067                         Status = _SEH2_GetExceptionCode();
1068                     }
1069                     _SEH2_END;
1070                 }
1071 
1072                 break;
1073             }
1074 
1075             default:
1076                 DPRINT1("NtQueryInformationToken(%d) invalid information class\n", TokenInformationClass);
1077                 Status = STATUS_INVALID_INFO_CLASS;
1078                 break;
1079         }
1080 
1081         /* Unlock and dereference the token */
1082         SepReleaseTokenLock(Token);
1083         ObDereferenceObject(Token);
1084     }
1085 
1086     return Status;
1087 }
1088 
1089 /**
1090  * @unimplemented
1091  * @brief
1092  * Sets (modifies) some specific information in regard of an access token. The
1093  * calling thread must have specific access rights in order to modify token's
1094  * information data.
1095  *
1096  * @param[in] TokenHandle
1097  * A handle of a token where information is to be modified.
1098  *
1099  * @param[in] TokenInformationClass
1100  * Token information class.
1101  *
1102  * @param[in] TokenInformation
1103  * An arbitrary pointer to a buffer with token information to set. Such
1104  * arbitrary buffer depends on the information class chosen that the caller
1105  * wants to modify such information data of a token.
1106  *
1107  * @param[in] TokenInformationLength
1108  * Length of the token information buffer, in bytes.
1109  *
1110  * @return
1111  * Returns STATUS_SUCCESS if information setting has completed successfully.
1112  * STATUS_INFO_LENGTH_MISMATCH is returned if the information length of the
1113  * buffer is less than the required length. STATUS_INSUFFICIENT_RESOURCES is
1114  * returned if memory pool allocation has failed. STATUS_PRIVILEGE_NOT_HELD
1115  * is returned if the calling thread hasn't the required privileges to perform
1116  * the operation in question. A failure NTSTATUS code is returned otherwise.
1117  *
1118  * @remarks
1119  * The function is partly implemented, mainly TokenOrigin and TokenDefaultDacl.
1120  */
1121 _Must_inspect_result_
1122 __kernel_entry
1123 NTSTATUS
1124 NTAPI
1125 NtSetInformationToken(
1126     _In_ HANDLE TokenHandle,
1127     _In_ TOKEN_INFORMATION_CLASS TokenInformationClass,
1128     _In_reads_bytes_(TokenInformationLength) PVOID TokenInformation,
1129     _In_ ULONG TokenInformationLength)
1130 {
1131     NTSTATUS Status;
1132     PTOKEN Token;
1133     KPROCESSOR_MODE PreviousMode;
1134     ULONG NeededAccess = TOKEN_ADJUST_DEFAULT;
1135 
1136     PAGED_CODE();
1137 
1138     PreviousMode = ExGetPreviousMode();
1139 
1140     Status = DefaultSetInfoBufferCheck(TokenInformationClass,
1141                                        SeTokenInformationClass,
1142                                        RTL_NUMBER_OF(SeTokenInformationClass),
1143                                        TokenInformation,
1144                                        TokenInformationLength,
1145                                        PreviousMode);
1146     if (!NT_SUCCESS(Status))
1147     {
1148         /* Invalid buffers */
1149         DPRINT("NtSetInformationToken() failed, Status: 0x%x\n", Status);
1150         return Status;
1151     }
1152 
1153     if (TokenInformationClass == TokenSessionId)
1154     {
1155         NeededAccess |= TOKEN_ADJUST_SESSIONID;
1156     }
1157 
1158     Status = ObReferenceObjectByHandle(TokenHandle,
1159                                        NeededAccess,
1160                                        SeTokenObjectType,
1161                                        PreviousMode,
1162                                        (PVOID*)&Token,
1163                                        NULL);
1164     if (NT_SUCCESS(Status))
1165     {
1166         switch (TokenInformationClass)
1167         {
1168             case TokenOwner:
1169             {
1170                 if (TokenInformationLength >= sizeof(TOKEN_OWNER))
1171                 {
1172                     PTOKEN_OWNER to = (PTOKEN_OWNER)TokenInformation;
1173                     PSID InputSid = NULL, CapturedSid;
1174                     ULONG DefaultOwnerIndex;
1175 
1176                     _SEH2_TRY
1177                     {
1178                         InputSid = to->Owner;
1179                     }
1180                     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1181                     {
1182                         Status = _SEH2_GetExceptionCode();
1183                         _SEH2_YIELD(goto Cleanup);
1184                     }
1185                     _SEH2_END;
1186 
1187                     Status = SepCaptureSid(InputSid,
1188                                            PreviousMode,
1189                                            PagedPool,
1190                                            FALSE,
1191                                            &CapturedSid);
1192                     if (NT_SUCCESS(Status))
1193                     {
1194                         /* Lock the token */
1195                         SepAcquireTokenLockExclusive(Token);
1196 
1197                         /* Find the owner amongst the existing token user and groups */
1198                         Status = SepFindPrimaryGroupAndDefaultOwner(Token,
1199                                                                     NULL,
1200                                                                     CapturedSid,
1201                                                                     NULL,
1202                                                                     &DefaultOwnerIndex);
1203                         if (NT_SUCCESS(Status))
1204                         {
1205                             /* Found it */
1206                             Token->DefaultOwnerIndex = DefaultOwnerIndex;
1207                             ExAllocateLocallyUniqueId(&Token->ModifiedId);
1208                         }
1209 
1210                         /* Unlock the token */
1211                         SepReleaseTokenLock(Token);
1212 
1213                         SepReleaseSid(CapturedSid,
1214                                       PreviousMode,
1215                                       FALSE);
1216                     }
1217                 }
1218                 else
1219                 {
1220                     Status = STATUS_INFO_LENGTH_MISMATCH;
1221                 }
1222                 break;
1223             }
1224 
1225             case TokenPrimaryGroup:
1226             {
1227                 if (TokenInformationLength >= sizeof(TOKEN_PRIMARY_GROUP))
1228                 {
1229                     PTOKEN_PRIMARY_GROUP tpg = (PTOKEN_PRIMARY_GROUP)TokenInformation;
1230                     PSID InputSid = NULL, CapturedSid;
1231                     ULONG PrimaryGroupIndex;
1232 
1233                     _SEH2_TRY
1234                     {
1235                         InputSid = tpg->PrimaryGroup;
1236                     }
1237                     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1238                     {
1239                         Status = _SEH2_GetExceptionCode();
1240                         _SEH2_YIELD(goto Cleanup);
1241                     }
1242                     _SEH2_END;
1243 
1244                     Status = SepCaptureSid(InputSid,
1245                                            PreviousMode,
1246                                            PagedPool,
1247                                            FALSE,
1248                                            &CapturedSid);
1249                     if (NT_SUCCESS(Status))
1250                     {
1251                         /* Lock the token */
1252                         SepAcquireTokenLockExclusive(Token);
1253 
1254                         /* Find the primary group amongst the existing token user and groups */
1255                         Status = SepFindPrimaryGroupAndDefaultOwner(Token,
1256                                                                     CapturedSid,
1257                                                                     NULL,
1258                                                                     &PrimaryGroupIndex,
1259                                                                     NULL);
1260                         if (NT_SUCCESS(Status))
1261                         {
1262                             /* Found it */
1263                             Token->PrimaryGroup = Token->UserAndGroups[PrimaryGroupIndex].Sid;
1264                             ExAllocateLocallyUniqueId(&Token->ModifiedId);
1265                         }
1266 
1267                         /* Unlock the token */
1268                         SepReleaseTokenLock(Token);
1269 
1270                         SepReleaseSid(CapturedSid,
1271                                       PreviousMode,
1272                                       FALSE);
1273                     }
1274                 }
1275                 else
1276                 {
1277                     Status = STATUS_INFO_LENGTH_MISMATCH;
1278                 }
1279                 break;
1280             }
1281 
1282             case TokenDefaultDacl:
1283             {
1284                 if (TokenInformationLength >= sizeof(TOKEN_DEFAULT_DACL))
1285                 {
1286                     PTOKEN_DEFAULT_DACL tdd = (PTOKEN_DEFAULT_DACL)TokenInformation;
1287                     PACL InputAcl = NULL;
1288 
1289                     _SEH2_TRY
1290                     {
1291                         InputAcl = tdd->DefaultDacl;
1292                     }
1293                     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1294                     {
1295                         Status = _SEH2_GetExceptionCode();
1296                         _SEH2_YIELD(goto Cleanup);
1297                     }
1298                     _SEH2_END;
1299 
1300                     if (InputAcl != NULL)
1301                     {
1302                         PACL CapturedAcl;
1303 
1304                         /* Capture, validate, and copy the DACL */
1305                         Status = SepCaptureAcl(InputAcl,
1306                                                PreviousMode,
1307                                                PagedPool,
1308                                                TRUE,
1309                                                &CapturedAcl);
1310                         if (NT_SUCCESS(Status))
1311                         {
1312                             ULONG DynamicLength;
1313 
1314                             /* Lock the token */
1315                             SepAcquireTokenLockExclusive(Token);
1316 
1317                             //
1318                             // NOTE: So far our dynamic area only contains
1319                             // the default dacl, so this makes the following
1320                             // code pretty simple. The day where it stores
1321                             // other data, the code will require adaptations.
1322                             //
1323 
1324                             DynamicLength = Token->DynamicAvailable;
1325                             // Add here any other data length present in the dynamic area...
1326                             if (Token->DefaultDacl)
1327                                 DynamicLength += Token->DefaultDacl->AclSize;
1328 
1329                             /* Reallocate the dynamic area if it is too small */
1330                             Status = STATUS_SUCCESS;
1331                             if ((DynamicLength < CapturedAcl->AclSize) ||
1332                                 (Token->DynamicPart == NULL))
1333                             {
1334                                 PVOID NewDynamicPart;
1335 
1336                                 NewDynamicPart = ExAllocatePoolWithTag(PagedPool,
1337                                                                        CapturedAcl->AclSize,
1338                                                                        TAG_TOKEN_DYNAMIC);
1339                                 if (NewDynamicPart == NULL)
1340                                 {
1341                                     Status = STATUS_INSUFFICIENT_RESOURCES;
1342                                 }
1343                                 else
1344                                 {
1345                                     if (Token->DynamicPart != NULL)
1346                                     {
1347                                         // RtlCopyMemory(NewDynamicPart, Token->DynamicPart, DynamicLength);
1348                                         ExFreePoolWithTag(Token->DynamicPart, TAG_TOKEN_DYNAMIC);
1349                                     }
1350                                     Token->DynamicPart = NewDynamicPart;
1351                                     Token->DynamicAvailable = 0;
1352                                 }
1353                             }
1354                             else
1355                             {
1356                                 Token->DynamicAvailable = DynamicLength - CapturedAcl->AclSize;
1357                             }
1358 
1359                             if (NT_SUCCESS(Status))
1360                             {
1361                                 /* Set the new dacl */
1362                                 Token->DefaultDacl = (PVOID)Token->DynamicPart;
1363                                 RtlCopyMemory(Token->DefaultDacl,
1364                                               CapturedAcl,
1365                                               CapturedAcl->AclSize);
1366 
1367                                 ExAllocateLocallyUniqueId(&Token->ModifiedId);
1368                             }
1369 
1370                             /* Unlock the token */
1371                             SepReleaseTokenLock(Token);
1372 
1373                             ExFreePoolWithTag(CapturedAcl, TAG_ACL);
1374                         }
1375                     }
1376                     else
1377                     {
1378                         /* Lock the token */
1379                         SepAcquireTokenLockExclusive(Token);
1380 
1381                         /* Clear the default dacl if present */
1382                         if (Token->DefaultDacl != NULL)
1383                         {
1384                             Token->DynamicAvailable += Token->DefaultDacl->AclSize;
1385                             RtlZeroMemory(Token->DefaultDacl, Token->DefaultDacl->AclSize);
1386                             Token->DefaultDacl = NULL;
1387 
1388                             ExAllocateLocallyUniqueId(&Token->ModifiedId);
1389                         }
1390 
1391                         /* Unlock the token */
1392                         SepReleaseTokenLock(Token);
1393                     }
1394                 }
1395                 else
1396                 {
1397                     Status = STATUS_INFO_LENGTH_MISMATCH;
1398                 }
1399                 break;
1400             }
1401 
1402             case TokenSessionId:
1403             {
1404                 ULONG SessionId = 0;
1405 
1406                 _SEH2_TRY
1407                 {
1408                     /* Buffer size was already verified, no need to check here again */
1409                     SessionId = *(PULONG)TokenInformation;
1410                 }
1411                 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1412                 {
1413                     Status = _SEH2_GetExceptionCode();
1414                     _SEH2_YIELD(goto Cleanup);
1415                 }
1416                 _SEH2_END;
1417 
1418                 /* Check for TCB privilege */
1419                 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
1420                 {
1421                     Status = STATUS_PRIVILEGE_NOT_HELD;
1422                     break;
1423                 }
1424 
1425                 /* Lock the token */
1426                 SepAcquireTokenLockExclusive(Token);
1427 
1428                 Token->SessionId = SessionId;
1429                 ExAllocateLocallyUniqueId(&Token->ModifiedId);
1430 
1431                 /* Unlock the token */
1432                 SepReleaseTokenLock(Token);
1433 
1434                 break;
1435             }
1436 
1437             case TokenSessionReference:
1438             {
1439                 ULONG SessionReference;
1440 
1441                 _SEH2_TRY
1442                 {
1443                     /* Buffer size was already verified, no need to check here again */
1444                     SessionReference = *(PULONG)TokenInformation;
1445                 }
1446                 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1447                 {
1448                     Status = _SEH2_GetExceptionCode();
1449                     _SEH2_YIELD(goto Cleanup);
1450                 }
1451                 _SEH2_END;
1452 
1453                 /* Check for TCB privilege */
1454                 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
1455                 {
1456                     Status = STATUS_PRIVILEGE_NOT_HELD;
1457                     goto Cleanup;
1458                 }
1459 
1460                 /* Check if it is 0 */
1461                 if (SessionReference == 0)
1462                 {
1463                     ULONG OldTokenFlags;
1464 
1465                     /* Lock the token */
1466                     SepAcquireTokenLockExclusive(Token);
1467 
1468                     /* Atomically set the flag in the token */
1469                     OldTokenFlags = RtlInterlockedSetBits(&Token->TokenFlags,
1470                                                           TOKEN_SESSION_NOT_REFERENCED);
1471                     /*
1472                      * If the flag was already set, do not dereference again
1473                      * the logon session. Use SessionReference as an indicator
1474                      * to know whether to really dereference the session.
1475                      */
1476                     if (OldTokenFlags == Token->TokenFlags)
1477                         SessionReference = ULONG_MAX;
1478 
1479                     /*
1480                      * Otherwise if the flag was never set but just for this first time then
1481                      * remove the referenced logon session data from the token and dereference
1482                      * the logon session when needed.
1483                      */
1484                     if (SessionReference == 0)
1485                     {
1486                         SepRmRemoveLogonSessionFromToken(Token);
1487                         SepRmDereferenceLogonSession(&Token->AuthenticationId);
1488                     }
1489 
1490                     /* Unlock the token */
1491                     SepReleaseTokenLock(Token);
1492                 }
1493                 break;
1494             }
1495 
1496             case TokenAuditPolicy:
1497             {
1498                 PTOKEN_AUDIT_POLICY_INFORMATION PolicyInformation =
1499                     (PTOKEN_AUDIT_POLICY_INFORMATION)TokenInformation;
1500                 SEP_AUDIT_POLICY AuditPolicy;
1501                 ULONG i;
1502 
1503                 _SEH2_TRY
1504                 {
1505                     ProbeForRead(PolicyInformation,
1506                                  FIELD_OFFSET(TOKEN_AUDIT_POLICY_INFORMATION,
1507                                               Policies[PolicyInformation->PolicyCount]),
1508                                  sizeof(ULONG));
1509 
1510                     /* Loop all policies in the structure */
1511                     for (i = 0; i < PolicyInformation->PolicyCount; i++)
1512                     {
1513                         /* Set the corresponding bits in the packed structure */
1514                         switch (PolicyInformation->Policies[i].Category)
1515                         {
1516                             case AuditCategorySystem:
1517                                 AuditPolicy.PolicyElements.System = PolicyInformation->Policies[i].Value;
1518                                 break;
1519 
1520                             case AuditCategoryLogon:
1521                                 AuditPolicy.PolicyElements.Logon = PolicyInformation->Policies[i].Value;
1522                                 break;
1523 
1524                             case AuditCategoryObjectAccess:
1525                                 AuditPolicy.PolicyElements.ObjectAccess = PolicyInformation->Policies[i].Value;
1526                                 break;
1527 
1528                             case AuditCategoryPrivilegeUse:
1529                                 AuditPolicy.PolicyElements.PrivilegeUse = PolicyInformation->Policies[i].Value;
1530                                 break;
1531 
1532                             case AuditCategoryDetailedTracking:
1533                                 AuditPolicy.PolicyElements.DetailedTracking = PolicyInformation->Policies[i].Value;
1534                                 break;
1535 
1536                             case AuditCategoryPolicyChange:
1537                                 AuditPolicy.PolicyElements.PolicyChange = PolicyInformation->Policies[i].Value;
1538                                 break;
1539 
1540                             case AuditCategoryAccountManagement:
1541                                 AuditPolicy.PolicyElements.AccountManagement = PolicyInformation->Policies[i].Value;
1542                                 break;
1543 
1544                             case AuditCategoryDirectoryServiceAccess:
1545                                 AuditPolicy.PolicyElements.DirectoryServiceAccess = PolicyInformation->Policies[i].Value;
1546                                 break;
1547 
1548                             case AuditCategoryAccountLogon:
1549                                 AuditPolicy.PolicyElements.AccountLogon = PolicyInformation->Policies[i].Value;
1550                                 break;
1551                         }
1552                     }
1553                 }
1554                 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1555                 {
1556                     Status = _SEH2_GetExceptionCode();
1557                     _SEH2_YIELD(goto Cleanup);
1558                 }
1559                 _SEH2_END;
1560 
1561                 /* Check for TCB privilege */
1562                 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
1563                 {
1564                     Status = STATUS_PRIVILEGE_NOT_HELD;
1565                     break;
1566                 }
1567 
1568                 /* Lock the token */
1569                 SepAcquireTokenLockExclusive(Token);
1570 
1571                 /* Set the new audit policy */
1572                 Token->AuditPolicy = AuditPolicy;
1573                 ExAllocateLocallyUniqueId(&Token->ModifiedId);
1574 
1575                 /* Unlock the token */
1576                 SepReleaseTokenLock(Token);
1577 
1578                 break;
1579             }
1580 
1581             case TokenOrigin:
1582             {
1583                 TOKEN_ORIGIN TokenOrigin;
1584 
1585                 _SEH2_TRY
1586                 {
1587                     /* Copy the token origin */
1588                     TokenOrigin = *(PTOKEN_ORIGIN)TokenInformation;
1589                 }
1590                 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1591                 {
1592                     Status = _SEH2_GetExceptionCode();
1593                     _SEH2_YIELD(goto Cleanup);
1594                 }
1595                 _SEH2_END;
1596 
1597                 /* Check for TCB privilege */
1598                 if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
1599                 {
1600                     Status = STATUS_PRIVILEGE_NOT_HELD;
1601                     break;
1602                 }
1603 
1604                 /* Lock the token */
1605                 SepAcquireTokenLockExclusive(Token);
1606 
1607                 /* Check if there is no token origin set yet */
1608                 if (RtlIsZeroLuid(&Token->OriginatingLogonSession))
1609                 {
1610                     /* Set the token origin */
1611                     Token->OriginatingLogonSession =
1612                         TokenOrigin.OriginatingLogonSession;
1613 
1614                     ExAllocateLocallyUniqueId(&Token->ModifiedId);
1615                 }
1616 
1617                 /* Unlock the token */
1618                 SepReleaseTokenLock(Token);
1619 
1620                 break;
1621             }
1622 
1623             default:
1624             {
1625                 DPRINT1("Invalid TokenInformationClass: 0x%lx\n",
1626                         TokenInformationClass);
1627                 Status = STATUS_INVALID_INFO_CLASS;
1628                 break;
1629             }
1630         }
1631 Cleanup:
1632         ObDereferenceObject(Token);
1633     }
1634 
1635     if (!NT_SUCCESS(Status))
1636     {
1637         DPRINT1("NtSetInformationToken failed with Status 0x%lx\n", Status);
1638     }
1639 
1640     return Status;
1641 }
1642 
1643 /* EOF */
1644