ReactOS  0.4.15-dev-3712-gf1ad684
token.c
Go to the documentation of this file.
1 /*
2  * PROJECT: ReactOS Kernel
3  * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE: Security token implementation support
5  * COPYRIGHT: Copyright David Welch <welch@cwcom.net>
6  * Copyright 2021 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 /* GLOBALS ********************************************************************/
18 
20 
21 TOKEN_SOURCE SeSystemTokenSource = {"*SYSTEM*", {0}};
24 
26  TOKEN_READ,
30 };
31 
33 
34  /* Class 0 not used, blame MS! */
35  IQS_NONE,
36 
37  /* TokenUser */
39  /* TokenGroups */
41  /* TokenPrivileges */
43  /* TokenOwner */
45  /* TokenPrimaryGroup */
47  /* TokenDefaultDacl */
49  /* TokenSource */
51  /* TokenType */
53  /* TokenImpersonationLevel */
55  /* TokenStatistics */
57  /* TokenRestrictedSids */
59  /* TokenSessionId */
61  /* TokenGroupsAndPrivileges */
63  /* TokenSessionReference */
65  /* TokenSandBoxInert */
67  /* TokenAuditPolicy */
69  /* TokenOrigin */
71 };
72 
73 /* FUNCTIONS *****************************************************************/
74 
87 static
91 {
92  PAGED_CODE();
93 
95  sizeof(ERESOURCE),
97  if (Token->TokenLock == NULL)
98  {
99  DPRINT1("SepCreateTokenLock(): Failed to allocate memory!\n");
101  }
102 
103  ExInitializeResourceLite(Token->TokenLock);
104  return STATUS_SUCCESS;
105 }
106 
117 static
118 VOID
121 {
122  PAGED_CODE();
123 
124  ExDeleteResourceLite(Token->TokenLock);
126 }
127 
150 static
151 BOOLEAN
153  _In_ PSID_AND_ATTRIBUTES SidArrayToken1,
154  _In_ ULONG CountSidArray1,
155  _In_ PSID_AND_ATTRIBUTES SidArrayToken2,
156  _In_ ULONG CountSidArray2)
157 {
158  ULONG FirstCount, SecondCount;
159  PSID_AND_ATTRIBUTES FirstSidArray, SecondSidArray;
160  PAGED_CODE();
161 
162  /* Bail out if index counters provided are not equal */
163  if (CountSidArray1 != CountSidArray2)
164  {
165  DPRINT("SepCompareSidAndAttributesFromTokens(): Index counters are not the same!\n");
166  return FALSE;
167  }
168 
169  /* Loop over the SID arrays and compare them */
170  for (FirstCount = 0; FirstCount < CountSidArray1; FirstCount++)
171  {
172  for (SecondCount = 0; SecondCount < CountSidArray2; SecondCount++)
173  {
174  FirstSidArray = &SidArrayToken1[FirstCount];
175  SecondSidArray = &SidArrayToken2[SecondCount];
176 
177  if (RtlEqualSid(FirstSidArray->Sid, SecondSidArray->Sid) &&
178  FirstSidArray->Attributes == SecondSidArray->Attributes)
179  {
180  break;
181  }
182  }
183 
184  /* We've exhausted the array of the second token without finding this one */
185  if (SecondCount == CountSidArray2)
186  {
187  DPRINT("SepCompareSidAndAttributesFromTokens(): No matching elements could be found in either token!\n");
188  return FALSE;
189  }
190  }
191 
192  return TRUE;
193 }
194 
217 static
218 BOOLEAN
220  _In_ PLUID_AND_ATTRIBUTES PrivArrayToken1,
221  _In_ ULONG CountPrivArray1,
222  _In_ PLUID_AND_ATTRIBUTES PrivArrayToken2,
223  _In_ ULONG CountPrivArray2)
224 {
225  ULONG FirstCount, SecondCount;
226  PLUID_AND_ATTRIBUTES FirstPrivArray, SecondPrivArray;
227  PAGED_CODE();
228 
229  /* Bail out if index counters provided are not equal */
230  if (CountPrivArray1 != CountPrivArray2)
231  {
232  DPRINT("SepComparePrivilegeAndAttributesFromTokens(): Index counters are not the same!\n");
233  return FALSE;
234  }
235 
236  /* Loop over the privilege arrays and compare them */
237  for (FirstCount = 0; FirstCount < CountPrivArray1; FirstCount++)
238  {
239  for (SecondCount = 0; SecondCount < CountPrivArray2; SecondCount++)
240  {
241  FirstPrivArray = &PrivArrayToken1[FirstCount];
242  SecondPrivArray = &PrivArrayToken2[SecondCount];
243 
244  if (RtlEqualLuid(&FirstPrivArray->Luid, &SecondPrivArray->Luid) &&
245  FirstPrivArray->Attributes == SecondPrivArray->Attributes)
246  {
247  break;
248  }
249  }
250 
251  /* We've exhausted the array of the second token without finding this one */
252  if (SecondCount == CountPrivArray2)
253  {
254  DPRINT("SepComparePrivilegeAndAttributesFromTokens(): No matching elements could be found in either token!\n");
255  return FALSE;
256  }
257  }
258 
259  return TRUE;
260 }
261 
286 static
287 NTSTATUS
289  _In_ PTOKEN FirstToken,
290  _In_ PTOKEN SecondToken,
291  _Out_ PBOOLEAN Equal)
292 {
294  PAGED_CODE();
295 
296  ASSERT(FirstToken != SecondToken);
297 
298  /* Lock the tokens */
299  SepAcquireTokenLockShared(FirstToken);
300  SepAcquireTokenLockShared(SecondToken);
301 
302  /* Check if every SID that is present in either token is also present in the other one */
303  if (!SepCompareSidAndAttributesFromTokens(FirstToken->UserAndGroups,
304  FirstToken->UserAndGroupCount,
305  SecondToken->UserAndGroups,
306  SecondToken->UserAndGroupCount))
307  {
308  goto Quit;
309  }
310 
311  /* Is one token restricted but the other isn't? */
312  Restricted = SeTokenIsRestricted(FirstToken);
313  if (Restricted != SeTokenIsRestricted(SecondToken))
314  {
315  /* If that's the case then bail out */
316  goto Quit;
317  }
318 
319  /*
320  * If both tokens are restricted check if every SID
321  * that is restricted in either token is also restricted
322  * in the other one.
323  */
324  if (Restricted)
325  {
326  if (!SepCompareSidAndAttributesFromTokens(FirstToken->RestrictedSids,
327  FirstToken->RestrictedSidCount,
328  SecondToken->RestrictedSids,
329  SecondToken->RestrictedSidCount))
330  {
331  goto Quit;
332  }
333  }
334 
335  /* Check if every privilege present in either token is also present in the other one */
336  if (!SepComparePrivilegeAndAttributesFromTokens(FirstToken->Privileges,
337  FirstToken->PrivilegeCount,
338  SecondToken->Privileges,
339  SecondToken->PrivilegeCount))
340  {
341  goto Quit;
342  }
343 
344  /* If we're here then the tokens are equal */
345  IsEqual = TRUE;
346  DPRINT("SepCompareTokens(): Tokens are equal!\n");
347 
348 Quit:
349  /* Unlock the tokens */
350  SepReleaseTokenLock(SecondToken);
351  SepReleaseTokenLock(FirstToken);
352 
353  *Equal = IsEqual;
354  return STATUS_SUCCESS;
355 }
356 
377 static
378 NTSTATUS
382 {
384  PTOKEN TokenToImpersonate, ProcessToken;
385  ULONG IncludeEveryoneValueData;
386  PAGED_CODE();
387 
388  /*
389  * We must check first which kind of token
390  * shall we assign for the thread to impersonate,
391  * the one with Everyone Group SID or the other
392  * without. Invoke the registry helper to
393  * return the data value for us.
394  */
395  Status = SepRegQueryHelper(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\Lsa",
396  L"EveryoneIncludesAnonymous",
397  REG_DWORD,
398  sizeof(IncludeEveryoneValueData),
399  &IncludeEveryoneValueData);
400  if (!NT_SUCCESS(Status))
401  {
402  DPRINT1("SepRegQueryHelper(): Failed to query the registry value (Status 0x%lx)\n", Status);
403  return Status;
404  }
405 
406  if (IncludeEveryoneValueData == 0)
407  {
408  DPRINT("SepImpersonateAnonymousToken(): Assigning the token not including the Everyone Group SID...\n");
409  TokenToImpersonate = SeAnonymousLogonTokenNoEveryone;
410  }
411  else
412  {
413  DPRINT("SepImpersonateAnonymousToken(): Assigning the token including the Everyone Group SID...\n");
414  TokenToImpersonate = SeAnonymousLogonToken;
415  }
416 
417  /*
418  * Tell the object manager that we're going to use this token
419  * object now by incrementing the reference count.
420  */
421  Status = ObReferenceObjectByPointer(TokenToImpersonate,
424  PreviousMode);
425  if (!NT_SUCCESS(Status))
426  {
427  DPRINT1("SepImpersonateAnonymousToken(): Couldn't be able to use the token, bail out...\n");
428  return Status;
429  }
430 
431  /*
432  * Reference the primary token of the current process that the anonymous
433  * logon token impersonation procedure is being performed. We'll be going
434  * to use the process' token to figure out if the process is actually
435  * restricted or not.
436  */
438  if (!ProcessToken)
439  {
440  DPRINT1("SepImpersonateAnonymousToken(): Couldn't be able to get the process' primary token, bail out...\n");
441  ObDereferenceObject(TokenToImpersonate);
442  return STATUS_UNSUCCESSFUL;
443  }
444 
445  /* Now, is the token from the current process restricted? */
446  if (SeTokenIsRestricted(ProcessToken))
447  {
448  DPRINT1("SepImpersonateAnonymousToken(): The process is restricted, can't do anything. Bail out...\n");
449  PsDereferencePrimaryToken(ProcessToken);
450  ObDereferenceObject(TokenToImpersonate);
451  return STATUS_ACCESS_DENIED;
452  }
453 
454  /*
455  * Finally it's time to impersonate! But first, fast dereference the
456  * process' primary token as we no longer need it.
457  */
460  if (!NT_SUCCESS(Status))
461  {
462  DPRINT1("SepImpersonateAnonymousToken(): Failed to impersonate, bail out...\n");
463  ObDereferenceObject(TokenToImpersonate);
464  return Status;
465  }
466 
467  return Status;
468 }
469 
486 static
487 VOID
490  _In_ ULONG Index)
491 {
492  ULONG TokenFlag;
493  ASSERT(Index < Token->PrivilegeCount);
494 
495  /* The high part of all values we are interested in is 0 */
496  if (Token->Privileges[Index].Luid.HighPart != 0)
497  {
498  return;
499  }
500 
501  /* Check for certain privileges to update flags */
502  if (Token->Privileges[Index].Luid.LowPart == SE_CHANGE_NOTIFY_PRIVILEGE)
503  {
504  TokenFlag = TOKEN_HAS_TRAVERSE_PRIVILEGE;
505  }
506  else if (Token->Privileges[Index].Luid.LowPart == SE_BACKUP_PRIVILEGE)
507  {
508  TokenFlag = TOKEN_HAS_BACKUP_PRIVILEGE;
509  }
510  else if (Token->Privileges[Index].Luid.LowPart == SE_RESTORE_PRIVILEGE)
511  {
512  TokenFlag = TOKEN_HAS_RESTORE_PRIVILEGE;
513  }
514  else if (Token->Privileges[Index].Luid.LowPart == SE_IMPERSONATE_PRIVILEGE)
515  {
517  }
518  else
519  {
520  /* Nothing to do */
521  return;
522  }
523 
524  /* Check if the specified privilege is enabled */
525  if (Token->Privileges[Index].Attributes & SE_PRIVILEGE_ENABLED)
526  {
527  /* It is enabled, so set the flag */
528  Token->TokenFlags |= TokenFlag;
529  }
530  else
531  {
532  /* Is is disabled, so remove the flag */
533  Token->TokenFlags &= ~TokenFlag;
534  }
535 }
536 
549 static
550 VOID
553 {
554  ULONG i;
555 
556  /* Loop all privileges */
557  for (i = 0; i < Token->PrivilegeCount; i++)
558  {
559  /* Updates the flags for this privilege */
561  }
562 }
563 
578 static
579 VOID
582  _In_ ULONG Index)
583 {
584  ULONG MoveCount;
585  ASSERT(Index < Token->PrivilegeCount);
586 
587  /* Calculate the number of trailing privileges */
588  MoveCount = Token->PrivilegeCount - Index - 1;
589  if (MoveCount != 0)
590  {
591  /* Move them one location ahead */
592  RtlMoveMemory(&Token->Privileges[Index],
593  &Token->Privileges[Index + 1],
594  MoveCount * sizeof(LUID_AND_ATTRIBUTES));
595  }
596 
597  /* Update privilege count */
598  Token->PrivilegeCount--;
599 }
600 
615 static
616 VOID
619  _In_ ULONG Index)
620 {
621  ULONG MoveCount;
622  ASSERT(Index < Token->UserAndGroupCount);
623 
624  /* Calculate the number of trailing groups */
625  MoveCount = Token->UserAndGroupCount - Index - 1;
626  if (MoveCount != 0)
627  {
628  /* Time to remove the group by moving one location ahead */
629  RtlMoveMemory(&Token->UserAndGroups[Index],
630  &Token->UserAndGroups[Index + 1],
631  MoveCount * sizeof(SID_AND_ATTRIBUTES));
632  }
633 
634  /* Remove one group count */
635  Token->UserAndGroupCount--;
636 }
637 
649 VOID
650 NTAPI
652  _Inout_ PVOID ProxyData)
653 {
655 }
656 
671 NTSTATUS
672 NTAPI
674  _Out_ PVOID* Dest,
675  _In_ PVOID Src)
676 {
678  return STATUS_NOT_IMPLEMENTED;
679 }
680 
702 NTSTATUS
703 NTAPI
706  _In_ PACCESS_TOKEN NewAccessToken,
707  _Out_ PACCESS_TOKEN* OldAccessToken)
708 {
709  PTOKEN OldToken;
710  PTOKEN NewToken = (PTOKEN)NewAccessToken;
711 
712  PAGED_CODE();
713 
714  if (NewToken->TokenType != TokenPrimary)
715  return STATUS_BAD_TOKEN_TYPE;
716 
717  if (NewToken->TokenInUse)
718  {
721 
722  /* Maybe we're trying to set the same token */
723  OldToken = PsReferencePrimaryToken(Process);
724  if (OldToken == NewToken)
725  {
726  /* So it's a nop. */
727  *OldAccessToken = OldToken;
728  return STATUS_SUCCESS;
729  }
730 
731  Status = SepCompareTokens(OldToken, NewToken, &IsEqual);
732  if (!NT_SUCCESS(Status))
733  {
734  PsDereferencePrimaryToken(OldToken);
735  *OldAccessToken = NULL;
736  return Status;
737  }
738 
739  if (!IsEqual)
740  {
741  PsDereferencePrimaryToken(OldToken);
742  *OldAccessToken = NULL;
744  }
745  /* Silently return STATUS_SUCCESS but do not set the new token,
746  * as it's already in use elsewhere. */
747  *OldAccessToken = OldToken;
748  return STATUS_SUCCESS;
749  }
750 
751  /* Lock the new token */
753 
754  /* Mark new token in use */
755  NewToken->TokenInUse = TRUE;
756 
757  /* Set the session ID for the new token */
758  NewToken->SessionId = MmGetSessionId(Process);
759 
760  /* Unlock the new token */
761  SepReleaseTokenLock(NewToken);
762 
763  /* Reference the new token */
764  ObReferenceObject(NewToken);
765 
766  /* Replace the old with the new */
767  OldToken = ObFastReplaceObject(&Process->Token, NewToken);
768 
769  /* Lock the old token */
771 
772  /* Mark the old token as free */
773  OldToken->TokenInUse = FALSE;
774 
775  /* Unlock the old token */
776  SepReleaseTokenLock(OldToken);
777 
778  *OldAccessToken = (PACCESS_TOKEN)OldToken;
779  return STATUS_SUCCESS;
780 }
781 
792 VOID
793 NTAPI
796 {
797  PTOKEN OldToken;
798 
799  /* Remove the Token */
800  OldToken = ObFastReplaceObject(&Process->Token, NULL);
801 
802  /* Mark the Old Token as free */
803  OldToken->TokenInUse = FALSE;
804 
805  /* Dereference the Token */
806  ObDereferenceObject(OldToken);
807 }
808 
822 static ULONG
824  _In_ ULONG Count,
826 {
827  ULONG i;
828  ULONG uLength;
829 
830  PAGED_CODE();
831 
832  uLength = Count * sizeof(SID_AND_ATTRIBUTES);
833  for (i = 0; i < Count; i++)
834  uLength += RtlLengthSid(Src[i].Sid);
835 
836  return uLength;
837 }
838 
868 static NTSTATUS
870  _In_ PTOKEN Token,
872  _In_opt_ PSID DefaultOwner,
873  _Out_opt_ PULONG PrimaryGroupIndex,
874  _Out_opt_ PULONG DefaultOwnerIndex)
875 {
876  ULONG i;
877 
878  /* We should return at least a search result */
879  if (!PrimaryGroupIndex && !DefaultOwnerIndex)
881 
882  if (PrimaryGroupIndex)
883  {
884  /* Initialize with an invalid index */
885  // Token->PrimaryGroup = NULL;
886  *PrimaryGroupIndex = Token->UserAndGroupCount;
887  }
888 
889  if (DefaultOwnerIndex)
890  {
891  if (DefaultOwner)
892  {
893  /* An owner is specified: check whether this is actually the user */
894  if (RtlEqualSid(Token->UserAndGroups[0].Sid, DefaultOwner))
895  {
896  /*
897  * It's the user (first element in array): set it
898  * as the owner and stop the search for it.
899  */
900  *DefaultOwnerIndex = 0;
901  DefaultOwnerIndex = NULL;
902  }
903  else
904  {
905  /* An owner is specified: initialize with an invalid index */
906  *DefaultOwnerIndex = Token->UserAndGroupCount;
907  }
908  }
909  else
910  {
911  /*
912  * No owner specified: set the user (first element in array)
913  * as the owner and stop the search for it.
914  */
915  *DefaultOwnerIndex = 0;
916  DefaultOwnerIndex = NULL;
917  }
918  }
919 
920  /* Validate and set the primary group and default owner indices */
921  for (i = 0; i < Token->UserAndGroupCount; i++)
922  {
923  /* Stop the search if we have found what we searched for */
924  if (!PrimaryGroupIndex && !DefaultOwnerIndex)
925  break;
926 
927  if (DefaultOwnerIndex && DefaultOwner &&
928  RtlEqualSid(Token->UserAndGroups[i].Sid, DefaultOwner) &&
929  (Token->UserAndGroups[i].Attributes & SE_GROUP_OWNER))
930  {
931  /* Owner is found, stop the search for it */
932  *DefaultOwnerIndex = i;
933  DefaultOwnerIndex = NULL;
934  }
935 
936  if (PrimaryGroupIndex &&
937  RtlEqualSid(Token->UserAndGroups[i].Sid, PrimaryGroup))
938  {
939  /* Primary group is found, stop the search for it */
940  // Token->PrimaryGroup = Token->UserAndGroups[i].Sid;
941  *PrimaryGroupIndex = i;
942  PrimaryGroupIndex = NULL;
943  }
944  }
945 
946  if (DefaultOwnerIndex)
947  {
948  if (*DefaultOwnerIndex == Token->UserAndGroupCount)
949  return STATUS_INVALID_OWNER;
950  }
951 
952  if (PrimaryGroupIndex)
953  {
954  if (*PrimaryGroupIndex == Token->UserAndGroupCount)
955  // if (Token->PrimaryGroup == NULL)
957  }
958 
959  return STATUS_SUCCESS;
960 }
961 
993 NTSTATUS
994 NTAPI
996  _In_ PTOKEN Token,
1002  _Out_ PTOKEN* NewAccessToken)
1003 {
1004  NTSTATUS Status;
1005  PTOKEN AccessToken;
1006  PVOID EndMem;
1007  ULONG PrimaryGroupIndex;
1008  ULONG VariableLength;
1009  ULONG TotalSize;
1010  ULONG PrivilegesIndex, GroupsIndex;
1011 
1012  PAGED_CODE();
1013 
1014  /* Compute how much size we need to allocate for the token */
1015  VariableLength = Token->VariableLength;
1016  TotalSize = FIELD_OFFSET(TOKEN, VariablePart) + VariableLength;
1017 
1021  PreviousMode,
1022  NULL,
1023  TotalSize,
1024  0,
1025  0,
1026  (PVOID*)&AccessToken);
1027  if (!NT_SUCCESS(Status))
1028  {
1029  DPRINT1("ObCreateObject() failed (Status 0x%lx)\n", Status);
1030  return Status;
1031  }
1032 
1033  /* Zero out the buffer and initialize the token */
1034  RtlZeroMemory(AccessToken, TotalSize);
1035 
1036  ExAllocateLocallyUniqueId(&AccessToken->TokenId);
1037 
1038  AccessToken->TokenType = TokenType;
1039  AccessToken->ImpersonationLevel = Level;
1040 
1041  /* Initialise the lock for the access token */
1042  Status = SepCreateTokenLock(AccessToken);
1043  if (!NT_SUCCESS(Status))
1044  {
1045  ObDereferenceObject(AccessToken);
1046  return Status;
1047  }
1048 
1049  /* Copy the immutable fields */
1050  RtlCopyLuid(&AccessToken->TokenSource.SourceIdentifier,
1051  &Token->TokenSource.SourceIdentifier);
1052  RtlCopyMemory(AccessToken->TokenSource.SourceName,
1053  Token->TokenSource.SourceName,
1054  sizeof(Token->TokenSource.SourceName));
1055 
1056  AccessToken->AuthenticationId = Token->AuthenticationId;
1057  AccessToken->ParentTokenId = Token->ParentTokenId;
1058  AccessToken->ExpirationTime = Token->ExpirationTime;
1059  AccessToken->OriginatingLogonSession = Token->OriginatingLogonSession;
1060 
1061  /* Lock the source token and copy the mutable fields */
1063 
1064  AccessToken->SessionId = Token->SessionId;
1065  RtlCopyLuid(&AccessToken->ModifiedId, &Token->ModifiedId);
1066 
1067  AccessToken->TokenFlags = Token->TokenFlags & ~TOKEN_SESSION_NOT_REFERENCED;
1068 
1069  /* Reference the logon session */
1070  Status = SepRmReferenceLogonSession(&AccessToken->AuthenticationId);
1071  if (!NT_SUCCESS(Status))
1072  {
1073  /* No logon session could be found, bail out */
1074  DPRINT1("SepRmReferenceLogonSession() failed (Status 0x%lx)\n", Status);
1075  /* Set the flag for proper cleanup by the delete procedure */
1076  AccessToken->TokenFlags |= TOKEN_SESSION_NOT_REFERENCED;
1077  goto Quit;
1078  }
1079 
1080  /* Insert the referenced logon session into the token */
1082  if (!NT_SUCCESS(Status))
1083  {
1084  /* Failed to insert the logon session into the token, bail out */
1085  DPRINT1("SepRmInsertLogonSessionIntoToken() failed (Status 0x%lx)\n", Status);
1086  goto Quit;
1087  }
1088 
1089  /* Assign the data that reside in the TOKEN's variable information area */
1090  AccessToken->VariableLength = VariableLength;
1091  EndMem = (PVOID)&AccessToken->VariablePart;
1092 
1093  /* Copy the privileges */
1094  AccessToken->PrivilegeCount = 0;
1095  AccessToken->Privileges = NULL;
1096  if (Token->Privileges && (Token->PrivilegeCount > 0))
1097  {
1098  ULONG PrivilegesLength = Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
1099  PrivilegesLength = ALIGN_UP_BY(PrivilegesLength, sizeof(PVOID));
1100 
1101  ASSERT(VariableLength >= PrivilegesLength);
1102 
1103  AccessToken->PrivilegeCount = Token->PrivilegeCount;
1104  AccessToken->Privileges = EndMem;
1105  EndMem = (PVOID)((ULONG_PTR)EndMem + PrivilegesLength);
1106  VariableLength -= PrivilegesLength;
1107 
1108  RtlCopyMemory(AccessToken->Privileges,
1109  Token->Privileges,
1110  AccessToken->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
1111  }
1112 
1113  /* Copy the user and groups */
1114  AccessToken->UserAndGroupCount = 0;
1115  AccessToken->UserAndGroups = NULL;
1116  if (Token->UserAndGroups && (Token->UserAndGroupCount > 0))
1117  {
1118  AccessToken->UserAndGroupCount = Token->UserAndGroupCount;
1119  AccessToken->UserAndGroups = EndMem;
1120  EndMem = &AccessToken->UserAndGroups[AccessToken->UserAndGroupCount];
1121  VariableLength -= ((ULONG_PTR)EndMem - (ULONG_PTR)AccessToken->UserAndGroups);
1122 
1123  Status = RtlCopySidAndAttributesArray(AccessToken->UserAndGroupCount,
1124  Token->UserAndGroups,
1125  VariableLength,
1126  AccessToken->UserAndGroups,
1127  EndMem,
1128  &EndMem,
1129  &VariableLength);
1130  if (!NT_SUCCESS(Status))
1131  {
1132  DPRINT1("RtlCopySidAndAttributesArray(UserAndGroups) failed (Status 0x%lx)\n", Status);
1133  goto Quit;
1134  }
1135  }
1136 
1137  /* Find the token primary group */
1139  Token->PrimaryGroup,
1140  NULL,
1141  &PrimaryGroupIndex,
1142  NULL);
1143  if (!NT_SUCCESS(Status))
1144  {
1145  DPRINT1("SepFindPrimaryGroupAndDefaultOwner failed (Status 0x%lx)\n", Status);
1146  goto Quit;
1147  }
1148 
1149  AccessToken->PrimaryGroup = AccessToken->UserAndGroups[PrimaryGroupIndex].Sid;
1150  AccessToken->DefaultOwnerIndex = Token->DefaultOwnerIndex;
1151 
1152  /* Copy the restricted SIDs */
1153  AccessToken->RestrictedSidCount = 0;
1154  AccessToken->RestrictedSids = NULL;
1155  if (Token->RestrictedSids && (Token->RestrictedSidCount > 0))
1156  {
1157  AccessToken->RestrictedSidCount = Token->RestrictedSidCount;
1158  AccessToken->RestrictedSids = EndMem;
1159  EndMem = &AccessToken->RestrictedSids[AccessToken->RestrictedSidCount];
1160  VariableLength -= ((ULONG_PTR)EndMem - (ULONG_PTR)AccessToken->RestrictedSids);
1161 
1162  Status = RtlCopySidAndAttributesArray(AccessToken->RestrictedSidCount,
1163  Token->RestrictedSids,
1164  VariableLength,
1165  AccessToken->RestrictedSids,
1166  EndMem,
1167  &EndMem,
1168  &VariableLength);
1169  if (!NT_SUCCESS(Status))
1170  {
1171  DPRINT1("RtlCopySidAndAttributesArray(RestrictedSids) failed (Status 0x%lx)\n", Status);
1172  goto Quit;
1173  }
1174  }
1175 
1176  /*
1177  * Filter the token by removing the disabled privileges
1178  * and groups if the caller wants to duplicate an access
1179  * token as effective only.
1180  */
1181  if (EffectiveOnly)
1182  {
1183  /* Begin querying the groups and search for disabled ones */
1184  for (GroupsIndex = 0; GroupsIndex < AccessToken->UserAndGroupCount; GroupsIndex++)
1185  {
1186  /*
1187  * A group or user is considered disabled if its attributes is either
1188  * 0 or SE_GROUP_ENABLED is not included in the attributes flags list.
1189  * That is because a certain user and/or group can have several attributes
1190  * that bear no influence on whether a user/group is enabled or not
1191  * (SE_GROUP_ENABLED_BY_DEFAULT for example which is a mere indicator
1192  * that the group has just been enabled by default). A mandatory
1193  * group (that is, the group has SE_GROUP_MANDATORY attribute)
1194  * by standards it's always enabled and no one can disable it.
1195  */
1196  if (AccessToken->UserAndGroups[GroupsIndex].Attributes == 0 ||
1197  (AccessToken->UserAndGroups[GroupsIndex].Attributes & SE_GROUP_ENABLED) == 0)
1198  {
1199  /*
1200  * If this group is an administrators group
1201  * and the token belongs to such group,
1202  * we've to take away TOKEN_HAS_ADMIN_GROUP
1203  * for the fact that's not enabled and as
1204  * such the token no longer belongs to
1205  * this group.
1206  */
1208  &AccessToken->UserAndGroups[GroupsIndex].Sid))
1209  {
1210  AccessToken->TokenFlags &= ~TOKEN_HAS_ADMIN_GROUP;
1211  }
1212 
1213  /*
1214  * A group is not enabled, it's time to remove
1215  * from the token and update the groups index
1216  * accordingly and continue with the next group.
1217  */
1218  SepRemoveUserGroupToken(AccessToken, GroupsIndex);
1219  GroupsIndex--;
1220  }
1221  }
1222 
1223  /* Begin querying the privileges and search for disabled ones */
1224  for (PrivilegesIndex = 0; PrivilegesIndex < AccessToken->PrivilegeCount; PrivilegesIndex++)
1225  {
1226  /*
1227  * A privilege is considered disabled if its attributes is either
1228  * 0 or SE_PRIVILEGE_ENABLED is not included in the attributes flags list.
1229  * That is because a certain privilege can have several attributes
1230  * that bear no influence on whether a privilege is enabled or not
1231  * (SE_PRIVILEGE_ENABLED_BY_DEFAULT for example which is a mere indicator
1232  * that the privilege has just been enabled by default).
1233  */
1234  if (AccessToken->Privileges[PrivilegesIndex].Attributes == 0 ||
1235  (AccessToken->Privileges[PrivilegesIndex].Attributes & SE_PRIVILEGE_ENABLED) == 0)
1236  {
1237  /*
1238  * A privilege is not enabled, therefor it's time
1239  * to strip it from the token and continue with the next
1240  * privilege. Of course we must also want to update the
1241  * privileges index accordingly.
1242  */
1243  SepRemovePrivilegeToken(AccessToken, PrivilegesIndex);
1244  PrivilegesIndex--;
1245  }
1246  }
1247  }
1248 
1249  //
1250  // NOTE: So far our dynamic area only contains
1251  // the default dacl, so this makes the following
1252  // code pretty simple. The day where it stores
1253  // other data, the code will require adaptations.
1254  //
1255 
1256  /* Now allocate the TOKEN's dynamic information area and set the data */
1257  AccessToken->DynamicAvailable = 0; // Unused memory in the dynamic area.
1258  AccessToken->DynamicPart = NULL;
1259  if (Token->DynamicPart && Token->DefaultDacl)
1260  {
1261  AccessToken->DynamicPart = ExAllocatePoolWithTag(PagedPool,
1262  Token->DefaultDacl->AclSize,
1264  if (AccessToken->DynamicPart == NULL)
1265  {
1267  goto Quit;
1268  }
1269  EndMem = (PVOID)AccessToken->DynamicPart;
1270 
1271  AccessToken->DefaultDacl = EndMem;
1272 
1273  RtlCopyMemory(AccessToken->DefaultDacl,
1274  Token->DefaultDacl,
1275  Token->DefaultDacl->AclSize);
1276  }
1277 
1278  /* Unlock the source token */
1280 
1281  /* Return the token */
1282  *NewAccessToken = AccessToken;
1284 
1285 Quit:
1286  if (!NT_SUCCESS(Status))
1287  {
1288  /* Unlock the source token */
1290 
1291  /* Dereference the token, the delete procedure will clean it up */
1292  ObDereferenceObject(AccessToken);
1293  }
1294 
1295  return Status;
1296 }
1297 
1319 NTSTATUS
1320 NTAPI
1322  _In_ PTOKEN ParentToken,
1323  _Out_ PTOKEN *Token,
1324  _In_ BOOLEAN InUse,
1326 {
1327  PTOKEN NewToken;
1329  NTSTATUS Status;
1330 
1331  /* Initialize the attributes and duplicate it */
1333  Status = SepDuplicateToken(ParentToken,
1335  FALSE,
1336  TokenPrimary,
1337  ParentToken->ImpersonationLevel,
1338  KernelMode,
1339  &NewToken);
1340  if (NT_SUCCESS(Status))
1341  {
1342  /* Insert it */
1343  Status = ObInsertObject(NewToken,
1344  NULL,
1345  0,
1346  0,
1347  NULL,
1348  NULL);
1349  if (NT_SUCCESS(Status))
1350  {
1351  /* Set the session ID */
1352  NewToken->SessionId = SessionId;
1353  NewToken->TokenInUse = InUse;
1354 
1355  /* Return the token */
1356  *Token = NewToken;
1357  }
1358  }
1359 
1360  /* Return status */
1361  return Status;
1362 }
1363 
1379 NTSTATUS
1380 NTAPI
1382  _In_ PTOKEN Token,
1384 {
1385  PTOKEN ProcessToken;
1386  LUID ProcessTokenId, CallerParentId;
1387 
1388  /* Assume failure */
1389  *IsChild = FALSE;
1390 
1391  /* Reference the process token */
1392  ProcessToken = PsReferencePrimaryToken(PsGetCurrentProcess());
1393  if (!ProcessToken)
1394  return STATUS_UNSUCCESSFUL;
1395 
1396  /* Get its token ID */
1397  ProcessTokenId = ProcessToken->TokenId;
1398 
1399  /* Dereference the token */
1401 
1402  /* Get our parent token ID */
1403  CallerParentId = Token->ParentTokenId;
1404 
1405  /* Compare the token IDs */
1406  if (RtlEqualLuid(&CallerParentId, &ProcessTokenId))
1407  *IsChild = TRUE;
1408 
1409  /* Return success */
1410  return STATUS_SUCCESS;
1411 }
1412 
1428 NTSTATUS
1429 NTAPI
1431  _In_ PTOKEN Token,
1432  _Out_ PBOOLEAN IsSibling)
1433 {
1434  PTOKEN ProcessToken;
1435  LUID ProcessParentId, ProcessAuthId;
1436  LUID CallerParentId, CallerAuthId;
1437 
1438  /* Assume failure */
1439  *IsSibling = FALSE;
1440 
1441  /* Reference the process token */
1442  ProcessToken = PsReferencePrimaryToken(PsGetCurrentProcess());
1443  if (!ProcessToken)
1444  return STATUS_UNSUCCESSFUL;
1445 
1446  /* Get its parent and authentication IDs */
1447  ProcessParentId = ProcessToken->ParentTokenId;
1448  ProcessAuthId = ProcessToken->AuthenticationId;
1449 
1450  /* Dereference the token */
1452 
1453  /* Get our parent and authentication IDs */
1454  CallerParentId = Token->ParentTokenId;
1455  CallerAuthId = Token->AuthenticationId;
1456 
1457  /* Compare the token IDs */
1458  if (RtlEqualLuid(&CallerParentId, &ProcessParentId) &&
1459  RtlEqualLuid(&CallerAuthId, &ProcessAuthId))
1460  {
1461  *IsSibling = TRUE;
1462  }
1463 
1464  /* Return success */
1465  return STATUS_SUCCESS;
1466 }
1467 
1488 NTSTATUS
1489 NTAPI
1494  _Out_ PACCESS_TOKEN* NewToken)
1495 {
1496  NTSTATUS Status;
1498 
1499  PAGED_CODE();
1500 
1502  NULL,
1503  0,
1504  NULL,
1505  NULL);
1506 
1509  FALSE,
1511  Level,
1512  PreviousMode,
1513  (PTOKEN*)NewToken);
1514 
1515  return Status;
1516 }
1517 
1530 VOID
1531 NTAPI
1533  _In_ PVOID ObjectBody)
1534 {
1535  NTSTATUS Status;
1536  PTOKEN AccessToken = (PTOKEN)ObjectBody;
1537 
1538  DPRINT("SepDeleteToken()\n");
1539 
1540  /* Remove the referenced logon session from token */
1541  if (AccessToken->LogonSession)
1542  {
1544  if (!NT_SUCCESS(Status))
1545  {
1546  /* Something seriously went wrong */
1547  DPRINT1("SepDeleteToken(): Failed to remove the logon session from token (Status: 0x%lx)\n", Status);
1548  return;
1549  }
1550  }
1551 
1552  /* Dereference the logon session */
1553  if ((AccessToken->TokenFlags & TOKEN_SESSION_NOT_REFERENCED) == 0)
1555 
1556  /* Delete the token lock */
1557  if (AccessToken->TokenLock)
1558  SepDeleteTokenLock(AccessToken);
1559 
1560  /* Delete the dynamic information area */
1561  if (AccessToken->DynamicPart)
1563 }
1564 
1573 CODE_SEG("INIT")
1574 VOID
1575 NTAPI
1577 {
1579  OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
1580 
1581  DPRINT("Creating Token Object Type\n");
1582 
1583  /* Initialize the Token type */
1584  RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
1585  RtlInitUnicodeString(&Name, L"Token");
1586  ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
1587  ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK;
1588  ObjectTypeInitializer.SecurityRequired = TRUE;
1589  ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(TOKEN);
1590  ObjectTypeInitializer.GenericMapping = SepTokenMapping;
1591  ObjectTypeInitializer.PoolType = PagedPool;
1592  ObjectTypeInitializer.ValidAccessMask = TOKEN_ALL_ACCESS;
1593  ObjectTypeInitializer.UseDefaultObject = TRUE;
1594  ObjectTypeInitializer.DeleteProcedure = SepDeleteToken;
1595  ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &SeTokenObjectType);
1596 }
1597 
1611 VOID
1612 NTAPI
1615  _In_ PTOKEN Token)
1616 {
1617  PAGED_CODE();
1618 
1619  /* Sanity checks */
1620  ASSERT(Token->TokenType == TokenPrimary);
1621  ASSERT(!Token->TokenInUse);
1622 
1623  /* Clean any previous token */
1624  if (Process->Token.Object) SeDeassignPrimaryToken(Process);
1625 
1626  /* Set the new token */
1628  Token->TokenInUse = TRUE;
1630 }
1631 
1706 NTSTATUS
1707 NTAPI
1715  _In_ PLUID AuthenticationId,
1716  _In_ PLARGE_INTEGER ExpirationTime,
1718  _In_ ULONG GroupCount,
1720  _In_ ULONG GroupsLength,
1721  _In_ ULONG PrivilegeCount,
1725  _In_opt_ PACL DefaultDacl,
1727  _In_ BOOLEAN SystemToken)
1728 {
1729  NTSTATUS Status;
1730  PTOKEN AccessToken;
1731  ULONG TokenFlags = 0;
1732  ULONG PrimaryGroupIndex, DefaultOwnerIndex;
1733  LUID TokenId;
1734  LUID ModifiedId;
1735  PVOID EndMem;
1736  ULONG PrivilegesLength;
1737  ULONG UserGroupsLength;
1738  ULONG VariableLength;
1739  ULONG TotalSize;
1740  ULONG i;
1741 
1742  PAGED_CODE();
1743 
1744  /* Loop all groups */
1745  for (i = 0; i < GroupCount; i++)
1746  {
1747  /* Check for mandatory groups */
1749  {
1750  /* Force them to be enabled */
1752  }
1753 
1754  /* Check of the group is an admin group */
1756  {
1757  /* Remember this so we can optimize queries later */
1758  TokenFlags |= TOKEN_HAS_ADMIN_GROUP;
1759  }
1760  }
1761 
1762  /* Allocate unique IDs for the token */
1763  ExAllocateLocallyUniqueId(&TokenId);
1764  ExAllocateLocallyUniqueId(&ModifiedId);
1765 
1766  /* Compute how much size we need to allocate for the token */
1767 
1768  /* Privileges size */
1769  PrivilegesLength = PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
1770  PrivilegesLength = ALIGN_UP_BY(PrivilegesLength, sizeof(PVOID));
1771 
1772  /* User and groups size */
1773  UserGroupsLength = (1 + GroupCount) * sizeof(SID_AND_ATTRIBUTES);
1774  UserGroupsLength += RtlLengthSid(User->Sid);
1775  for (i = 0; i < GroupCount; i++)
1776  {
1777  UserGroupsLength += RtlLengthSid(Groups[i].Sid);
1778  }
1779  UserGroupsLength = ALIGN_UP_BY(UserGroupsLength, sizeof(PVOID));
1780 
1781  /* Add the additional groups array length */
1782  UserGroupsLength += ALIGN_UP_BY(GroupsLength, sizeof(PVOID));
1783 
1784  VariableLength = PrivilegesLength + UserGroupsLength;
1785  TotalSize = FIELD_OFFSET(TOKEN, VariablePart) + VariableLength;
1786 
1790  PreviousMode,
1791  NULL,
1792  TotalSize,
1793  0,
1794  0,
1795  (PVOID*)&AccessToken);
1796  if (!NT_SUCCESS(Status))
1797  {
1798  DPRINT1("ObCreateObject() failed (Status 0x%lx)\n", Status);
1799  return Status;
1800  }
1801 
1802  /* Zero out the buffer and initialize the token */
1803  RtlZeroMemory(AccessToken, TotalSize);
1804 
1805  RtlCopyLuid(&AccessToken->TokenId, &TokenId);
1806 
1807  AccessToken->TokenType = TokenType;
1808  AccessToken->ImpersonationLevel = ImpersonationLevel;
1809 
1810  /* Initialise the lock for the access token */
1811  Status = SepCreateTokenLock(AccessToken);
1812  if (!NT_SUCCESS(Status))
1813  goto Quit;
1814 
1815  RtlCopyLuid(&AccessToken->TokenSource.SourceIdentifier,
1816  &TokenSource->SourceIdentifier);
1817  RtlCopyMemory(AccessToken->TokenSource.SourceName,
1818  TokenSource->SourceName,
1819  sizeof(TokenSource->SourceName));
1820 
1821  AccessToken->ExpirationTime = *ExpirationTime;
1822  RtlCopyLuid(&AccessToken->ModifiedId, &ModifiedId);
1823 
1824  AccessToken->TokenFlags = TokenFlags & ~TOKEN_SESSION_NOT_REFERENCED;
1825 
1826  /* Copy and reference the logon session */
1827  RtlCopyLuid(&AccessToken->AuthenticationId, AuthenticationId);
1828  Status = SepRmReferenceLogonSession(&AccessToken->AuthenticationId);
1829  if (!NT_SUCCESS(Status))
1830  {
1831  /* No logon session could be found, bail out */
1832  DPRINT1("SepRmReferenceLogonSession() failed (Status 0x%lx)\n", Status);
1833  /* Set the flag for proper cleanup by the delete procedure */
1834  AccessToken->TokenFlags |= TOKEN_SESSION_NOT_REFERENCED;
1835  goto Quit;
1836  }
1837 
1838  /* Insert the referenced logon session into the token */
1840  if (!NT_SUCCESS(Status))
1841  {
1842  /* Failed to insert the logon session into the token, bail out */
1843  DPRINT1("SepRmInsertLogonSessionIntoToken() failed (Status 0x%lx)\n", Status);
1844  goto Quit;
1845  }
1846 
1847  /* Assign the data that reside in the TOKEN's variable information area */
1848  AccessToken->VariableLength = VariableLength;
1849  EndMem = (PVOID)&AccessToken->VariablePart;
1850 
1851  /* Copy the privileges */
1852  AccessToken->PrivilegeCount = PrivilegeCount;
1853  AccessToken->Privileges = NULL;
1854  if (PrivilegeCount > 0)
1855  {
1856  AccessToken->Privileges = EndMem;
1857  EndMem = (PVOID)((ULONG_PTR)EndMem + PrivilegesLength);
1858  VariableLength -= PrivilegesLength;
1859 
1860  if (PreviousMode != KernelMode)
1861  {
1862  _SEH2_TRY
1863  {
1864  RtlCopyMemory(AccessToken->Privileges,
1865  Privileges,
1866  PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
1867  }
1869  {
1871  }
1872  _SEH2_END;
1873  }
1874  else
1875  {
1876  RtlCopyMemory(AccessToken->Privileges,
1877  Privileges,
1878  PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
1879  }
1880 
1881  if (!NT_SUCCESS(Status))
1882  goto Quit;
1883  }
1884 
1885  /* Update the privilege flags */
1886  SepUpdatePrivilegeFlagsToken(AccessToken);
1887 
1888  /* Copy the user and groups */
1889  AccessToken->UserAndGroupCount = 1 + GroupCount;
1890  AccessToken->UserAndGroups = EndMem;
1891  EndMem = &AccessToken->UserAndGroups[AccessToken->UserAndGroupCount];
1892  VariableLength -= ((ULONG_PTR)EndMem - (ULONG_PTR)AccessToken->UserAndGroups);
1893 
1895  User,
1896  VariableLength,
1897  &AccessToken->UserAndGroups[0],
1898  EndMem,
1899  &EndMem,
1900  &VariableLength);
1901  if (!NT_SUCCESS(Status))
1902  goto Quit;
1903 
1904  Status = RtlCopySidAndAttributesArray(GroupCount,
1905  Groups,
1906  VariableLength,
1907  &AccessToken->UserAndGroups[1],
1908  EndMem,
1909  &EndMem,
1910  &VariableLength);
1911  if (!NT_SUCCESS(Status))
1912  goto Quit;
1913 
1914  /* Find the token primary group and default owner */
1916  PrimaryGroup,
1917  Owner,
1918  &PrimaryGroupIndex,
1919  &DefaultOwnerIndex);
1920  if (!NT_SUCCESS(Status))
1921  {
1922  DPRINT1("SepFindPrimaryGroupAndDefaultOwner failed (Status 0x%lx)\n", Status);
1923  goto Quit;
1924  }
1925 
1926  AccessToken->PrimaryGroup = AccessToken->UserAndGroups[PrimaryGroupIndex].Sid;
1927  AccessToken->DefaultOwnerIndex = DefaultOwnerIndex;
1928 
1929  /* Now allocate the TOKEN's dynamic information area and set the data */
1930  AccessToken->DynamicAvailable = 0; // Unused memory in the dynamic area.
1931  AccessToken->DynamicPart = NULL;
1932  if (DefaultDacl != NULL)
1933  {
1934  AccessToken->DynamicPart = ExAllocatePoolWithTag(PagedPool,
1935  DefaultDacl->AclSize,
1937  if (AccessToken->DynamicPart == NULL)
1938  {
1940  goto Quit;
1941  }
1942  EndMem = (PVOID)AccessToken->DynamicPart;
1943 
1944  AccessToken->DefaultDacl = EndMem;
1945 
1946  RtlCopyMemory(AccessToken->DefaultDacl,
1947  DefaultDacl,
1948  DefaultDacl->AclSize);
1949  }
1950 
1951  /* Insert the token only if it's not the system token, otherwise return it directly */
1952  if (!SystemToken)
1953  {
1954  Status = ObInsertObject(AccessToken,
1955  NULL,
1956  DesiredAccess,
1957  0,
1958  NULL,
1959  TokenHandle);
1960  if (!NT_SUCCESS(Status))
1961  {
1962  DPRINT1("ObInsertObject() failed (Status 0x%lx)\n", Status);
1963  }
1964  }
1965  else
1966  {
1967  /* Return pointer instead of handle */
1968  *TokenHandle = (HANDLE)AccessToken;
1969  }
1970 
1971 Quit:
1972  if (!NT_SUCCESS(Status))
1973  {
1974  /* Dereference the token, the delete procedure will clean it up */
1975  ObDereferenceObject(AccessToken);
1976  }
1977 
1978  return Status;
1979 }
1980 
2038 static
2039 NTSTATUS
2041  _In_ PTOKEN Token,
2042  _In_opt_ PLUID_AND_ATTRIBUTES PrivilegesToBeDeleted,
2043  _In_opt_ PSID_AND_ATTRIBUTES SidsToBeDisabled,
2044  _In_opt_ PSID_AND_ATTRIBUTES RestrictedSidsIntoToken,
2045  _When_(PrivilegesToBeDeleted != NULL, _In_) ULONG PrivilegesCount,
2046  _When_(SidsToBeDisabled != NULL, _In_) ULONG RegularGroupsSidCount,
2047  _When_(RestrictedSidsIntoToken != NULL, _In_) ULONG RestrictedSidsCount,
2048  _In_ ULONG PrivilegeFlags,
2050  _Out_ PTOKEN *FilteredToken)
2051 {
2052  PTOKEN AccessToken;
2053  NTSTATUS Status;
2054  PVOID EndMem;
2055  ULONG RestrictedSidsLength;
2056  ULONG PrivilegesLength;
2057  ULONG PrimaryGroupIndex;
2058  ULONG RestrictedSidsInList;
2059  ULONG RestrictedSidsInToken;
2060  ULONG VariableLength, TotalSize;
2061  ULONG PrivsInToken, PrivsInList;
2062  ULONG GroupsInToken, GroupsInList;
2063  BOOLEAN WantPrivilegesDisabled;
2064  BOOLEAN FoundPrivilege;
2065  BOOLEAN FoundGroup;
2066  PAGED_CODE();
2067 
2068  /* Ensure that the token we get is not garbage */
2069  ASSERT(Token);
2070 
2071  /* Assume the caller doesn't want privileges disabled */
2072  WantPrivilegesDisabled = FALSE;
2073 
2074  /* Assume we haven't found anything */
2075  FoundPrivilege = FALSE;
2076  FoundGroup = FALSE;
2077 
2078  /*
2079  * Take the size that we need for filtered token
2080  * allocation based upon the existing access token
2081  * we've been given.
2082  */
2083  VariableLength = Token->VariableLength;
2084 
2085  if (RestrictedSidsIntoToken != NULL)
2086  {
2087  /*
2088  * If the caller provided a list of restricted SIDs
2089  * to be added onto the filtered access token then
2090  * we must compute the size which is the total space
2091  * of the current token and the length of the restricted
2092  * SIDs for the filtered token.
2093  */
2094  RestrictedSidsLength = RestrictedSidsCount * sizeof(SID_AND_ATTRIBUTES);
2095  RestrictedSidsLength += RtlLengthSidAndAttributes(RestrictedSidsCount, RestrictedSidsIntoToken);
2096  RestrictedSidsLength = ALIGN_UP_BY(RestrictedSidsLength, sizeof(PVOID));
2097 
2098  /*
2099  * The variable length of the token is not just
2100  * the actual space length of the existing token
2101  * but also the sum of the restricted SIDs length.
2102  */
2103  VariableLength += RestrictedSidsLength;
2104  TotalSize = FIELD_OFFSET(TOKEN, VariablePart) + VariableLength + RestrictedSidsLength;
2105  }
2106  else
2107  {
2108  /* Otherwise the size is of the actual current token */
2109  TotalSize = FIELD_OFFSET(TOKEN, VariablePart) + VariableLength;
2110  }
2111 
2112  /* Set up a filtered token object */
2115  NULL,
2116  PreviousMode,
2117  NULL,
2118  TotalSize,
2119  0,
2120  0,
2121  (PVOID*)&AccessToken);
2122  if (!NT_SUCCESS(Status))
2123  {
2124  DPRINT1("SepPerformTokenFiltering(): Failed to create the filtered token object (Status 0x%lx)\n", Status);
2125  return Status;
2126  }
2127 
2128  /* Initialize the token and begin filling stuff to it */
2129  RtlZeroMemory(AccessToken, TotalSize);
2130 
2131  /* Set up a lock for the new token */
2132  Status = SepCreateTokenLock(AccessToken);
2133  if (!NT_SUCCESS(Status))
2134  {
2135  ObDereferenceObject(AccessToken);
2136  return Status;
2137  }
2138 
2139  /* Allocate new IDs for the token */
2140  ExAllocateLocallyUniqueId(&AccessToken->TokenId);
2141  ExAllocateLocallyUniqueId(&AccessToken->ModifiedId);
2142 
2143  /* Copy the type and impersonation level from the token */
2144  AccessToken->TokenType = Token->TokenType;
2145  AccessToken->ImpersonationLevel = Token->ImpersonationLevel;
2146 
2147  /* Copy the immutable fields */
2148  RtlCopyLuid(&AccessToken->TokenSource.SourceIdentifier,
2149  &Token->TokenSource.SourceIdentifier);
2150  RtlCopyMemory(AccessToken->TokenSource.SourceName,
2151  Token->TokenSource.SourceName,
2152  sizeof(Token->TokenSource.SourceName));
2153 
2154  RtlCopyLuid(&AccessToken->AuthenticationId, &Token->AuthenticationId);
2155  RtlCopyLuid(&AccessToken->ParentTokenId, &Token->TokenId);
2156  RtlCopyLuid(&AccessToken->OriginatingLogonSession,
2157  &Token->OriginatingLogonSession);
2158 
2159  AccessToken->ExpirationTime = Token->ExpirationTime;
2160 
2161  /* Copy the mutable fields */
2162  AccessToken->SessionId = Token->SessionId;
2163  AccessToken->TokenFlags = Token->TokenFlags & ~TOKEN_SESSION_NOT_REFERENCED;
2164 
2165  /* Reference the logon session */
2166  Status = SepRmReferenceLogonSession(&AccessToken->AuthenticationId);
2167  if (!NT_SUCCESS(Status))
2168  {
2169  /* We failed, bail out*/
2170  DPRINT1("SepPerformTokenFiltering(): Failed to reference the logon session (Status 0x%lx)\n", Status);
2171  AccessToken->TokenFlags |= TOKEN_SESSION_NOT_REFERENCED;
2172  goto Quit;
2173  }
2174 
2175  /* Insert the referenced logon session into the token */
2177  if (!NT_SUCCESS(Status))
2178  {
2179  /* Failed to insert the logon session into the token, bail out */
2180  DPRINT1("SepPerformTokenFiltering(): Failed to insert the logon session into token (Status 0x%lx)\n", Status);
2181  goto Quit;
2182  }
2183 
2184  /* Assign the data that reside in the token's variable information area */
2185  AccessToken->VariableLength = VariableLength;
2186  EndMem = (PVOID)&AccessToken->VariablePart;
2187 
2188  /* Copy the privileges from the existing token */
2189  AccessToken->PrivilegeCount = 0;
2190  AccessToken->Privileges = NULL;
2191  if (Token->Privileges && (Token->PrivilegeCount > 0))
2192  {
2193  PrivilegesLength = Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
2194  PrivilegesLength = ALIGN_UP_BY(PrivilegesLength, sizeof(PVOID));
2195 
2196  /*
2197  * Ensure that the token can actually hold all
2198  * the privileges from the existing token.
2199  * Otherwise something's seriously wrong and
2200  * we've to guard ourselves.
2201  */
2202  ASSERT(VariableLength >= PrivilegesLength);
2203 
2204  AccessToken->PrivilegeCount = Token->PrivilegeCount;
2205  AccessToken->Privileges = EndMem;
2206  EndMem = (PVOID)((ULONG_PTR)EndMem + PrivilegesLength);
2207  VariableLength -= PrivilegesLength;
2208 
2209  if (PreviousMode != KernelMode)
2210  {
2211  _SEH2_TRY
2212  {
2213  RtlCopyMemory(AccessToken->Privileges,
2214  Token->Privileges,
2215  AccessToken->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
2216  }
2218  {
2220  _SEH2_YIELD(goto Quit);
2221  }
2222  _SEH2_END;
2223  }
2224  else
2225  {
2226  RtlCopyMemory(AccessToken->Privileges,
2227  Token->Privileges,
2228  AccessToken->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
2229  }
2230  }
2231 
2232  /* Copy the user and groups */
2233  AccessToken->UserAndGroupCount = 0;
2234  AccessToken->UserAndGroups = NULL;
2235  if (Token->UserAndGroups && (Token->UserAndGroupCount > 0))
2236  {
2237  AccessToken->UserAndGroupCount = Token->UserAndGroupCount;
2238  AccessToken->UserAndGroups = EndMem;
2239  EndMem = &AccessToken->UserAndGroups[AccessToken->UserAndGroupCount];
2240  VariableLength -= ((ULONG_PTR)EndMem - (ULONG_PTR)AccessToken->UserAndGroups);
2241 
2242  if (PreviousMode != KernelMode)
2243  {
2244  _SEH2_TRY
2245  {
2246  Status = RtlCopySidAndAttributesArray(AccessToken->UserAndGroupCount,
2247  Token->UserAndGroups,
2248  VariableLength,
2249  AccessToken->UserAndGroups,
2250  EndMem,
2251  &EndMem,
2252  &VariableLength);
2253  }
2255  {
2257  _SEH2_YIELD(goto Quit);
2258  }
2259  _SEH2_END;
2260  }
2261  else
2262  {
2263  Status = RtlCopySidAndAttributesArray(AccessToken->UserAndGroupCount,
2264  Token->UserAndGroups,
2265  VariableLength,
2266  AccessToken->UserAndGroups,
2267  EndMem,
2268  &EndMem,
2269  &VariableLength);
2270  if (!NT_SUCCESS(Status))
2271  {
2272  DPRINT1("SepPerformTokenFiltering(): Failed to copy the groups into token (Status 0x%lx)\n", Status);
2273  goto Quit;
2274  }
2275  }
2276  }
2277 
2278  /* Copy the restricted SIDs */
2279  AccessToken->RestrictedSidCount = 0;
2280  AccessToken->RestrictedSids = NULL;
2281  if (Token->RestrictedSids && (Token->RestrictedSidCount > 0))
2282  {
2283  AccessToken->RestrictedSidCount = Token->RestrictedSidCount;
2284  AccessToken->RestrictedSids = EndMem;
2285  EndMem = &AccessToken->RestrictedSids[AccessToken->RestrictedSidCount];
2286  VariableLength -= ((ULONG_PTR)EndMem - (ULONG_PTR)AccessToken->RestrictedSids);
2287 
2288  if (PreviousMode != KernelMode)
2289  {
2290  _SEH2_TRY
2291  {
2292  Status = RtlCopySidAndAttributesArray(AccessToken->RestrictedSidCount,
2293  Token->RestrictedSids,
2294  VariableLength,
2295  AccessToken->RestrictedSids,
2296  EndMem,
2297  &EndMem,
2298  &VariableLength);
2299  }
2301  {
2303  _SEH2_YIELD(goto Quit);
2304  }
2305  _SEH2_END;
2306  }
2307  else
2308  {
2309  Status = RtlCopySidAndAttributesArray(AccessToken->RestrictedSidCount,
2310  Token->RestrictedSids,
2311  VariableLength,
2312  AccessToken->RestrictedSids,
2313  EndMem,
2314  &EndMem,
2315  &VariableLength);
2316  if (!NT_SUCCESS(Status))
2317  {
2318  DPRINT1("SepPerformTokenFiltering(): Failed to copy the restricted SIDs into token (Status 0x%lx)\n", Status);
2319  goto Quit;
2320  }
2321  }
2322  }
2323 
2324  /* Search for the primary group */
2326  Token->PrimaryGroup,
2327  NULL,
2328  &PrimaryGroupIndex,
2329  NULL);
2330  if (!NT_SUCCESS(Status))
2331  {
2332  DPRINT1("SepPerformTokenFiltering(): Failed searching for the primary group (Status 0x%lx)\n", Status);
2333  goto Quit;
2334  }
2335 
2336  /* Assign the primary group and default owner index now */
2337  AccessToken->PrimaryGroup = AccessToken->UserAndGroups[PrimaryGroupIndex].Sid;
2338  AccessToken->DefaultOwnerIndex = Token->DefaultOwnerIndex;
2339 
2340  /* Now allocate the token's dynamic information area and set the data */
2341  AccessToken->DynamicAvailable = 0;
2342  AccessToken->DynamicPart = NULL;
2343  if (Token->DynamicPart && Token->DefaultDacl)
2344  {
2345  AccessToken->DynamicPart = ExAllocatePoolWithTag(PagedPool,
2346  Token->DefaultDacl->AclSize,
2348  if (AccessToken->DynamicPart == NULL)
2349  {
2351  goto Quit;
2352  }
2353 
2354  EndMem = (PVOID)AccessToken->DynamicPart;
2355  AccessToken->DefaultDacl = EndMem;
2356 
2357  RtlCopyMemory(AccessToken->DefaultDacl,
2358  Token->DefaultDacl,
2359  Token->DefaultDacl->AclSize);
2360  }
2361 
2362  /*
2363  * Now figure out what does the caller
2364  * want with the privileges.
2365  */
2366  if (PrivilegeFlags & DISABLE_MAX_PRIVILEGE)
2367  {
2368  /*
2369  * The caller wants them disabled, cache this request
2370  * for later operations.
2371  */
2372  WantPrivilegesDisabled = TRUE;
2373  }
2374 
2375  if (PrivilegeFlags & SANDBOX_INERT)
2376  {
2377  /* The caller wants an inert token, store the TOKEN_SANDBOX_INERT flag now */
2378  AccessToken->TokenFlags |= TOKEN_SANDBOX_INERT;
2379  }
2380 
2381  /*
2382  * Now it's time to filter the token's privileges.
2383  * Loop all the privileges in the token.
2384  */
2385  for (PrivsInToken = 0; PrivsInToken < AccessToken->PrivilegeCount; PrivsInToken++)
2386  {
2387  if (WantPrivilegesDisabled)
2388  {
2389  /*
2390  * We got the acknowledgement that the caller wants
2391  * to disable all the privileges so let's just do it.
2392  * However, as per the general documentation is stated
2393  * that only SE_CHANGE_NOTIFY_PRIVILEGE must be kept
2394  * therefore in that case we must skip this privilege.
2395  */
2396  if (AccessToken->Privileges[PrivsInToken].Luid.LowPart == SE_CHANGE_NOTIFY_PRIVILEGE)
2397  {
2398  continue;
2399  }
2400  else
2401  {
2402  /*
2403  * The act of disabling privileges actually means
2404  * "deleting" them from the access token entirely.
2405  * First we must disable them so that we can update
2406  * token flags accordingly.
2407  */
2408  AccessToken->Privileges[PrivsInToken].Attributes &= ~SE_PRIVILEGE_ENABLED;
2409  SepUpdateSinglePrivilegeFlagToken(AccessToken, PrivsInToken);
2410 
2411  /* Remove the privileges now */
2412  SepRemovePrivilegeToken(AccessToken, PrivsInToken);
2413  PrivsInToken--;
2414  }
2415  }
2416  else
2417  {
2418  if (PrivilegesToBeDeleted != NULL)
2419  {
2420  /* Loop the privileges we've got to delete */
2421  for (PrivsInList = 0; PrivsInList < PrivilegesCount; PrivsInList++)
2422  {
2423  /* Does this privilege exist in the token? */
2424  if (RtlEqualLuid(&AccessToken->Privileges[PrivsInToken].Luid,
2425  &PrivilegesToBeDeleted[PrivsInList].Luid))
2426  {
2427  /* Mark that we found it */
2428  FoundPrivilege = TRUE;
2429  break;
2430  }
2431  }
2432 
2433  /* Did we find the privilege? */
2434  if (PrivsInList == PrivilegesCount)
2435  {
2436  /* We didn't, continue with next one */
2437  continue;
2438  }
2439  }
2440  }
2441 
2442  /*
2443  * If we have found the target privilege in the token
2444  * based on the privileges list given by the caller
2445  * then begin deleting it.
2446  */
2447  if (FoundPrivilege)
2448  {
2449  /* Disable the privilege and update the flags */
2450  AccessToken->Privileges[PrivsInToken].Attributes &= ~SE_PRIVILEGE_ENABLED;
2451  SepUpdateSinglePrivilegeFlagToken(AccessToken, PrivsInToken);
2452 
2453  /* Delete the privilege */
2454  SepRemovePrivilegeToken(AccessToken, PrivsInToken);
2455 
2456  /*
2457  * Adjust the index and reset the FoundPrivilege indicator
2458  * so that we can continue with the next privilege to delete.
2459  */
2460  PrivsInToken--;
2461  FoundPrivilege = FALSE;
2462  continue;
2463  }
2464  }
2465 
2466  /*
2467  * Loop the group SIDs that we want to disable as
2468  * per on the request by the caller.
2469  */
2470  if (SidsToBeDisabled != NULL)
2471  {
2472  for (GroupsInToken = 0; GroupsInToken < AccessToken->UserAndGroupCount; GroupsInToken++)
2473  {
2474  for (GroupsInList = 0; GroupsInList < RegularGroupsSidCount; GroupsInList++)
2475  {
2476  /* Does this group SID exist in the token? */
2477  if (RtlEqualSid(&AccessToken->UserAndGroups[GroupsInToken].Sid,
2478  &SidsToBeDisabled[GroupsInList].Sid))
2479  {
2480  /* Mark that we found it */
2481  FoundGroup = TRUE;
2482  break;
2483  }
2484  }
2485 
2486  /* Did we find the group? */
2487  if (GroupsInList == RegularGroupsSidCount)
2488  {
2489  /* We didn't, continue with next one */
2490  continue;
2491  }
2492 
2493  /* If we have found the group, disable it */
2494  if (FoundGroup)
2495  {
2496  /*
2497  * If the acess token belongs to the administrators
2498  * group and this is the target group, we must take
2499  * away TOKEN_HAS_ADMIN_GROUP flag from the token.
2500  */
2502  &AccessToken->UserAndGroups[GroupsInToken].Sid))
2503  {
2504  AccessToken->TokenFlags &= ~TOKEN_HAS_ADMIN_GROUP;
2505  }
2506 
2507  /*
2508  * If the target group that we have found it is the
2509  * owner then from now on it no longer is but the user.
2510  * Therefore assign the default owner index as the user.
2511  */
2512  if (AccessToken->DefaultOwnerIndex == GroupsInToken)
2513  {
2514  AccessToken->DefaultOwnerIndex = 0;
2515  }
2516 
2517  /*
2518  * The principle of disabling a group SID is by
2519  * taking away SE_GROUP_ENABLED_BY_DEFAULT and
2520  * SE_GROUP_ENABLED attributes and assign
2521  * SE_GROUP_USE_FOR_DENY_ONLY. This renders
2522  * SID a "Deny only" SID.
2523  */
2524  AccessToken->UserAndGroups[GroupsInToken].Attributes &= ~(SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT);
2525  AccessToken->UserAndGroups[GroupsInToken].Attributes |= SE_GROUP_USE_FOR_DENY_ONLY;
2526 
2527  /* Adjust the index and continue with the next group */
2528  GroupsInToken--;
2529  FoundGroup = FALSE;
2530  continue;
2531  }
2532  }
2533  }
2534 
2535  /*
2536  * Insert the restricted SIDs into the token on
2537  * the request by the caller.
2538  */
2539  if (RestrictedSidsIntoToken != NULL)
2540  {
2541  for (RestrictedSidsInList = 0; RestrictedSidsInList < RestrictedSidsCount; RestrictedSidsInList++)
2542  {
2543  /* Did the caller assign attributes to the restricted SIDs? */
2544  if (RestrictedSidsIntoToken[RestrictedSidsInList].Attributes != 0)
2545  {
2546  /* There mustn't be any attributes, bail out */
2547  DPRINT1("SepPerformTokenFiltering(): There mustn't be any attributes to restricted SIDs!\n");
2549  goto Quit;
2550  }
2551  }
2552 
2553  /*
2554  * Ensure that the token can hold the restricted SIDs
2555  * (the variable length is calculated at the beginning
2556  * of the routine call).
2557  */
2558  ASSERT(VariableLength >= RestrictedSidsLength);
2559 
2560  /*
2561  * Now let's begin inserting the restricted SIDs into the filtered
2562  * access token from the list the caller gave us.
2563  */
2564  AccessToken->RestrictedSidCount = RestrictedSidsCount;
2565  AccessToken->RestrictedSids = EndMem;
2566  EndMem = (PVOID)((ULONG_PTR)EndMem + RestrictedSidsLength);
2567  VariableLength -= RestrictedSidsLength;
2568 
2569  if (PreviousMode != KernelMode)
2570  {
2571  _SEH2_TRY
2572  {
2573  RtlCopyMemory(AccessToken->RestrictedSids,
2574  RestrictedSidsIntoToken,
2575  AccessToken->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES));
2576  }
2578  {
2580  _SEH2_YIELD(goto Quit);
2581  }
2582  _SEH2_END;
2583  }
2584  else
2585  {
2586  RtlCopyMemory(AccessToken->RestrictedSids,
2587  RestrictedSidsIntoToken,
2588  AccessToken->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES));
2589  }
2590 
2591  /*
2592  * As we've copied the restricted SIDs into
2593  * the token, we must assign them the following
2594  * combination of attributes SE_GROUP_ENABLED,
2595  * SE_GROUP_ENABLED_BY_DEFAULT and SE_GROUP_MANDATORY.
2596  * With such attributes we estabilish that restricting
2597  * SIDs into the token are enabled for access checks.
2598  */
2599  for (RestrictedSidsInToken = 0; RestrictedSidsInToken < AccessToken->RestrictedSidCount; RestrictedSidsInToken++)
2600  {
2601  AccessToken->RestrictedSids[RestrictedSidsInToken].Attributes |= (SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_MANDATORY);
2602  }
2603 
2604  /*
2605  * As we added restricted SIDs into the token, mark
2606  * it as restricted.
2607  */
2608  AccessToken->TokenFlags |= TOKEN_IS_RESTRICTED;
2609  }
2610 
2611  /* We've finally filtered the token, give it to the caller */
2612  *FilteredToken = AccessToken;
2614  DPRINT("SepPerformTokenFiltering(): The token has been filtered!\n");
2615 
2616 Quit:
2617  if (!NT_SUCCESS(Status))
2618  {
2619  /* Dereference the token */
2620  ObDereferenceObject(AccessToken);
2621  }
2622 
2623  return Status;
2624 }
2625 
2634 CODE_SEG("INIT")
2635 PTOKEN
2636 NTAPI
2638 {
2640  ULONG GroupAttributes, OwnerAttributes;
2642  LARGE_INTEGER Expiration;
2643  SID_AND_ATTRIBUTES UserSid;
2644  ULONG GroupsLength;
2647  PSID Owner;
2648  ULONG i;
2649  PTOKEN Token;
2650  NTSTATUS Status;
2651 
2652  /* Don't ever expire */
2653  Expiration.QuadPart = -1;
2654 
2655  /* All groups mandatory and enabled */
2658 
2659  /* User is Local System */
2660  UserSid.Sid = SeLocalSystemSid;
2661  UserSid.Attributes = 0;
2662 
2663  /* Primary group is Local System */
2665 
2666  /* Owner is Administrators */
2668 
2669  /* Groups are Administrators, World, and Authenticated Users */
2670  Groups[0].Sid = SeAliasAdminsSid;
2671  Groups[0].Attributes = OwnerAttributes;
2672  Groups[1].Sid = SeWorldSid;
2673  Groups[1].Attributes = GroupAttributes;
2675  Groups[2].Attributes = GroupAttributes;
2676  GroupsLength = sizeof(SID_AND_ATTRIBUTES) +
2677  SeLengthSid(Groups[0].Sid) +
2678  SeLengthSid(Groups[1].Sid) +
2679  SeLengthSid(Groups[2].Sid);
2680  ASSERT(GroupsLength <= sizeof(Groups));
2681 
2682  /* Setup the privileges */
2683  i = 0;
2685  Privileges[i++].Luid = SeTcbPrivilege;
2686 
2687  Privileges[i].Attributes = 0;
2689 
2690  Privileges[i].Attributes = 0;
2692 
2695 
2698 
2699  Privileges[i].Attributes = 0;
2701 
2702  Privileges[i].Attributes = 0;
2704 
2707 
2710 
2712  Privileges[i++].Luid = SeDebugPrivilege;
2713 
2715  Privileges[i++].Luid = SeAuditPrivilege;
2716 
2717  Privileges[i].Attributes = 0;
2718  Privileges[i++].Luid = SeSecurityPrivilege;
2719 
2720  Privileges[i].Attributes = 0;
2722 
2725 
2726  Privileges[i].Attributes = 0;
2727  Privileges[i++].Luid = SeBackupPrivilege;
2728 
2729  Privileges[i].Attributes = 0;
2730  Privileges[i++].Luid = SeRestorePrivilege;
2731 
2732  Privileges[i].Attributes = 0;
2733  Privileges[i++].Luid = SeShutdownPrivilege;
2734 
2735  Privileges[i].Attributes = 0;
2737 
2740 
2741  Privileges[i].Attributes = 0;
2743  ASSERT(i == 20);
2744 
2745  /* Setup the object attributes */
2748 
2749  /* Create the token */
2751  KernelMode,
2752  0,
2754  TokenPrimary,
2757  &Expiration,
2758  &UserSid,
2759  3,
2760  Groups,
2761  GroupsLength,
2762  20,
2763  Privileges,
2764  Owner,
2765  PrimaryGroup,
2768  TRUE);
2770 
2771  /* Return the token */
2772  return Token;
2773 }
2774 
2785 CODE_SEG("INIT")
2786 PTOKEN
2788 {
2789  SID_AND_ATTRIBUTES Groups[32], UserSid;
2791  PTOKEN Token;
2792  ULONG GroupsLength;
2793  LARGE_INTEGER Expiration;
2795  NTSTATUS Status;
2796 
2797  /* The token never expires */
2798  Expiration.QuadPart = -1;
2799 
2800  /* The user is the anonymous logon */
2801  UserSid.Sid = SeAnonymousLogonSid;
2802  UserSid.Attributes = 0;
2803 
2804  /* The primary group is also the anonymous logon */
2806 
2807  /* The only group for the token is the World */
2808  Groups[0].Sid = SeWorldSid;
2810  GroupsLength = sizeof(SID_AND_ATTRIBUTES) +
2811  SeLengthSid(Groups[0].Sid);
2812  ASSERT(GroupsLength <= sizeof(Groups));
2813 
2814  /* Initialise the object attributes for the token */
2817 
2818  /* Create token */
2820  KernelMode,
2821  0,
2823  TokenPrimary,
2826  &Expiration,
2827  &UserSid,
2828  1,
2829  Groups,
2830  GroupsLength,
2831  0,
2832  NULL,
2833  NULL,
2834  PrimaryGroup,
2837  TRUE);
2839 
2840  /* Return the anonymous logon token */
2841  return Token;
2842 }
2843 
2853 CODE_SEG("INIT")
2854 PTOKEN
2856 {
2857  SID_AND_ATTRIBUTES UserSid;
2859  PTOKEN Token;
2860  LARGE_INTEGER Expiration;
2862  NTSTATUS Status;
2863 
2864  /* The token never expires */
2865  Expiration.QuadPart = -1;
2866 
2867  /* The user is the anonymous logon */
2868  UserSid.Sid = SeAnonymousLogonSid;
2869  UserSid.Attributes = 0;
2870 
2871  /* The primary group is also the anonymous logon */
2873 
2874  /* Initialise the object attributes for the token */
2877 
2878  /* Create token */
2880  KernelMode,
2881  0,
2883  TokenPrimary,
2886  &Expiration,
2887  &UserSid,
2888  0,
2889  NULL,
2890  0,
2891  0,
2892  NULL,
2893  NULL,
2894  PrimaryGroup,
2897  TRUE);
2899 
2900  /* Return the anonymous (not including everyone) logon token */
2901  return Token;
2902 }
2903 
2904 /* PUBLIC FUNCTIONS ***********************************************************/
2905 
2945 NTSTATUS
2946 NTAPI
2948  _In_ PACCESS_TOKEN ExistingToken,
2949  _In_ ULONG Flags,
2950  _In_opt_ PTOKEN_GROUPS SidsToDisable,
2951  _In_opt_ PTOKEN_PRIVILEGES PrivilegesToDelete,
2952  _In_opt_ PTOKEN_GROUPS RestrictedSids,
2953  _Out_ PACCESS_TOKEN *FilteredToken)
2954 {
2955  NTSTATUS Status;
2956  PTOKEN AccessToken;
2957  ULONG PrivilegesCount = 0;
2958  ULONG SidsCount = 0;
2959  ULONG RestrictedSidsCount = 0;
2960  PAGED_CODE();
2961 
2962  /* Begin copying the counters */
2963  if (SidsToDisable != NULL)
2964  {
2965  SidsCount = SidsToDisable->GroupCount;
2966  }
2967 
2968  if (PrivilegesToDelete != NULL)
2969  {
2970  PrivilegesCount = PrivilegesToDelete->PrivilegeCount;
2971  }
2972 
2973  if (RestrictedSids != NULL)
2974  {
2975  RestrictedSidsCount = RestrictedSids->GroupCount;
2976  }
2977 
2978  /* Call the internal API */
2979  Status = SepPerformTokenFiltering(ExistingToken,
2980  PrivilegesToDelete->Privileges,
2981  SidsToDisable->Groups,
2982  RestrictedSids->Groups,
2983  PrivilegesCount,
2984  SidsCount,
2985  RestrictedSidsCount,
2986  Flags,
2987  KernelMode,
2988  &AccessToken);
2989  if (!NT_SUCCESS(Status))
2990  {
2991  DPRINT1("SeFilterToken(): Failed to filter the token (Status 0x%lx)\n", Status);
2992  return Status;
2993  }
2994 
2995  /* Insert the filtered token */
2996  Status = ObInsertObject(AccessToken,
2997  NULL,
2998  0,
2999  0,
3000  NULL,
3001  NULL);
3002  if (!NT_SUCCESS(Status))
3003  {
3004  DPRINT1("SeFilterToken(): Failed to insert the token (Status 0x%lx)\n", Status);
3005  return Status;
3006  }
3007 
3008  /* Give it to the caller */
3009  *FilteredToken = AccessToken;
3010  return Status;
3011 }
3012 
3044 NTSTATUS
3045 NTAPI
3047  _In_ PACCESS_TOKEN AccessToken,
3049  _Outptr_result_buffer_(_Inexpressible_(token-dependent)) PVOID *TokenInformation)
3050 {
3051  NTSTATUS Status;
3052  PTOKEN Token = (PTOKEN)AccessToken;
3054  union
3055  {
3056  PSID PSid;
3057  ULONG Ulong;
3058  } Unused;
3059 
3060  PAGED_CODE();
3061 
3062  /* Lock the token */
3064 
3065  switch (TokenInformationClass)
3066  {
3067  case TokenUser:
3068  {
3069  PTOKEN_USER tu;
3070 
3071  DPRINT("SeQueryInformationToken(TokenUser)\n");
3072  RequiredLength = sizeof(TOKEN_USER) +
3073  RtlLengthSid(Token->UserAndGroups[0].Sid);
3074 
3075  /* Allocate the output buffer */
3077  if (tu == NULL)
3078  {
3080  break;
3081  }
3082 
3084  &Token->UserAndGroups[0],
3085  RequiredLength - sizeof(TOKEN_USER),
3086  &tu->User,
3087  (PSID)(tu + 1),
3088  &Unused.PSid,
3089  &Unused.Ulong);
3090 
3091  /* Return the structure */
3092  *TokenInformation = tu;
3094  break;
3095  }
3096 
3097  case TokenGroups:
3098  {
3099  PTOKEN_GROUPS tg;
3100  ULONG SidLen;
3101  PSID Sid;
3102 
3103  DPRINT("SeQueryInformationToken(TokenGroups)\n");
3104  RequiredLength = sizeof(tg->GroupCount) +
3105  RtlLengthSidAndAttributes(Token->UserAndGroupCount - 1, &Token->UserAndGroups[1]);
3106 
3107  SidLen = RequiredLength - sizeof(tg->GroupCount) -
3108  ((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES));
3109 
3110  /* Allocate the output buffer */
3112  if (tg == NULL)
3113  {
3115  break;
3116  }
3117 
3118  Sid = (PSID)((ULONG_PTR)tg + sizeof(tg->GroupCount) +
3119  ((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES)));
3120 
3121  tg->GroupCount = Token->UserAndGroupCount - 1;
3122  Status = RtlCopySidAndAttributesArray(Token->UserAndGroupCount - 1,
3123  &Token->UserAndGroups[1],
3124  SidLen,
3125  &tg->Groups[0],
3126  Sid,
3127  &Unused.PSid,
3128  &Unused.Ulong);
3129 
3130  /* Return the structure */
3131  *TokenInformation = tg;
3133  break;
3134  }
3135 
3136  case TokenPrivileges:
3137  {
3139 
3140  DPRINT("SeQueryInformationToken(TokenPrivileges)\n");
3141  RequiredLength = sizeof(tp->PrivilegeCount) +
3142  (Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
3143 
3144  /* Allocate the output buffer */
3146  if (tp == NULL)
3147  {
3149  break;
3150  }
3151 
3152  tp->PrivilegeCount = Token->PrivilegeCount;
3153  RtlCopyLuidAndAttributesArray(Token->PrivilegeCount,
3154  Token->Privileges,
3155  &tp->Privileges[0]);
3156 
3157  /* Return the structure */
3158  *TokenInformation = tp;
3160  break;
3161  }
3162 
3163  case TokenOwner:
3164  {
3165  PTOKEN_OWNER to;
3166  ULONG SidLen;
3167 
3168  DPRINT("SeQueryInformationToken(TokenOwner)\n");
3169  SidLen = RtlLengthSid(Token->UserAndGroups[Token->DefaultOwnerIndex].Sid);
3170  RequiredLength = sizeof(TOKEN_OWNER) + SidLen;
3171 
3172  /* Allocate the output buffer */
3174  if (to == NULL)
3175  {
3177  break;
3178  }
3179 
3180  to->Owner = (PSID)(to + 1);
3181  Status = RtlCopySid(SidLen,
3182  to->Owner,
3183  Token->UserAndGroups[Token->DefaultOwnerIndex].Sid);
3184 
3185  /* Return the structure */
3186  *TokenInformation = to;
3188  break;
3189  }
3190 
3191  case TokenPrimaryGroup:
3192  {
3194  ULONG SidLen;
3195 
3196  DPRINT("SeQueryInformationToken(TokenPrimaryGroup)\n");
3197  SidLen = RtlLengthSid(Token->PrimaryGroup);
3198  RequiredLength = sizeof(TOKEN_PRIMARY_GROUP) + SidLen;
3199 
3200  /* Allocate the output buffer */
3202  if (tpg == NULL)
3203  {
3205  break;
3206  }
3207 
3208  tpg->PrimaryGroup = (PSID)(tpg + 1);
3209  Status = RtlCopySid(SidLen,
3210  tpg->PrimaryGroup,
3211  Token->PrimaryGroup);
3212 
3213  /* Return the structure */
3214  *TokenInformation = tpg;
3216  break;
3217  }
3218 
3219  case TokenDefaultDacl:
3220  {
3221  PTOKEN_DEFAULT_DACL tdd;
3222 
3223  DPRINT("SeQueryInformationToken(TokenDefaultDacl)\n");
3225 
3226  if (Token->DefaultDacl != NULL)
3227  RequiredLength += Token->DefaultDacl->AclSize;
3228 
3229  /* Allocate the output buffer */
3231  if (tdd == NULL)
3232  {
3234  break;
3235  }
3236 
3237  if (Token->DefaultDacl != NULL)
3238  {
3239  tdd->DefaultDacl = (PACL)(tdd + 1);
3241  Token->DefaultDacl,
3242  Token->DefaultDacl->AclSize);
3243  }
3244  else
3245  {
3246  tdd->DefaultDacl = NULL;
3247  }
3248 
3249  /* Return the structure */
3250  *TokenInformation = tdd;
3252  break;
3253  }
3254 
3255  case TokenSource:
3256  {
3257  PTOKEN_SOURCE ts;
3258 
3259  DPRINT("SeQueryInformationToken(TokenSource)\n");
3260  RequiredLength = sizeof(TOKEN_SOURCE);
3261 
3262  /* Allocate the output buffer */
3264  if (ts == NULL)
3265  {
3267  break;
3268  }
3269 
3270  *ts = Token->TokenSource;
3271 
3272  /* Return the structure */
3273  *TokenInformation = ts;
3275  break;
3276  }
3277 
3278  case TokenType:
3279  {
3280  PTOKEN_TYPE tt;
3281 
3282  DPRINT("SeQueryInformationToken(TokenType)\n");
3283  RequiredLength = sizeof(TOKEN_TYPE);
3284 
3285  /* Allocate the output buffer */
3287  if (tt == NULL)
3288  {
3290  break;
3291  }
3292 
3293  *tt = Token->TokenType;
3294 
3295  /* Return the structure */
3296  *TokenInformation = tt;
3298  break;
3299  }
3300 
3302  {
3304 
3305  DPRINT("SeQueryInformationToken(TokenImpersonationLevel)\n");
3307 
3308  /* Fail if the token is not an impersonation token */
3309  if (Token->TokenType != TokenImpersonation)
3310  {
3312  break;
3313  }
3314 
3315  /* Allocate the output buffer */
3317  if (sil == NULL)
3318  {
3320  break;
3321  }
3322 
3323  *sil = Token->ImpersonationLevel;
3324 
3325  /* Return the structure */
3326  *TokenInformation = sil;
3328  break;
3329  }
3330 
3331  case TokenStatistics:
3332  {
3333  PTOKEN_STATISTICS ts;
3334 
3335  DPRINT("SeQueryInformationToken(TokenStatistics)\n");
3336  RequiredLength = sizeof(TOKEN_STATISTICS);
3337 
3338  /* Allocate the output buffer */
3340  if (ts == NULL)
3341  {
3343  break;
3344  }
3345 
3346  ts->TokenId = Token->TokenId;
3347  ts->AuthenticationId = Token->AuthenticationId;
3348  ts->ExpirationTime = Token->ExpirationTime;
3349  ts->TokenType = Token->TokenType;
3350  ts->ImpersonationLevel = Token->ImpersonationLevel;
3351  ts->DynamicCharged = Token->DynamicCharged;
3352  ts->DynamicAvailable = Token->DynamicAvailable;
3353  ts->GroupCount = Token->UserAndGroupCount - 1;
3354  ts->PrivilegeCount = Token->PrivilegeCount;
3355  ts->ModifiedId = Token->ModifiedId;
3356 
3357  /* Return the structure */
3358  *TokenInformation = ts;
3360  break;
3361  }
3362 
3363  case TokenSessionId:
3364  {
3365  DPRINT("SeQueryInformationToken(TokenSessionId)\n");
3366  Status = SeQuerySessionIdToken(Token, (PULONG)TokenInformation);
3367  break;
3368  }
3369 
3370  default:
3371  DPRINT1("SeQueryInformationToken(%d) invalid information class\n", TokenInformationClass);
3373  break;
3374  }
3375 
3376  /* Release the lock of the token */
3378 
3379  return Status;
3380 }
3381 
3395 NTSTATUS
3396 NTAPI
3399  _Out_ PULONG pSessionId)
3400 {
3401  PAGED_CODE();
3402 
3403  /* Lock the token */
3405 
3406  *pSessionId = ((PTOKEN)Token)->SessionId;
3407 
3408  /* Unlock the token */
3410 
3411  return STATUS_SUCCESS;
3412 }
3413 
3427 NTSTATUS
3428 NTAPI
3432 {
3433  PAGED_CODE();
3434 
3435  *LogonId = ((PTOKEN)Token)->AuthenticationId;
3436 
3437  return STATUS_SUCCESS;
3438 }
3439 
3451 NTAPI
3454 {
3455  PAGED_CODE();
3456 
3457  return ((PTOKEN)Token)->ImpersonationLevel;
3458 }
3459 
3471 TOKEN_TYPE
3472 NTAPI
3475 {
3476  PAGED_CODE();
3477 
3478  return ((PTOKEN)Token)->TokenType;
3479 }
3480 
3494 BOOLEAN
3495 NTAPI
3498 {
3499  PAGED_CODE();
3500 
3501  // NOTE: Win7+ instead really checks the list of groups in the token
3502  // (since TOKEN_HAS_ADMIN_GROUP == TOKEN_WRITE_RESTRICTED ...)
3503  return (((PTOKEN)Token)->TokenFlags & TOKEN_HAS_ADMIN_GROUP) != 0;
3504 }
3505 
3517 BOOLEAN
3518 NTAPI
3521 {
3522  PAGED_CODE();
3523 
3524  return (((PTOKEN)Token)->TokenFlags & TOKEN_IS_RESTRICTED) != 0;
3525 }
3526 
3542 BOOLEAN
3543 NTAPI
3546 {
3547  PAGED_CODE();
3548 
3549  // NOTE: NT 5.1 SP2 x86 checks the SE_BACKUP_PRIVILEGES_CHECKED flag
3550  // while Vista+ checks the TOKEN_WRITE_RESTRICTED flag as one expects.
3551  return (((PTOKEN)Token)->TokenFlags & SE_BACKUP_PRIVILEGES_CHECKED) != 0;
3552 }
3553 
3573 BOOLEAN
3574 NTAPI
3576  _In_ PTOKEN ProcessToken,
3577  _In_ PTOKEN TokenToImpersonate,
3579 {
3580  BOOLEAN CanImpersonate;
3581  PAGED_CODE();
3582 
3583  /*
3584  * SecurityAnonymous and SecurityIdentification levels do not
3585  * allow impersonation.
3586  */
3589  {
3590  return FALSE;
3591  }
3592 
3593  /* Time to lock our tokens */
3594  SepAcquireTokenLockShared(ProcessToken);
3595  SepAcquireTokenLockShared(TokenToImpersonate);
3596 
3597  /* What kind of authentication ID does the token have? */
3598  if (RtlEqualLuid(&TokenToImpersonate->AuthenticationId,
3600  {
3601  /*
3602  * OK, it looks like the token has an anonymous
3603  * authentication. Is that token created by the system?
3604  */
3605  if (TokenToImpersonate->TokenSource.SourceName != SeSystemTokenSource.SourceName &&
3606  !RtlEqualLuid(&TokenToImpersonate->TokenSource.SourceIdentifier, &SeSystemTokenSource.SourceIdentifier))
3607  {
3608  /* It isn't, we can't impersonate regular tokens */
3609  DPRINT("SeTokenCanImpersonate(): Token has an anonymous authentication ID, can't impersonate!\n");
3610  CanImpersonate = FALSE;
3611  goto Quit;
3612  }
3613  }
3614 
3615  /* Are the SID values from both tokens equal? */
3616  if (!RtlEqualSid(ProcessToken->UserAndGroups->Sid,
3617  TokenToImpersonate->UserAndGroups->Sid))
3618  {
3619  /* They aren't, bail out */
3620  DPRINT("SeTokenCanImpersonate(): Tokens SIDs are not equal!\n");
3621  CanImpersonate = FALSE;
3622  goto Quit;
3623  }
3624 
3625  /*
3626  * Make sure the tokens aren't diverged in terms of
3627  * restrictions, that is, one token is restricted
3628  * but the other one isn't.
3629  */
3630  if (SeTokenIsRestricted(ProcessToken) !=
3631  SeTokenIsRestricted(TokenToImpersonate))
3632  {
3633  /*
3634  * One token is restricted so we cannot
3635  * continue further at this point, bail out.
3636  */
3637  DPRINT("SeTokenCanImpersonate(): One token is restricted, can't continue!\n");
3638  CanImpersonate = FALSE;
3639  goto Quit;
3640  }
3641 
3642  /* If we've reached that far then we can impersonate! */
3643  DPRINT("SeTokenCanImpersonate(): We can impersonate.\n");
3644  CanImpersonate = TRUE;
3645 
3646 Quit:
3647  /* We're done, unlock the tokens now */
3648  SepReleaseTokenLock(ProcessToken);
3649  SepReleaseTokenLock(TokenToImpersonate);
3650 
3651  return CanImpersonate;
3652 }
3653 
3654 /* SYSTEM CALLS ***************************************************************/
3655 
3690 NTSTATUS
3691 NTAPI
3696  PVOID TokenInformation,
3699 {
3700  NTSTATUS Status;
3702  PTOKEN Token;
3704  union
3705  {
3706  PSID PSid;
3707  ULONG Ulong;
3708  } Unused;
3709 
3710  PAGED_CODE();
3711 
3713 
3714  /* Check buffers and class validity */
3718  TokenInformation,
3720  ReturnLength,
3721  NULL,
3722  PreviousMode,
3723  TRUE);
3724  if (!NT_SUCCESS(Status))
3725  {
3726  DPRINT("NtQueryInformationToken() failed, Status: 0x%x\n", Status);
3727  return Status;
3728  }
3729 
3733  PreviousMode,
3734  (PVOID*)&Token,
3735  NULL);
3736  if (NT_SUCCESS(Status))
3737  {
3738  /* Lock the token */
3740 
3741  switch (TokenInformationClass)
3742  {
3743  case TokenUser:
3744  {
3745  PTOKEN_USER tu = (PTOKEN_USER)TokenInformation;
3746 
3747  DPRINT("NtQueryInformationToken(TokenUser)\n");
3748  RequiredLength = sizeof(TOKEN_USER) +
3749  RtlLengthSid(Token->UserAndGroups[0].Sid);
3750 
3751  _SEH2_TRY
3752  {
3754  {
3756  &Token->UserAndGroups[0],
3757  RequiredLength - sizeof(TOKEN_USER),
3758  &tu->User,
3759  (PSID)(tu + 1),
3760  &Unused.PSid,
3761  &Unused.Ulong);
3762  }
3763  else
3764  {
3766  }
3767 
3768  if (ReturnLength != NULL)
3769  {
3771  }
3772  }
3774  {
3776  }
3777  _SEH2_END;
3778 
3779  break;
3780  }
3781 
3782  case TokenGroups:
3783  {
3784  PTOKEN_GROUPS tg = (PTOKEN_GROUPS)TokenInformation;
3785 
3786  DPRINT("NtQueryInformationToken(TokenGroups)\n");
3787  RequiredLength = sizeof(tg->GroupCount) +
3788  RtlLengthSidAndAttributes(Token->UserAndGroupCount - 1, &Token->UserAndGroups[1]);
3789 
3790  _SEH2_TRY
3791  {
3793  {
3794  ULONG SidLen = RequiredLength - sizeof(tg->GroupCount) -
3795  ((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES));
3796  PSID Sid = (PSID_AND_ATTRIBUTES)((ULONG_PTR)tg + sizeof(tg->GroupCount) +
3797  ((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES)));
3798 
3799  tg->GroupCount = Token->UserAndGroupCount - 1;
3800  Status = RtlCopySidAndAttributesArray(Token->UserAndGroupCount - 1,
3801  &Token->UserAndGroups[1],
3802  SidLen,
3803  &tg->Groups[0],
3804  Sid,
3805  &Unused.PSid,
3806  &Unused.Ulong);
3807  }
3808  else
3809  {
3811  }
3812 
3813  if (ReturnLength != NULL)
3814  {
3816  }
3817  }
3819  {
3821  }
3822  _SEH2_END;
3823 
3824  break;
3825  }
3826 
3827  case TokenPrivileges:
3828  {
3829  PTOKEN_PRIVILEGES tp = (PTOKEN_PRIVILEGES)TokenInformation;
3830 
3831  DPRINT("NtQueryInformationToken(TokenPrivileges)\n");
3832  RequiredLength = sizeof(tp->PrivilegeCount) +
3833  (Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
3834 
3835  _SEH2_TRY
3836  {
3838  {
3839  tp->PrivilegeCount = Token->PrivilegeCount;
3840  RtlCopyLuidAndAttributesArray(Token->PrivilegeCount,
3841  Token->Privileges,
3842  &tp->Privileges[0]);
3843  }
3844  else
3845  {
3847  }
3848 
3849  if (ReturnLength != NULL)
3850  {
3852  }
3853  }
3855  {
3857  }
3858  _SEH2_END;
3859 
3860  break;
3861  }
3862 
3863  case TokenOwner:
3864  {
3865  PTOKEN_OWNER to = (PTOKEN_OWNER)TokenInformation;
3866  ULONG SidLen;
3867 
3868  DPRINT("NtQueryInformationToken(TokenOwner)\n");
3869  SidLen = RtlLengthSid(Token->UserAndGroups[Token->DefaultOwnerIndex].Sid);
3870  RequiredLength = sizeof(TOKEN_OWNER) + SidLen;
3871 
3872  _SEH2_TRY
3873  {
3875  {
3876  to->Owner = (PSID)(to + 1);
3877  Status = RtlCopySid(SidLen,
3878  to->Owner,
3879  Token->UserAndGroups[Token->DefaultOwnerIndex].Sid);
3880  }
3881  else
3882  {
3884  }
3885 
3886  if (ReturnLength != NULL)
3887  {
3889  }
3890  }
3892  {
3894  }
3895  _SEH2_END;
3896 
3897  break;
3898  }
3899 
3900  case TokenPrimaryGroup:
3901  {
3902  PTOKEN_PRIMARY_GROUP tpg = (PTOKEN_PRIMARY_GROUP)TokenInformation;
3903  ULONG SidLen;
3904 
3905  DPRINT("NtQueryInformationToken(TokenPrimaryGroup)\n");
3906  SidLen = RtlLengthSid(Token->PrimaryGroup);
3907  RequiredLength = sizeof(TOKEN_PRIMARY_GROUP) + SidLen;
3908 
3909  _SEH2_TRY
3910  {
3912  {
3913  tpg->PrimaryGroup = (PSID)(tpg + 1);
3914  Status = RtlCopySid(SidLen,
3915  tpg->PrimaryGroup,
3916  Token->PrimaryGroup);
3917  }
3918  else
3919  {
3921  }
3922 
3923  if (ReturnLength != NULL)
3924  {
3926  }
3927  }
3929  {
3931  }
3932  _SEH2_END;
3933 
3934  break;
3935  }
3936 
3937  case TokenDefaultDacl:
3938  {
3939  PTOKEN_DEFAULT_DACL tdd = (PTOKEN_DEFAULT_DACL)TokenInformation;
3940 
3941  DPRINT("NtQueryInformationToken(TokenDefaultDacl)\n");
3943 
3944  if (Token->DefaultDacl != NULL)
3945  RequiredLength += Token->DefaultDacl->AclSize;
3946 
3947  _SEH2_TRY
3948  {
3950  {
3951  if (Token->DefaultDacl != NULL)
3952  {
3953  tdd->DefaultDacl = (PACL)(tdd + 1);
3955  Token->DefaultDacl,
3956  Token->DefaultDacl->AclSize);
3957  }
3958  else
3959  {
3960  tdd->DefaultDacl = NULL;
3961  }
3962  }
3963  else
3964  {
3966  }
3967 
3968  if (ReturnLength != NULL)
3969  {
3971  }
3972  }
3974  {
3976  }
3977  _SEH2_END;
3978 
3979  break;
3980  }
3981 
3982  case TokenSource:
3983  {
3984  PTOKEN_SOURCE ts = (PTOKEN_SOURCE)TokenInformation;
3985 
3986  DPRINT("NtQueryInformationToken(TokenSource)\n");
3987  RequiredLength = sizeof(TOKEN_SOURCE);
3988 
3989  _SEH2_TRY
3990  {
3992  {
3993  *ts = Token->TokenSource;
3994  }
3995  else
3996  {
3998  }
3999 
4000  if (ReturnLength != NULL)
4001  {
4003  }
4004  }
4006  {
4008  }
4009  _SEH2_END;
4010 
4011  break;
4012  }
4013 
4014  case TokenType:
4015  {
4016  PTOKEN_TYPE tt = (PTOKEN_TYPE)TokenInformation;
4017 
4018  DPRINT("NtQueryInformationToken(TokenType)\n");
4019  RequiredLength = sizeof(TOKEN_TYPE);
4020 
4021  _SEH2_TRY
4022  {
4024  {
4025  *tt = Token->TokenType;
4026  }
4027  else
4028  {
4030  }
4031 
4032  if (ReturnLength != NULL)
4033  {
4035  }
4036  }
4038  {
4040  }
4041  _SEH2_END;
4042 
4043  break;
4044  }
4045 
4047  {
4049 
4050  DPRINT("NtQueryInformationToken(TokenImpersonationLevel)\n");
4051 
4052  /* Fail if the token is not an impersonation token */
4053  if (Token->TokenType != TokenImpersonation)
4054  {
4056  break;
4057  }
4058 
4060 
4061  _SEH2_TRY
4062  {
4064  {
4065  *sil = Token->ImpersonationLevel;
4066  }
4067  else
4068  {
4070  }
4071 
4072  if (ReturnLength != NULL)
4073  {
4075  }
4076  }
4078  {
4080  }
4081  _SEH2_END;
4082 
4083  break;
4084  }
4085 
4086  case TokenStatistics:
4087  {
4088  PTOKEN_STATISTICS ts = (PTOKEN_STATISTICS)TokenInformation;
4089 
4090  DPRINT("NtQueryInformationToken(TokenStatistics)\n");
4091  RequiredLength = sizeof(TOKEN_STATISTICS);
4092 
4093  _SEH2_TRY
4094  {
4096  {
4097  ts->TokenId = Token->TokenId;
4098  ts->AuthenticationId = Token->AuthenticationId;
4099  ts->ExpirationTime = Token->ExpirationTime;
4100  ts->TokenType = Token->TokenType;
4101  ts->ImpersonationLevel = Token->ImpersonationLevel;
4102  ts->DynamicCharged = Token->DynamicCharged;
4103  ts->DynamicAvailable = Token->DynamicAvailable;
4104  ts->GroupCount = Token->UserAndGroupCount - 1;
4105  ts->PrivilegeCount = Token->PrivilegeCount;
4106  ts->ModifiedId = Token->ModifiedId;
4107  }
4108  else
4109  {
4111  }
4112 
4113  if (ReturnLength != NULL)
4114  {
4116  }
4117  }
4119  {
4121  }
4122  _SEH2_END;
4123 
4124  break;
4125  }
4126 
4127  case TokenOrigin:
4128  {
4129  PTOKEN_ORIGIN to = (PTOKEN_ORIGIN)TokenInformation;
4130 
4131  DPRINT("NtQueryInformationToken(TokenOrigin)\n");
4132  RequiredLength = sizeof(TOKEN_ORIGIN);
4133 
4134  _SEH2_TRY
4135  {
4137  {
4139  &Token->AuthenticationId);
4140  }
4141  else
4142  {
4144  }
4145 
4146  if (ReturnLength != NULL)
4147  {
4149  }
4150  }
4152  {
4154  }
4155  _SEH2_END;
4156 
4157  break;
4158  }
4159 
4161  DPRINT1("NtQueryInformationToken(TokenGroupsAndPrivileges) not implemented\n");
4163  break;
4164 
4165  case TokenRestrictedSids:
4166  {
4167  PTOKEN_GROUPS tg = (PTOKEN_GROUPS)TokenInformation;
4168 
4169  DPRINT("NtQueryInformationToken(TokenRestrictedSids)\n");
4170  RequiredLength = sizeof(tg->GroupCount) +
4171  RtlLengthSidAndAttributes(Token->RestrictedSidCount, Token->RestrictedSids);
4172 
4173  _SEH2_TRY
4174  {
4176  {
4177  ULONG SidLen = RequiredLength - sizeof(tg->GroupCount) -
4178  (Token->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES));
4179  PSID Sid = (PSID)((ULONG_PTR)tg + sizeof(tg->GroupCount) +
4180  (Token->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES)));
4181 
4182  tg->GroupCount = Token->RestrictedSidCount;
4183  Status = RtlCopySidAndAttributesArray(Token->RestrictedSidCount,
4184  Token->RestrictedSids,
4185  SidLen,
4186  &tg->Groups[0],
4187  Sid,
4188  &Unused.PSid,
4189  &Unused.Ulong);
4190  }
4191  else
4192  {
4194  }
4195 
4196  if (ReturnLength != NULL)
4197  {
4199  }
4200  }
4202  {
4204  }
4205  _SEH2_END;
4206 
4207  break;
4208  }
4209 
4210  case TokenSandBoxInert:
4211  DPRINT1("NtQueryInformationToken(TokenSandboxInert) not implemented\n");
4213  break;
4214 
4215  case TokenSessionId:
4216  {
4217  ULONG SessionId = 0;
4218 
4219  DPRINT("NtQueryInformationToken(TokenSessionId)\n");
4220 
4222  if (NT_SUCCESS(Status))
4223  {
4224  _SEH2_TRY
4225  {
4226  /* Buffer size was already verified, no need to check here again */
4227  *(PULONG)TokenInformation = SessionId;
4228 
4229  if (ReturnLength != NULL)
4230  {
4231  *ReturnLength = sizeof(ULONG);
4232  }
4233  }
4235  {
4237  }
4238  _SEH2_END;
4239  }
4240 
4241  break;
4242  }
4243 
4244  default:
4245  DPRINT1("NtQueryInformationToken(%d) invalid information class\n", TokenInformationClass);
4247  break;
4248  }
4249 
4250  /* Unlock and dereference the token */
4253  }
4254 
4255  return Status;
4256 }
4257 
4292 NTSTATUS
4293 NTAPI
4297  _In_reads_bytes_(TokenInformationLength) PVOID TokenInformation,
4299 {
4300  NTSTATUS Status;
4301  PTOKEN Token;
4303  ULONG NeededAccess = TOKEN_ADJUST_DEFAULT;
4304 
4305  PAGED_CODE();
4306 
4308 
4312  TokenInformation,
4314  PreviousMode);
4315  if (!NT_SUCCESS(Status))
4316  {
4317  /* Invalid buffers */
4318  DPRINT("NtSetInformationToken() failed, Status: 0x%x\n", Status);
4319  return Status;
4320  }
4321 
4323  {
4324  NeededAccess |= TOKEN_ADJUST_SESSIONID;
4325  }
4326 
4328  NeededAccess,
4330  PreviousMode,
4331  (PVOID*)&Token,
4332  NULL);
4333  if (NT_SUCCESS(Status))
4334  {
4335  switch (TokenInformationClass)
4336  {
4337  case TokenOwner:
4338  {
4339  if (TokenInformationLength >= sizeof(TOKEN_OWNER))
4340  {
4341  PTOKEN_OWNER to = (PTOKEN_OWNER)TokenInformation;
4342  PSID InputSid = NULL, CapturedSid;
4343  ULONG DefaultOwnerIndex;
4344 
4345  _SEH2_TRY
4346  {
4347  InputSid = to->Owner;
4348  }
4350  {
4352  _SEH2_YIELD(goto Cleanup);
4353  }
4354  _SEH2_END;
4355 
4356  Status = SepCaptureSid(InputSid,
4357  PreviousMode,
4358  PagedPool,
4359  FALSE,
4360  &CapturedSid);
4361  if (NT_SUCCESS(Status))
4362  {
4363  /* Lock the token */
4365 
4366  /* Find the owner amongst the existing token user and groups */
4368  NULL,
4369  CapturedSid,
4370  NULL,
4371  &DefaultOwnerIndex);
4372  if (NT_SUCCESS(Status))
4373  {
4374  /* Found it */
4375  Token->DefaultOwnerIndex = DefaultOwnerIndex;
4376  ExAllocateLocallyUniqueId(&Token->ModifiedId);
4377  }
4378 
4379  /* Unlock the token */
4381 
4382  SepReleaseSid(CapturedSid,
4383  PreviousMode,
4384  FALSE);
4385  }
4386  }
4387  else
4388  {
4390  }
4391  break;
4392  }
4393 
4394  case TokenPrimaryGroup:
4395  {
4397  {
4398  PTOKEN_PRIMARY_GROUP tpg = (PTOKEN_PRIMARY_GROUP)TokenInformation;
4399  PSID InputSid = NULL, CapturedSid;
4400  ULONG PrimaryGroupIndex;
4401 
4402  _SEH2_TRY
4403  {
4404  InputSid = tpg->PrimaryGroup;
4405  }
4407  {
4409  _SEH2_YIELD(goto Cleanup);
4410  }
4411  _SEH2_END;
4412 
4413  Status = SepCaptureSid(InputSid,
4414  PreviousMode,
4415  PagedPool,
4416  FALSE,
4417  &CapturedSid);
4418  if (NT_SUCCESS(Status))
4419  {
4420  /* Lock the token */
4422 
4423  /* Find the primary group amongst the existing token user and groups */
4425  CapturedSid,
4426  NULL,
4427  &PrimaryGroupIndex,
4428  NULL);
4429  if (NT_SUCCESS(Status))
4430  {
4431  /* Found it */
4432  Token->PrimaryGroup = Token->UserAndGroups[PrimaryGroupIndex].Sid;
4433  ExAllocateLocallyUniqueId(&Token->ModifiedId);
4434  }
4435 
4436  /* Unlock the token */
4438 
4439  SepReleaseSid(CapturedSid,
4440  PreviousMode,
4441  FALSE);
4442  }
4443  }
4444  else
4445  {
4447  }
4448  break;
4449  }
4450 
4451  case TokenDefaultDacl:
4452  {
4454  {
4455  PTOKEN_DEFAULT_DACL tdd = (PTOKEN_DEFAULT_DACL)TokenInformation;
4456  PACL InputAcl = NULL;
4457 
4458  _SEH2_TRY
4459  {
4460  InputAcl = tdd->DefaultDacl;
4461  }
4463  {
4465  _SEH2_YIELD(goto Cleanup);
4466  }
4467  _SEH2_END;
4468 
4469  if (InputAcl != NULL)
4470  {
4471  PACL CapturedAcl;
4472 
4473  /* Capture and copy the dacl */
4474  Status = SepCaptureAcl(InputAcl,
4475  PreviousMode,
4476  PagedPool,
4477  TRUE,
4478  &CapturedAcl);
4479  if (NT_SUCCESS(Status))
4480  {
4481  ULONG DynamicLength;
4482 
4483  /* Lock the token */
4485 
4486  //
4487  // NOTE: So far our dynamic area only contains
4488  // the default dacl, so this makes the following
4489  // code pretty simple. The day where it stores
4490  // other data, the code will require adaptations.
4491  //
4492 
4493  DynamicLength = Token->DynamicAvailable;
4494  // Add here any other data length present in the dynamic area...
4495  if (Token->DefaultDacl)
4496  DynamicLength += Token->DefaultDacl->AclSize;
4497 
4498  /* Reallocate the dynamic area if it is too small */
4500  if ((DynamicLength < CapturedAcl->AclSize) ||
4501  (Token->DynamicPart == NULL))
4502  {
4503  PVOID NewDynamicPart;
4504 
4505  NewDynamicPart = ExAllocatePoolWithTag(PagedPool,
4506  CapturedAcl->AclSize,
4508  if (NewDynamicPart == NULL)
4509  {
4511  }
4512  else
4513  {
4514  if (Token->DynamicPart != NULL)
4515  {
4516  // RtlCopyMemory(NewDynamicPart, Token->DynamicPart, DynamicLength);
4517  ExFreePoolWithTag(Token->DynamicPart, TAG_TOKEN_DYNAMIC);
4518  }
4519  Token->DynamicPart = NewDynamicPart;
4520  Token->DynamicAvailable = 0;
4521  }
4522  }
4523  else
4524  {
4525  Token->DynamicAvailable = DynamicLength - CapturedAcl->AclSize;
4526  }
4527 
4528  if (NT_SUCCESS(Status))
4529  {
4530  /* Set the new dacl */
4531  Token->DefaultDacl = (PVOID)Token->DynamicPart;
4532  RtlCopyMemory(Token->DefaultDacl,
4533  CapturedAcl,
4534  CapturedAcl->AclSize);
4535 
4536  ExAllocateLocallyUniqueId(&Token->ModifiedId);
4537  }
4538 
4539  /* Unlock the token */
4541 
4542  ExFreePoolWithTag(CapturedAcl, TAG_ACL);
4543  }
4544  }
4545  else
4546  {
4547  /* Lock the token */
4549 
4550  /* Clear the default dacl if present */
4551  if (Token->DefaultDacl != NULL)
4552  {
4553  Token->DynamicAvailable += Token->DefaultDacl->AclSize;
4554  RtlZeroMemory(Token->DefaultDacl, Token->DefaultDacl->AclSize);
4555  Token->DefaultDacl = NULL;
4556 
4557  ExAllocateLocallyUniqueId(&Token->ModifiedId);
4558  }
4559 
4560  /* Unlock the token */
4562  }
4563  }
4564  else
4565  {
4567  }
4568  break;
4569  }
4570 
4571  case TokenSessionId:
4572  {
4573  ULONG SessionId = 0;
4574 
4575  _SEH2_TRY
4576  {
4577  /* Buffer size was already verified, no need to check here again */
4578  SessionId = *(PULONG)TokenInformation;
4579  }
4581  {
4583  _SEH2_YIELD(goto Cleanup);
4584  }
4585  _SEH2_END;
4586 
4587  /* Check for TCB privilege */
4589  {
4591  break;
4592  }
4593 
4594  /* Lock the token */
4596 
4597  Token->SessionId = SessionId;
4598  ExAllocateLocallyUniqueId(&Token->ModifiedId);
4599 
4600  /* Unlock the token */
4602 
4603  break;
4604  }
4605 
4606  case TokenSessionReference:
4607  {
4608  ULONG SessionReference;
4609 
4610  _SEH2_TRY
4611  {
4612  /* Buffer size was already verified, no need to check here again */
4613  SessionReference = *(PULONG)TokenInformation;
4614  }
4616  {
4618  _SEH2_YIELD(goto Cleanup);
4619  }
4620  _SEH2_END;
4621 
4622  /* Check for TCB privilege */
4624  {
4626  goto Cleanup;
4627  }
4628 
4629  /* Check if it is 0 */
4630  if (SessionReference == 0)
4631  {
4632  ULONG OldTokenFlags;
4633 
4634  /* Lock the token */
4636 
4637  /* Atomically set the flag in the token */
4638  OldTokenFlags = RtlInterlockedSetBits(&Token->TokenFlags,
4640  /*
4641  * If the flag was already set, do not dereference again
4642  * the logon session. Use SessionReference as an indicator
4643  * to know whether to really dereference the session.
4644  */
4645  if (OldTokenFlags == Token->TokenFlags)
4646  SessionReference = ULONG_MAX;
4647 
4648  /*
4649  * Otherwise if the flag was never set but just for this first time then
4650  * remove the referenced logon session data from the token and dereference
4651  * the logon session when needed.
4652  */
4653  if (SessionReference == 0)
4654  {
4656  SepRmDereferenceLogonSession(&Token->AuthenticationId);
4657  }
4658 
4659  /* Unlock the token */
4661  }
4662  break;
4663  }
4664 
4665  case TokenAuditPolicy:
4666  {
4667  PTOKEN_AUDIT_POLICY_INFORMATION PolicyInformation =
4668  (PTOKEN_AUDIT_POLICY_INFORMATION)TokenInformation;
4669  SEP_AUDIT_POLICY AuditPolicy;
4670  ULONG i;
4671 
4672  _SEH2_TRY
4673  {
4674  ProbeForRead(PolicyInformation,
4676  Policies[PolicyInformation->PolicyCount]),
4677  sizeof(ULONG));
4678 
4679  /* Loop all policies in the structure */
4680  for (i = 0; i < PolicyInformation->PolicyCount; i++)
4681  {
4682  /* Set the corresponding bits in the packed structure */
4683  switch (PolicyInformation->Policies[i].Category)
4684  {
4685  case AuditCategorySystem:
4686  AuditPolicy.PolicyElements.System = PolicyInformation->Policies[i].Value;
4687  break;
4688 
4689  case AuditCategoryLogon:
4690  AuditPolicy.PolicyElements.Logon = PolicyInformation->Policies[i].Value;
4691  break;
4692 
4694  AuditPolicy.PolicyElements.ObjectAccess = PolicyInformation->Policies[i].Value;
4695  break;
4696 
4698  AuditPolicy.PolicyElements.PrivilegeUse = PolicyInformation->Policies[i].Value;
4699  break;
4700 
4702  AuditPolicy.PolicyElements.DetailedTracking = PolicyInformation->Policies[i].Value;
4703  break;
4704 
4706  AuditPolicy.PolicyElements.PolicyChange = PolicyInformation->Policies[i].Value;
4707  break;
4708 
4710  AuditPolicy.PolicyElements.AccountManagement = PolicyInformation->Policies[i].Value;
4711  break;
4712 
4714  AuditPolicy.PolicyElements.DirectoryServiceAccess = PolicyInformation->Policies[i].Value;
4715  break;
4716 
4718  AuditPolicy.PolicyElements.AccountLogon = PolicyInformation->Policies[i].Value;
4719  break;
4720  }
4721  }
4722  }
4724  {
4726  _SEH2_YIELD(goto Cleanup);
4727  }
4728  _SEH2_END;
4729 
4730  /* Check for TCB privilege */
4732  {
4734  break;
4735  }
4736 
4737  /* Lock the token */
4739 
4740  /* Set the new audit policy */
4741  Token->AuditPolicy = AuditPolicy;
4742  ExAllocateLocallyUniqueId(&Token->ModifiedId);
4743 
4744  /* Unlock the token */
4746 
4747  break;
4748  }
4749 
4750  case TokenOrigin:
4751  {
4753 
4754  _SEH2_TRY
4755  {
4756  /* Copy the token origin */
4757  TokenOrigin = *(PTOKEN_ORIGIN)TokenInformation;
4758  }
4760  {
4762  _SEH2_YIELD(goto Cleanup);
4763  }
4764  _SEH2_END;
4765 
4766  /* Check for TCB privilege */
4768  {
4770  break;
4771  }
4772 
4773  /* Lock the token */
4775 
4776  /* Check if there is no token origin set yet */
4777  if (RtlIsZeroLuid(&Token->OriginatingLogonSession))
4778  {
4779  /* Set the token origin */
4780  Token->OriginatingLogonSession =
4781  TokenOrigin.OriginatingLogonSession;
4782 
4783  ExAllocateLocallyUniqueId(&Token->ModifiedId);
4784  }
4785 
4786  /* Unlock the token */
4788 
4789  break;
4790  }
4791 
4792  default:
4793  {
4794  DPRINT1("Invalid TokenInformationClass: 0x%lx\n",
4797  break;
4798  }
4799  }
4800 Cleanup:
4802  }
4803 
4804  if (!NT_SUCCESS(Status))
4805  {
4806  DPRINT1("NtSetInformationToken failed with Status 0x%lx\n", Status);
4807  }
4808 
4809  return Status;
4810 }
4811 
4851 NTSTATUS
4852 NTAPI
4854  _In_ HANDLE ExistingTokenHandle,
4860 {
4862  HANDLE hToken;
4863  PTOKEN Token;
4864  PTOKEN NewToken;
4865  PSECURITY_QUALITY_OF_SERVICE CapturedSecurityQualityOfService;
4866  BOOLEAN QoSPresent;
4868  NTSTATUS Status;
4869 
4870  PAGED_CODE();
4871 
4872  if (TokenType != TokenImpersonation &&
4874  {
4875  return STATUS_INVALID_PARAMETER;
4876  }
4877 
4879 
4880  if (PreviousMode != KernelMode)
4881  {
4882  _SEH2_TRY
4883  {
4885  }
4887  {
4888  /* Return the exception code */
4890  }
4891  _SEH2_END;
4892  }
4893 
4895  PreviousMode,
4896  PagedPool,
4897  FALSE,
4898  &CapturedSecurityQualityOfService,
4899  &QoSPresent);
4900  if (!NT_SUCCESS(Status))
4901  {
4902  DPRINT1("NtDuplicateToken() failed to capture QoS! Status: 0x%x\n", Status);
4903  return Status;
4904  }
4905 
4906  Status = ObReferenceObjectByHandle(ExistingTokenHandle,
4909  PreviousMode,
4910  (PVOID*)&Token,
4912  if (!NT_SUCCESS(Status))
4913  {
4914  DPRINT1("Failed to reference token (Status 0x%lx)\n", Status);
4915  SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
4916  PreviousMode,
4917  FALSE);
4918  return Status;
4919  }
4920 
4921  /*
4922  * Fail, if the original token is an impersonation token and the caller
4923  * tries to raise the impersonation level of the new token above the
4924  * impersonation level of the original token.
4925  */
4926  if (Token->TokenType == TokenImpersonation)
4927  {
4928  if (QoSPresent &&
4929  CapturedSecurityQualityOfService->ImpersonationLevel >Token->ImpersonationLevel)
4930  {
4932  SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
4933  PreviousMode,
4934  FALSE);
4936  }
4937  }
4938 
4939  /*
4940  * Fail, if a primary token is to be created from an impersonation token
4941  * and and the impersonation level of the impersonation token is below SecurityImpersonation.
4942  */
4943  if (Token->TokenType == TokenImpersonation &&
4944  TokenType == TokenPrimary &&
4945  Token->ImpersonationLevel < SecurityImpersonation)
4946  {
4948  SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
4949  PreviousMode,
4950  FALSE);
4952  }
4953 
4956  EffectiveOnly,
4957  TokenType,
4958  (QoSPresent ? CapturedSecurityQualityOfService->ImpersonationLevel : SecurityAnonymous),
4959  PreviousMode,
4960  &NewToken);
4961 
4963 
4964  if (NT_SUCCESS(Status))
4965  {
4966  Status = ObInsertObject(NewToken,
4967  NULL,
4968  (DesiredAccess ? DesiredAccess : HandleInformation.GrantedAccess),
4969  0,
4970  NULL,
4971  &hToken);
4972  if (NT_SUCCESS(Status))
4973  {
4974  _SEH2_TRY
4975  {
4976  *NewTokenHandle = hToken;
4977  }
4979  {
4981  }
4982  _SEH2_END;
4983  }
4984  }
4985 
4986  /* Free the captured structure */
4987  SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
4988  PreviousMode,
4989  FALSE);
4990 
4991  return Status;
4992 }
4993 
5066 static
5067 NTSTATUS
5069  _In_ PTOKEN Token,
5070  _In_opt_ PSID_AND_ATTRIBUTES NewState,
5071  _In_ ULONG NewStateCount,
5073  _In_ BOOLEAN ResetToDefaultStates,
5074  _Out_ PBOOLEAN ChangesMade,
5075  _Out_opt_ PTOKEN_GROUPS PreviousGroupsState,
5076  _Out_ PULONG ChangedGroups)
5077 {
5078  ULONG GroupsInToken, GroupsInList;
5079  ULONG ChangeCount, GroupsCount, NewAttributes;
5080 
5081  PAGED_CODE();
5082 
5083  /* Ensure that the token we get is not plain garbage */
5084  ASSERT(Token);
5085 
5086  /* Initialize the counters and begin the work */
5087  *ChangesMade = FALSE;
5088  GroupsCount = 0;
5089  ChangeCount = 0;
5090 
5091  /* Begin looping all the groups in the token */
5092  for (GroupsInToken = 0; GroupsInToken < Token->UserAndGroupCount; GroupsInToken++)
5093  {
5094  /* Does the caller want to reset groups to default states? */
5095  if (ResetToDefaultStates)
5096  {
5097  /*
5098  * SE_GROUP_ENABLED_BY_DEFAULT is a special indicator that informs us
5099  * if a certain group has been enabled by default or not. In case
5100  * a group is enabled by default but it is not currently enabled then
5101  * at that point we must enable it back by default. For now just
5102  * assign the respective SE_GROUP_ENABLED attribute as we'll do the
5103  * eventual work later.
5104  */
5105  if ((Token->UserAndGroups[GroupsInToken].Attributes & SE_GROUP_ENABLED_BY_DEFAULT) &&
5106  (Token->UserAndGroups[GroupsInToken].Attributes & SE_GROUP_ENABLED) == 0)
5107  {
5108  NewAttributes = Token->UserAndGroups[GroupsInToken].Attributes |= SE_GROUP_ENABLED;
5109  }
5110 
5111  /*
5112  * Unlike the case above, a group that hasn't been enabled by
5113  * default but it's currently enabled then we must disable
5114  * it back.
5115  */
5116  if ((Token->UserAndGroups[GroupsInToken].Attributes & SE_GROUP_ENABLED_BY_DEFAULT) == 0 &&
5117  (Token->UserAndGroups[GroupsInToken].Attributes & SE_GROUP_ENABLED))
5118  {
5119  NewAttributes = Token->UserAndGroups[GroupsInToken].Attributes & ~SE_GROUP_ENABLED;
5120  }
5121  }
5122  else
5123  {
5124  /* Loop the provided groups in the list then */
5125  for (GroupsInList = 0; GroupsInList < NewStateCount; GroupsInList++)
5126  {
5127  /* Does this group exist in the token? */
5128  if (RtlEqualSid(&Token->UserAndGroups[GroupsInToken].Sid,
5129  &NewState[GroupsInList].Sid))
5130  {
5131  /*
5132  * This is the group that we're looking for.
5133  * However, it could be that the group is a
5134  * mandatory group which we are not allowed
5135  * and cannot disable it.
5136  */
5137  if ((Token->UserAndGroups[GroupsInToken].Attributes & SE_GROUP_MANDATORY) &&
5138  (NewState[GroupsInList].Attributes & SE_GROUP_ENABLED) == 0)
5139  {
5140  /* It is mandatory, forget about this group */
5141  DPRINT1("SepAdjustGroups(): The SID group is mandatory!\n");
5143  }
5144 
5145  /*
5146  * We've to ensure that apart the group mustn't be
5147  * mandatory, it mustn't be a restricted group as
5148  * well. That is, the group is marked with
5149  * SE_GROUP_USE_FOR_DENY_ONLY flag and no one
5150  * can enable it because it's for "deny" use only.
5151  */
5152  if ((Token->UserAndGroups[GroupsInToken].Attributes & SE_GROUP_USE_FOR_DENY_ONLY) &&
5153  (NewState[GroupsInList].Attributes & SE_GROUP_ENABLED))
5154  {
5155  /* This group is restricted, forget about it */
5156  DPRINT1("SepAdjustGroups(): The SID group is for use deny only!\n");
5158  }
5159 
5160  /* Copy the attributes and stop searching */
5161  NewAttributes = NewState[GroupsInList].Attributes;
5162  NewAttributes &= SE_GROUP_ENABLED;
5163  NewAttributes = Token->UserAndGroups[GroupsInToken].Attributes & ~SE_GROUP_ENABLED;
5164  break;
5165  }
5166 
5167  /* Did we find the specific group we wanted? */
5168  if (GroupsInList == NewStateCount)
5169  {
5170  /* We didn't, continue with the next token's group */
5171  continue;
5172  }
5173  }
5174 
5175  /* Count the group that we found it */
5176  GroupsCount++;
5177 
5178  /* Does the token have the same attributes as the caller requested them? */
5179  if (Token->UserAndGroups[GroupsInToken].Attributes != NewAttributes)
5180  {
5181  /*
5182  * No, then it's time to make some adjustment to the
5183  * token's groups. Does the caller want the previous states
5184  * of groups?
5185  */
5186  if (PreviousGroupsState != NULL)
5187  {
5188  PreviousGroupsState->Groups[ChangeCount] = Token->UserAndGroups[GroupsInToken];
5189  }
5190 
5191  /* Time to apply the changes now? */
5192  if (ApplyChanges)
5193  {
5194  /* The caller gave us consent, apply and report that we made changes! */
5195  Token->UserAndGroups[GroupsInToken].Attributes = NewAttributes;
5196  *ChangesMade = TRUE;
5197  }
5198 
5199  /* Increment the count change */
5200  ChangeCount++;
5201  }
5202  }
5203  }
5204 
5205  /* Report the number of previous saved groups */
5206  if (PreviousGroupsState != NULL)
5207  {
5208  PreviousGroupsState->GroupCount = ChangeCount;
5209  }
5210 
5211  /* Report the number of changed groups */
5212  *ChangedGroups = ChangeCount;
5213 
5214  /* Did we miss some groups? */
5215  if (!ResetToDefaultStates && (GroupsCount < NewStateCount))
5216  {
5217  /*
5218  * If we're at this stage then we are in a situation
5219  * where the adjust changes done to token's groups is
5220  * not deterministic as the caller might have wanted
5221  * as per NewState parameter.
5222  */
5223  DPRINT1("SepAdjustGroups(): The token hasn't all the groups assigned!\n");
5224  return STATUS_NOT_ALL_ASSIGNED;
5225  }
5226 
5227  return STATUS_SUCCESS;
5228 }
5229 
5274 NTSTATUS
5275 NTAPI
5278  _In_ BOOLEAN ResetToDefault,
5279  _In_ PTOKEN_GROUPS NewState,
5284 {
5285  PTOKEN Token;
5286  NTSTATUS Status;
5288  ULONG ChangeCount, RequiredLength;
5289  ULONG CapturedCount = 0;
5290  ULONG CapturedLength = 0;
5291  ULONG NewStateSize = 0;
5292  PSID_AND_ATTRIBUTES CapturedGroups = NULL;
5293  BOOLEAN ChangesMade = FALSE;
5294  BOOLEAN LockAndReferenceAcquired = FALSE;
5295 
5296  PAGED_CODE();
5297 
5298  /*
5299  * If the caller doesn't want to reset the groups of an
5300  * access token to default states then at least we must
5301  * expect a list of groups to be adjusted based on NewState
5302  * parameter. Otherwise bail out because the caller has
5303  * no idea what they're doing.
5304  */
5305  if (!ResetToDefault && !NewState)
5306  {
5307  DPRINT1("NtAdjustGroupsToken(): The caller hasn't provided any list of groups to adjust!\n");
5308  return STATUS_INVALID_PARAMETER;
5309  }
5310 
5312 
5313  if (PreviousMode != KernelMode)
5314  {
5315  _SEH2_TRY
5316  {
5317  /* Probe NewState */
5318  if (!ResetToDefault)
5319  {
5320  /* Probe the header */
5321  ProbeForRead(NewState, sizeof(*NewState), sizeof(ULONG));
5322 
5323  CapturedCount = NewState->GroupCount;
5324  NewStateSize = FIELD_OFFSET(TOKEN_GROUPS, Groups[CapturedCount]);
5325 
5326  ProbeForRead(NewState, NewStateSize, sizeof(ULONG));
5327  }
5328 
5329  if (PreviousState != NULL)
5330  {
5332  ProbeForWrite(ReturnLength, sizeof(*ReturnLength), sizeof(ULONG));
5333  }
5334  }
5336  {
5337  /* Return the exception code */
5339  }
5340  _SEH2_END;
5341  }
5342  else
5343  {
5344  /*
5345  * We're calling directly from the kernel, just retrieve
5346  * the number count of captured groups outright.
5347  */
5348  if (!ResetToDefault)
5349  {
5350  CapturedCount = NewState->GroupCount;
5351  }
5352  }
5353 
5354  /* Time to capture the NewState list */
5355  if (!ResetToDefault)
5356  {
5357  _SEH2_TRY
5358  {
5359  Status = SeCaptureSidAndAttributesArray(NewState->Groups,
5360  CapturedCount,
5361  PreviousMode,
5362  NULL,
5363  0,
5364  PagedPool,
5365  TRUE,
5366  &CapturedGroups,
5367  &CapturedLength);
5368  }
5370  {
5372  }
5373  _SEH2_END;
5374 
5375  if (!NT_SUCCESS(Status))
5376  {
5377  DPRINT1("NtAdjustGroupsToken(): Failed to capture the NewState list of groups (Status 0x%lx)\n", Status);
5378  return Status;
5379  }
5380  }
5381 
5382  /* Time to reference the token */
5386  PreviousMode,
5387  (PVOID*)&Token,
5388  NULL);
5389  if (!NT_SUCCESS(Status))
5390  {
5391  /* We couldn't reference the access token, bail out */
5392  DPRINT1("NtAdjustGroupsToken(): Failed to reference the token (Status 0x%lx)\n", Status);
5393 
5394  if (CapturedGroups != NULL)
5395  {
5396  SeReleaseSidAndAttributesArray(CapturedGroups,
5397  PreviousMode,
5398  TRUE);
5399  }
5400 
5401  goto Quit;
5402  }
5403 
5404  /* Lock the token */
5406  LockAndReferenceAcquired = TRUE;
5407 
5408  /* Count the number of groups to be changed */
5410  CapturedGroups,
5411  CapturedCount,
5412  FALSE,
5413  ResetToDefault,
5414  &ChangesMade,
5415  NULL,
5416  &ChangeCount);
5417 
5418  /* Does the caller want the previous state of groups? */
5419  if (PreviousState != NULL)
5420  {
5421  /* Calculate the required length */
5423 
5424  /* Return the required length to the caller */
5425  _SEH2_TRY
5426  {
5428  }
5430  {
5431  /* Bail out and return the exception code */
5433  _SEH2_YIELD(goto Quit);
5434  }
5435  _SEH2_END;
5436 
5437  /* The buffer length provided is smaller than the required length, bail out */
5439  {
5441  goto Quit;
5442  }
5443  }
5444 
5445  /*
5446  * Now it's time to apply changes. Wrap the code
5447  * in SEH as we are returning the old groups state
5448  * list to the caller since PreviousState is a
5449  * UM pointer.
5450  */
5451  _SEH2_TRY
5452  {
5454  CapturedGroups,
5455  CapturedCount,
5456  TRUE,
5457  ResetToDefault,
5458  &ChangesMade,
5459  PreviousState,
5460  &ChangeCount);
5461  }
5463  {
5464  /* Bail out and return the exception code */
5466 
5467  /* Force the write as we touched the token still */
5468  ChangesMade = TRUE;
5469  _SEH2_YIELD(goto Quit);
5470  }
5471  _SEH2_END;
5472 
5473 Quit:
5474  /* Allocate a new ID for the token as we made changes */
5475  if (ChangesMade)
5476  {
5477  ExAllocateLocallyUniqueId(&Token->ModifiedId);
5478  }
5479 
5480  /* Have we successfully acquired the lock and referenced the token before? */
5481  if (LockAndReferenceAcquired)
5482  {
5483  /* Unlock and dereference the token */
5486  }
5487 
5488  /* Release the captured groups */
5489  if (CapturedGroups != NULL)
5490  {
5491  SeReleaseSidAndAttributesArray(CapturedGroups,
5492  PreviousMode,
5493  TRUE);
5494  }
5495 
5496  return Status;
5497 }
5498 
5536 static
5537 NTSTATUS
5540  _In_ BOOLEAN DisableAllPrivileges,
5541  _In_opt_ PLUID_AND_ATTRIBUTES NewState,
5542  _In_ ULONG NewStateCount,
5545  _Out_ PULONG ChangedPrivileges,
5546  _Out_ PBOOLEAN ChangesMade)
5547 {
5548  ULONG i, j, PrivilegeCount, ChangeCount, NewAttributes;
5549 
5550  PAGED_CODE();
5551 
5552  /* Count the found privileges and those that need to be changed */
5553  PrivilegeCount = 0;
5554  ChangeCount = 0;
5555  *ChangesMade = FALSE;
5556 
5557  /* Loop all privileges in the token */
5558  for (i = 0; i < Token->PrivilegeCount; i++)
5559  {
5560  /* Shall all of them be disabled? */
5561  if (DisableAllPrivileges)
5562  {
5563  /* The new attributes are the old ones, but disabled */
5564  NewAttributes = Token->Privileges[i].Attributes & ~SE_PRIVILEGE_ENABLED;
5565  }
5566  else
5567  {
5568  /* Otherwise loop all provided privileges */
5569  for (j = 0; j < NewStateCount; j++)
5570  {
5571  /* Check if this is the LUID we are looking for */
5572  if (RtlEqualLuid(&Token->Privileges[i].Luid, &NewState[j].Luid))
5573  {
5574  DPRINT("Found privilege\n");
5575 
5576  /* Copy SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_REMOVED */
5577  NewAttributes = NewState[j].Attributes;
5578  NewAttributes &= (SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_REMOVED);
5579  NewAttributes |= Token->Privileges[i].Attributes & ~SE_PRIVILEGE_ENABLED;
5580 
5581  /* Stop looking */
5582  break;
5583  }
5584  }
5585 
5586  /* Check if we didn't find the privilege */
5587  if (j == NewStateCount)
5588  {
5589  /* Continue with the token's next privilege */
5590  continue;
5591  }
5592  }
5593 
5594  /* We found a privilege, count it */
5595  PrivilegeCount++;
5596 
5597  /* Does the privilege need to be changed? */
5598  if (Token->Privileges[i].Attributes != NewAttributes)
5599  {
5600  /* Does the caller want the old privileges? */
5601  if (PreviousState != NULL)
5602  {
5603  /* Copy the old privilege */
5604  PreviousState->Privileges[ChangeCount] = Token->Privileges[i];
5605  }
5606 
5607  /* Does the caller want to apply the changes? */
5608  if (ApplyChanges)
5609  {
5610  /* Shall we remove the privilege? */
5611  if (NewAttributes & SE_PRIVILEGE_REMOVED)
5612  {
5613  /* Set the token as disabled and update flags for it */
5614  Token->Privileges[i].Attributes &= ~SE_PRIVILEGE_ENABLED;
5616 
5617  /* Remove the privilege */
5619 
5620  *ChangesMade = TRUE;
5621 
5622  /* Fix the running index and continue with next one */
5623  i--;
5624  continue;
5625  }
5626 
5627  /* Set the new attributes and update flags */
5628  Token->Privileges[i].Attributes = NewAttributes;
5630  *ChangesMade = TRUE;
5631  }
5632 
5633  /* Increment the change count */
5634  ChangeCount++;
5635  }
5636  }
5637 
5638  /* Set the number of saved privileges */
5639  if (PreviousState != NULL)
5640  PreviousState->PrivilegeCount = ChangeCount;
5641 
5642  /* Return the number of changed privileges */
5643  *ChangedPrivileges = ChangeCount;
5644 
5645  /* Check if we missed some */
5646  if (!DisableAllPrivileges && (PrivilegeCount < NewStateCount))
5647  {
5648  return STATUS_NOT_ALL_ASSIGNED;
5649  }
5650 
5651  return STATUS_SUCCESS;
5652 }
5653 
5693 NTSTATUS
5694 NTAPI
5697  _In_ BOOLEAN DisableAllPrivileges,
5698  _In_opt_ PTOKEN_PRIVILEGES NewState,
5703 {
5704  NTSTATUS Status;
5706  PTOKEN Token;
5707  PLUID_AND_ATTRIBUTES CapturedPrivileges = NULL;
5708  ULONG CapturedCount = 0;
5709  ULONG CapturedLength = 0;
5710  ULONG NewStateSize = 0;
5711  ULONG ChangeCount;
5713  BOOLEAN ChangesMade = FALSE;
5714 
5715  PAGED_CODE();
5716 
5717  DPRINT("NtAdjustPrivilegesToken() called\n");
5718 
5719  /* Fail, if we do not disable all privileges but NewState is NULL */
5720  if (DisableAllPrivileges == FALSE && NewState == NULL)
5721  return STATUS_INVALID_PARAMETER;
5722 
5724  if (PreviousMode != KernelMode)
5725  {
5726  _SEH2_TRY
5727  {
5728  /* Probe NewState */
5729  if (DisableAllPrivileges == FALSE)
5730  {
5731  /* First probe the header */
5732  ProbeForRead(NewState, sizeof(TOKEN_PRIVILEGES), sizeof(ULONG));
5733 
5734  CapturedCount = NewState->PrivilegeCount;
5735  NewStateSize = FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges[CapturedCount]);
5736 
5737  ProbeForRead(NewState, NewStateSize, sizeof(ULONG));
5738  }
5739 
5740  /* Probe PreviousState and ReturnLength */
5741  if (PreviousState != NULL)
5742  {
5744  ProbeForWrite(ReturnLength, sizeof(ULONG), sizeof(ULONG));
5745  }
5746  }
5748  {
5749  /* Return the exception code */
5751  }
5752  _SEH2_END;
5753  }
5754  else
5755  {
5756  /* This is kernel mode, we trust the caller */
5757  if (DisableAllPrivileges == FALSE)
5758  CapturedCount = NewState->PrivilegeCount;
5759  }
5760 
5761  /* Do we need to capture the new state? */
5762  if (DisableAllPrivileges == FALSE)
5763  {
5764  _SEH2_TRY
5765  {
5766  /* Capture the new state array of privileges */
5767  Status = SeCaptureLuidAndAttributesArray(NewState->Privileges,
5768  CapturedCount,
5769  PreviousMode,
5770  NULL,
5771  0,
5772  PagedPool,
5773  TRUE,
5774  &CapturedPrivileges,
5775  &CapturedLength);
5776  }
5778  {
5779  /* Return the exception code */
5781  }
5782  _SEH2_END;
5783 
5784  if (!NT_SUCCESS(Status))
5785  return Status;
5786  }
5787 
5788  /* Reference the token */
5792  PreviousMode,
5793  (PVOID*)&Token,
5794  NULL);
5795  if (!NT_SUCCESS(Status))
5796  {
5797  DPRINT1("Failed to reference token (Status 0x%lx)\n", Status);
5798 
5799  /* Release the captured privileges */
5800  if (CapturedPrivileges != NULL)
5801  {
5802  SeReleaseLuidAndAttributesArray(CapturedPrivileges,
5803  PreviousMode,
5804  TRUE);
5805  }
5806 
5807  return Status;
5808  }
5809 
5810  /* Lock the token */
5812 
5813  /* Count the privileges that need to be changed, do not apply them yet */
5815  DisableAllPrivileges,
5816  CapturedPrivileges,
5817  CapturedCount,
5818  NULL,
5819  FALSE,
5820  &ChangeCount,
5821  &ChangesMade);
5822 
5823  /* Check if the caller asked for the previous state */
5824  if (PreviousState != NULL)
5825  {
5826  /* Calculate the required length */
5828 
5829  /* Try to return the required buffer length */
5830  _SEH2_TRY
5831  {
5833  }
5835  {
5836  /* Do cleanup and return the exception code */
5838  _SEH2_YIELD(goto Cleanup);
5839  }
5840  _SEH2_END;
5841 
5842  /* Fail, if the buffer length is smaller than the required length */
5844  {
5846  goto Cleanup;
5847  }
5848  }
5849 
5850  /* Now enter SEH, since we might return the old privileges */
5851  _SEH2_TRY
5852  {
5853  /* This time apply the changes */
5855  DisableAllPrivileges,
5856  CapturedPrivileges,
5857  CapturedCount,
5858  PreviousState,
5859  TRUE,
5860  &ChangeCount,
5861  &ChangesMade);
5862  }
5864  {
5865  /* Do cleanup and return the exception code */
5867  ChangesMade = TRUE; // Force write.
5868  _SEH2_YIELD(goto Cleanup);
5869  }
5870  _SEH2_END;
5871 
5872 Cleanup:
5873  /* Touch the token if we made changes */
5874  if (ChangesMade)
5875  ExAllocateLocallyUniqueId(&Token->ModifiedId);
5876 
5877  /* Unlock and dereference the token */
5880 
5881  /* Release the captured privileges */
5882  if (CapturedPrivileges != NULL)
5883  {
5884  SeReleaseLuidAndAttributesArray(CapturedPrivileges,
5885  PreviousMode,
5886  TRUE);
5887  }
5888 
5889  DPRINT ("NtAdjustPrivilegesToken() done\n");
5890  return Status;
5891 }
5892 
5942 NTSTATUS
5943 NTAPI
5949  _In_ PLUID AuthenticationId,
5950  _In_ PLARGE_INTEGER ExpirationTime,
5958 {
5959  HANDLE hToken;
5961  ULONG PrivilegeCount, GroupCount;
5962  PSID OwnerSid, PrimaryGroupSid;
5963  PACL DefaultDacl;
5964  LARGE_INTEGER LocalExpirationTime = {{0, 0}};
5965  LUID LocalAuthenticationId;
5966  TOKEN_SOURCE LocalTokenSource;
5967  SECURITY_QUALITY_OF_SERVICE LocalSecurityQos;
5968  PLUID_AND_ATTRIBUTES CapturedPrivileges = NULL;
5969  PSID_AND_ATTRIBUTES CapturedUser = NULL;
5970  PSID_AND_ATTRIBUTES CapturedGroups = NULL;
5971  PSID CapturedOwnerSid = NULL;
5972  PSID CapturedPrimaryGroupSid = NULL;
5973  PACL CapturedDefaultDacl = NULL;
5974  ULONG PrivilegesLength, UserLength, GroupsLength;
5975  NTSTATUS Status;
5976 
5977  PAGED_CODE();
5978 
5980 
5981  if (PreviousMode != KernelMode)
5982  {
5983  _SEH2_TRY
5984  {
5986 
5987  if (ObjectAttributes != NULL)
5988  {
5990  sizeof(OBJECT_ATTRIBUTES),
5991  sizeof(ULONG));
5992  LocalSecurityQos = *(SECURITY_QUALITY_OF_SERVICE*)ObjectAttributes->SecurityQualityOfService;
5993  }
5994 
5995  ProbeForRead(AuthenticationId,
5996  sizeof(LUID),
5997  sizeof(ULONG));
5998  LocalAuthenticationId = *AuthenticationId;
5999 
6000  LocalExpirationTime = ProbeForReadLargeInteger(ExpirationTime);
6001 
6003  sizeof(TOKEN_USER),
6004  sizeof(ULONG));
6005 
6007  sizeof(TOKEN_GROUPS),
6008  sizeof(ULONG));
6009  GroupCount = TokenGroups->GroupCount;
6010 
6012  sizeof(TOKEN_PRIVILEGES),
6013  sizeof(ULONG));
6014  PrivilegeCount = TokenPrivileges->PrivilegeCount;
6015 
6016  if (TokenOwner != NULL)
6017  {
6019  sizeof(TOKEN_OWNER),
6020  sizeof(ULONG));
6021  OwnerSid = TokenOwner->Owner;
6022  }
6023  else
6024  {
6025  OwnerSid = NULL;
6026  }
6027 
6029  sizeof(TOKEN_PRIMARY_GROUP),
6030  sizeof(ULONG));
6031  PrimaryGroupSid = TokenPrimaryGroup->PrimaryGroup;
6032 
6033  if (TokenDefaultDacl != NULL)
6034  {
6036  sizeof(TOKEN_DEFAULT_DACL),
6037  sizeof(ULONG));
6038  DefaultDacl = TokenDefaultDacl->DefaultDacl;
6039  }
6040  else
6041  {
6042  DefaultDacl = NULL;
6043  }
6044 
6046  sizeof(TOKEN_SOURCE),
6047  sizeof(ULONG));
6048  LocalTokenSource = *TokenSource;
6049  }
6051  {
6052  /* Return the exception code */
6054  }
6055  _SEH2_END;
6056  }
6057  else
6058  {
6059  if (ObjectAttributes != NULL)
6060  LocalSecurityQos = *(SECURITY_QUALITY_OF_SERVICE*)ObjectAttributes->SecurityQualityOfService;
6061  LocalAuthenticationId = *AuthenticationId;
6062  LocalExpirationTime = *ExpirationTime;
6063  GroupCount = TokenGroups->GroupCount;
6064  PrivilegeCount = TokenPrivileges->PrivilegeCount;
6065  OwnerSid = TokenOwner ? TokenOwner->Owner : NULL;
6066  PrimaryGroupSid = TokenPrimaryGroup->PrimaryGroup;
6067  DefaultDacl = TokenDefaultDacl ? TokenDefaultDacl->DefaultDacl : NULL;
6068  LocalTokenSource = *TokenSource;
6069  }
6070 
6071  /* Check token type */
6072  if ((TokenType < TokenPrimary) ||
6074  {
6075  return STATUS_BAD_TOKEN_TYPE;
6076  }
6077 
6078  /* Check for token creation privilege */
6080  {
6082  }
6083 
6084  /* Capture the user SID and attributes */
6086  1,
6087  PreviousMode,
6088  NULL,
6089  0,
6090  PagedPool,
6091  FALSE,
6092  &CapturedUser,
6093  &UserLength);
6094  if (!NT_SUCCESS(Status))
6095  {
6096  goto Cleanup;
6097  }
6098 
6099  /* Capture the groups SID and attributes array */
6101  GroupCount,
6102  PreviousMode,
6103  NULL,
6104  0,
6105  PagedPool,
6106  FALSE,
6107  &CapturedGroups,
6108  &GroupsLength);
6109  if (!NT_SUCCESS(Status))
6110  {
6111  goto Cleanup;
6112  }
6113 
6114  /* Capture privileges */
6116  PrivilegeCount,
6117  PreviousMode,
6118  NULL,
6119  0,
6120  PagedPool,
6121  FALSE,
6122  &CapturedPrivileges,
6123  &PrivilegesLength);
6124  if (!NT_SUCCESS(Status))
6125  {
6126  goto Cleanup;
6127  }
6128 
6129  /* Capture the token owner SID */
6130  if (TokenOwner != NULL)
6131  {
6132  Status = SepCaptureSid(OwnerSid,
6133  PreviousMode,
6134  PagedPool,
6135  FALSE,
6136  &CapturedOwnerSid);
6137  if (!NT_SUCCESS(Status))
6138  {
6139  goto Cleanup;
6140  }
6141  }
6142 
6143  /* Capture the token primary group SID */
6144  Status = SepCaptureSid(PrimaryGroupSid,
6145  PreviousMode,
6146  PagedPool,
6147  FALSE,
6148  &CapturedPrimaryGroupSid);
6149  if (!NT_SUCCESS(Status))
6150  {
6151  goto Cleanup;
6152  }
6153 
6154  /* Capture DefaultDacl */
6155  if (DefaultDacl != NULL)
6156  {
6157  Status = SepCaptureAcl(DefaultDacl,
6158  PreviousMode,
6159  NonPagedPool,
6160  FALSE,
6161  &CapturedDefaultDacl);
6162  if (!NT_SUCCESS(Status))
6163  {
6164  goto Cleanup;
6165  }
6166  }
6167 
6168  /* Call the internal function */
6169  Status = SepCreateToken(&hToken,
6170  PreviousMode,
6171  DesiredAccess,
6173  TokenType,
6174  LocalSecurityQos.ImpersonationLevel,
6175  &LocalAuthenticationId,
6176  &LocalExpirationTime,
6177  CapturedUser,
6178  GroupCount,
6179  CapturedGroups,
6180  GroupsLength,
6181  PrivilegeCount,
6182  CapturedPrivileges,
6183  CapturedOwnerSid,
6184  CapturedPrimaryGroupSid,
6185  CapturedDefaultDacl,
6186  &LocalTokenSource,
6187  FALSE);
6188  if (NT_SUCCESS(Status))
6189  {
6190  _SEH2_TRY
6191  {
6192  *TokenHandle = hToken;
6193  }
6195  {
6197  }
6198  _SEH2_END;
6199  }
6200 
6201 Cleanup:
6202 
6203  /* Release what we captured */
6206  SeReleaseLuidAndAttributesArray(CapturedPrivileges, PreviousMode, FALSE);
6207  SepReleaseSid(CapturedOwnerSid, PreviousMode, FALSE);
6208  SepReleaseSid(CapturedPrimaryGroupSid, PreviousMode, FALSE);
6209  SepReleaseAcl(CapturedDefaultDacl, PreviousMode, FALSE);
6210 
6211  return Status;
6212 }
6213 
6241 NTSTATUS
6242 NTAPI
6244  _In_ HANDLE ThreadHandle,