ReactOS  0.4.15-dev-3297-g037c744
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 VariableLength;
1008  ULONG TotalSize;
1009  ULONG PrivilegesIndex, GroupsIndex;
1010 
1011  PAGED_CODE();
1012 
1013  /* Compute how much size we need to allocate for the token */
1014  VariableLength = Token->VariableLength;
1015  TotalSize = FIELD_OFFSET(TOKEN, VariablePart) + VariableLength;
1016 
1020  PreviousMode,
1021  NULL,
1022  TotalSize,
1023  0,
1024  0,
1025  (PVOID*)&AccessToken);
1026  if (!NT_SUCCESS(Status))
1027  {
1028  DPRINT1("ObCreateObject() failed (Status 0x%lx)\n", Status);
1029  return Status;
1030  }
1031 
1032  /* Zero out the buffer and initialize the token */
1033  RtlZeroMemory(AccessToken, TotalSize);
1034 
1035  ExAllocateLocallyUniqueId(&AccessToken->TokenId);
1036 
1037  AccessToken->TokenType = TokenType;
1038  AccessToken->ImpersonationLevel = Level;
1039 
1040  /* Initialise the lock for the access token */
1041  Status = SepCreateTokenLock(AccessToken);
1042  if (!NT_SUCCESS(Status))
1043  {
1044  ObDereferenceObject(AccessToken);
1045  return Status;
1046  }
1047 
1048  /* Copy the immutable fields */
1049  RtlCopyLuid(&AccessToken->TokenSource.SourceIdentifier,
1050  &Token->TokenSource.SourceIdentifier);
1051  RtlCopyMemory(AccessToken->TokenSource.SourceName,
1052  Token->TokenSource.SourceName,
1053  sizeof(Token->TokenSource.SourceName));
1054 
1055  AccessToken->AuthenticationId = Token->AuthenticationId;
1056  AccessToken->ParentTokenId = Token->ParentTokenId;
1057  AccessToken->ExpirationTime = Token->ExpirationTime;
1058  AccessToken->OriginatingLogonSession = Token->OriginatingLogonSession;
1059 
1060  /* Lock the source token and copy the mutable fields */
1062 
1063  AccessToken->SessionId = Token->SessionId;
1064  RtlCopyLuid(&AccessToken->ModifiedId, &Token->ModifiedId);
1065 
1066  AccessToken->TokenFlags = Token->TokenFlags & ~TOKEN_SESSION_NOT_REFERENCED;
1067 
1068  /* Reference the logon session */
1069  Status = SepRmReferenceLogonSession(&AccessToken->AuthenticationId);
1070  if (!NT_SUCCESS(Status))
1071  {
1072  /* No logon session could be found, bail out */
1073  DPRINT1("SepRmReferenceLogonSession() failed (Status 0x%lx)\n", Status);
1074  /* Set the flag for proper cleanup by the delete procedure */
1075  AccessToken->TokenFlags |= TOKEN_SESSION_NOT_REFERENCED;
1076  goto Quit;
1077  }
1078 
1079  /* Insert the referenced logon session into the token */
1081  if (!NT_SUCCESS(Status))
1082  {
1083  /* Failed to insert the logon session into the token, bail out */
1084  DPRINT1("SepRmInsertLogonSessionIntoToken() failed (Status 0x%lx)\n", Status);
1085  goto Quit;
1086  }
1087 
1088  /* Assign the data that reside in the TOKEN's variable information area */
1089  AccessToken->VariableLength = VariableLength;
1090  EndMem = (PVOID)&AccessToken->VariablePart;
1091 
1092  /* Copy the privileges */
1093  AccessToken->PrivilegeCount = 0;
1094  AccessToken->Privileges = NULL;
1095  if (Token->Privileges && (Token->PrivilegeCount > 0))
1096  {
1097  ULONG PrivilegesLength = Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
1098  PrivilegesLength = ALIGN_UP_BY(PrivilegesLength, sizeof(PVOID));
1099 
1100  ASSERT(VariableLength >= PrivilegesLength);
1101 
1102  AccessToken->PrivilegeCount = Token->PrivilegeCount;
1103  AccessToken->Privileges = EndMem;
1104  EndMem = (PVOID)((ULONG_PTR)EndMem + PrivilegesLength);
1105  VariableLength -= PrivilegesLength;
1106 
1107  RtlCopyMemory(AccessToken->Privileges,
1108  Token->Privileges,
1109  AccessToken->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
1110  }
1111 
1112  /* Copy the user and groups */
1113  AccessToken->UserAndGroupCount = 0;
1114  AccessToken->UserAndGroups = NULL;
1115  if (Token->UserAndGroups && (Token->UserAndGroupCount > 0))
1116  {
1117  AccessToken->UserAndGroupCount = Token->UserAndGroupCount;
1118  AccessToken->UserAndGroups = EndMem;
1119  EndMem = &AccessToken->UserAndGroups[AccessToken->UserAndGroupCount];
1120  VariableLength -= ((ULONG_PTR)EndMem - (ULONG_PTR)AccessToken->UserAndGroups);
1121 
1122  Status = RtlCopySidAndAttributesArray(AccessToken->UserAndGroupCount,
1123  Token->UserAndGroups,
1124  VariableLength,
1125  AccessToken->UserAndGroups,
1126  EndMem,
1127  &EndMem,
1128  &VariableLength);
1129  if (!NT_SUCCESS(Status))
1130  {
1131  DPRINT1("RtlCopySidAndAttributesArray(UserAndGroups) failed (Status 0x%lx)\n", Status);
1132  goto Quit;
1133  }
1134  }
1135 
1136 #if 1
1137  {
1138  ULONG PrimaryGroupIndex;
1139 
1140  /* Find the token primary group */
1142  Token->PrimaryGroup,
1143  NULL,
1144  &PrimaryGroupIndex,
1145  NULL);
1146  if (!NT_SUCCESS(Status))
1147  {
1148  DPRINT1("SepFindPrimaryGroupAndDefaultOwner failed (Status 0x%lx)\n", Status);
1149  goto Quit;
1150  }
1151  AccessToken->PrimaryGroup = AccessToken->UserAndGroups[PrimaryGroupIndex].Sid;
1152  }
1153 #else
1154  AccessToken->PrimaryGroup = (PVOID)((ULONG_PTR)AccessToken + (ULONG_PTR)Token->PrimaryGroup - (ULONG_PTR)Token->UserAndGroups);
1155 #endif
1156  AccessToken->DefaultOwnerIndex = Token->DefaultOwnerIndex;
1157 
1158  /* Copy the restricted SIDs */
1159  AccessToken->RestrictedSidCount = 0;
1160  AccessToken->RestrictedSids = NULL;
1161  if (Token->RestrictedSids && (Token->RestrictedSidCount > 0))
1162  {
1163  AccessToken->RestrictedSidCount = Token->RestrictedSidCount;
1164  AccessToken->RestrictedSids = EndMem;
1165  EndMem = &AccessToken->RestrictedSids[AccessToken->RestrictedSidCount];
1166  VariableLength -= ((ULONG_PTR)EndMem - (ULONG_PTR)AccessToken->RestrictedSids);
1167 
1168  Status = RtlCopySidAndAttributesArray(AccessToken->RestrictedSidCount,
1169  Token->RestrictedSids,
1170  VariableLength,
1171  AccessToken->RestrictedSids,
1172  EndMem,
1173  &EndMem,
1174  &VariableLength);
1175  if (!NT_SUCCESS(Status))
1176  {
1177  DPRINT1("RtlCopySidAndAttributesArray(RestrictedSids) failed (Status 0x%lx)\n", Status);
1178  goto Quit;
1179  }
1180  }
1181 
1182  /*
1183  * Filter the token by removing the disabled privileges
1184  * and groups if the caller wants to duplicate an access
1185  * token as effective only.
1186  */
1187  if (EffectiveOnly)
1188  {
1189  /* Begin querying the groups and search for disabled ones */
1190  for (GroupsIndex = 0; GroupsIndex < AccessToken->UserAndGroupCount; GroupsIndex++)
1191  {
1192  /*
1193  * A group or user is considered disabled if its attributes is either
1194  * 0 or SE_GROUP_ENABLED is not included in the attributes flags list.
1195  * That is because a certain user and/or group can have several attributes
1196  * that bear no influence on whether a user/group is enabled or not
1197  * (SE_GROUP_ENABLED_BY_DEFAULT for example which is a mere indicator
1198  * that the group has just been enabled by default). A mandatory
1199  * group (that is, the group has SE_GROUP_MANDATORY attribute)
1200  * by standards it's always enabled and no one can disable it.
1201  */
1202  if (AccessToken->UserAndGroups[GroupsIndex].Attributes == 0 ||
1203  (AccessToken->UserAndGroups[GroupsIndex].Attributes & SE_GROUP_ENABLED) == 0)
1204  {
1205  /*
1206  * A group is not enabled, it's time to remove
1207  * from the token and update the groups index
1208  * accordingly and continue with the next group.
1209  */
1210  SepRemoveUserGroupToken(AccessToken, GroupsIndex);
1211  GroupsIndex--;
1212  }
1213  }
1214 
1215  /* Begin querying the privileges and search for disabled ones */
1216  for (PrivilegesIndex = 0; PrivilegesIndex < AccessToken->PrivilegeCount; PrivilegesIndex++)
1217  {
1218  /*
1219  * A privilege is considered disabled if its attributes is either
1220  * 0 or SE_PRIVILEGE_ENABLED is not included in the attributes flags list.
1221  * That is because a certain privilege can have several attributes
1222  * that bear no influence on whether a privilege is enabled or not
1223  * (SE_PRIVILEGE_ENABLED_BY_DEFAULT for example which is a mere indicator
1224  * that the privilege has just been enabled by default).
1225  */
1226  if (AccessToken->Privileges[PrivilegesIndex].Attributes == 0 ||
1227  (AccessToken->Privileges[PrivilegesIndex].Attributes & SE_PRIVILEGE_ENABLED) == 0)
1228  {
1229  /*
1230  * A privilege is not enabled, therefor it's time
1231  * to strip it from the token and continue with the next
1232  * privilege. Of course we must also want to update the
1233  * privileges index accordingly.
1234  */
1235  SepRemovePrivilegeToken(AccessToken, PrivilegesIndex);
1236  PrivilegesIndex--;
1237  }
1238  }
1239  }
1240 
1241  //
1242  // NOTE: So far our dynamic area only contains
1243  // the default dacl, so this makes the following
1244  // code pretty simple. The day where it stores
1245  // other data, the code will require adaptations.
1246  //
1247 
1248  /* Now allocate the TOKEN's dynamic information area and set the data */
1249  AccessToken->DynamicAvailable = 0; // Unused memory in the dynamic area.
1250  AccessToken->DynamicPart = NULL;
1251  if (Token->DynamicPart && Token->DefaultDacl)
1252  {
1253  AccessToken->DynamicPart = ExAllocatePoolWithTag(PagedPool,
1254  Token->DefaultDacl->AclSize,
1256  if (AccessToken->DynamicPart == NULL)
1257  {
1259  goto Quit;
1260  }
1261  EndMem = (PVOID)AccessToken->DynamicPart;
1262 
1263  AccessToken->DefaultDacl = EndMem;
1264 
1265  RtlCopyMemory(AccessToken->DefaultDacl,
1266  Token->DefaultDacl,
1267  Token->DefaultDacl->AclSize);
1268  }
1269 
1270  /* Unlock the source token */
1272 
1273  /* Return the token */
1274  *NewAccessToken = AccessToken;
1276 
1277 Quit:
1278  if (!NT_SUCCESS(Status))
1279  {
1280  /* Unlock the source token */
1282 
1283  /* Dereference the token, the delete procedure will clean it up */
1284  ObDereferenceObject(AccessToken);
1285  }
1286 
1287  return Status;
1288 }
1289 
1311 NTSTATUS
1312 NTAPI
1314  _In_ PTOKEN ParentToken,
1315  _Out_ PTOKEN *Token,
1316  _In_ BOOLEAN InUse,
1318 {
1319  PTOKEN NewToken;
1321  NTSTATUS Status;
1322 
1323  /* Initialize the attributes and duplicate it */
1325  Status = SepDuplicateToken(ParentToken,
1327  FALSE,
1328  TokenPrimary,
1329  ParentToken->ImpersonationLevel,
1330  KernelMode,
1331  &NewToken);
1332  if (NT_SUCCESS(Status))
1333  {
1334  /* Insert it */
1335  Status = ObInsertObject(NewToken,
1336  NULL,
1337  0,
1338  0,
1339  NULL,
1340  NULL);
1341  if (NT_SUCCESS(Status))
1342  {
1343  /* Set the session ID */
1344  NewToken->SessionId = SessionId;
1345  NewToken->TokenInUse = InUse;
1346 
1347  /* Return the token */
1348  *Token = NewToken;
1349  }
1350  }
1351 
1352  /* Return status */
1353  return Status;
1354 }
1355 
1371 NTSTATUS
1372 NTAPI
1374  _In_ PTOKEN Token,
1376 {
1377  PTOKEN ProcessToken;
1378  LUID ProcessTokenId, CallerParentId;
1379 
1380  /* Assume failure */
1381  *IsChild = FALSE;
1382 
1383  /* Reference the process token */
1384  ProcessToken = PsReferencePrimaryToken(PsGetCurrentProcess());
1385  if (!ProcessToken)
1386  return STATUS_UNSUCCESSFUL;
1387 
1388  /* Get its token ID */
1389  ProcessTokenId = ProcessToken->TokenId;
1390 
1391  /* Dereference the token */
1393 
1394  /* Get our parent token ID */
1395  CallerParentId = Token->ParentTokenId;
1396 
1397  /* Compare the token IDs */
1398  if (RtlEqualLuid(&CallerParentId, &ProcessTokenId))
1399  *IsChild = TRUE;
1400 
1401  /* Return success */
1402  return STATUS_SUCCESS;
1403 }
1404 
1420 NTSTATUS
1421 NTAPI
1423  _In_ PTOKEN Token,
1424  _Out_ PBOOLEAN IsSibling)
1425 {
1426  PTOKEN ProcessToken;
1427  LUID ProcessParentId, ProcessAuthId;
1428  LUID CallerParentId, CallerAuthId;
1429 
1430  /* Assume failure */
1431  *IsSibling = FALSE;
1432 
1433  /* Reference the process token */
1434  ProcessToken = PsReferencePrimaryToken(PsGetCurrentProcess());
1435  if (!ProcessToken)
1436  return STATUS_UNSUCCESSFUL;
1437 
1438  /* Get its parent and authentication IDs */
1439  ProcessParentId = ProcessToken->ParentTokenId;
1440  ProcessAuthId = ProcessToken->AuthenticationId;
1441 
1442  /* Dereference the token */
1444 
1445  /* Get our parent and authentication IDs */
1446  CallerParentId = Token->ParentTokenId;
1447  CallerAuthId = Token->AuthenticationId;
1448 
1449  /* Compare the token IDs */
1450  if (RtlEqualLuid(&CallerParentId, &ProcessParentId) &&
1451  RtlEqualLuid(&CallerAuthId, &ProcessAuthId))
1452  {
1453  *IsSibling = TRUE;
1454  }
1455 
1456  /* Return success */
1457  return STATUS_SUCCESS;
1458 }
1459 
1480 NTSTATUS
1481 NTAPI
1486  _Out_ PACCESS_TOKEN* NewToken)
1487 {
1488  NTSTATUS Status;
1490 
1491  PAGED_CODE();
1492 
1494  NULL,
1495  0,
1496  NULL,
1497  NULL);
1498 
1501  FALSE,
1503  Level,
1504  PreviousMode,
1505  (PTOKEN*)NewToken);
1506 
1507  return Status;
1508 }
1509 
1522 VOID
1523 NTAPI
1525  _In_ PVOID ObjectBody)
1526 {
1527  NTSTATUS Status;
1528  PTOKEN AccessToken = (PTOKEN)ObjectBody;
1529 
1530  DPRINT("SepDeleteToken()\n");
1531 
1532  /* Remove the referenced logon session from token */
1533  if (AccessToken->LogonSession)
1534  {
1536  if (!NT_SUCCESS(Status))
1537  {
1538  /* Something seriously went wrong */
1539  DPRINT1("SepDeleteToken(): Failed to remove the logon session from token (Status: 0x%lx)\n", Status);
1540  return;
1541  }
1542  }
1543 
1544  /* Dereference the logon session */
1545  if ((AccessToken->TokenFlags & TOKEN_SESSION_NOT_REFERENCED) == 0)
1547 
1548  /* Delete the token lock */
1549  if (AccessToken->TokenLock)
1550  SepDeleteTokenLock(AccessToken);
1551 
1552  /* Delete the dynamic information area */
1553  if (AccessToken->DynamicPart)
1555 }
1556 
1565 CODE_SEG("INIT")
1566 VOID
1567 NTAPI
1569 {
1571  OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
1572 
1573  DPRINT("Creating Token Object Type\n");
1574 
1575  /* Initialize the Token type */
1576  RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
1577  RtlInitUnicodeString(&Name, L"Token");
1578  ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
1579  ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK;
1580  ObjectTypeInitializer.SecurityRequired = TRUE;
1581  ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(TOKEN);
1582  ObjectTypeInitializer.GenericMapping = SepTokenMapping;
1583  ObjectTypeInitializer.PoolType = PagedPool;
1584  ObjectTypeInitializer.ValidAccessMask = TOKEN_ALL_ACCESS;
1585  ObjectTypeInitializer.UseDefaultObject = TRUE;
1586  ObjectTypeInitializer.DeleteProcedure = SepDeleteToken;
1587  ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &SeTokenObjectType);
1588 }
1589 
1603 VOID
1604 NTAPI
1607  _In_ PTOKEN Token)
1608 {
1609  PAGED_CODE();
1610 
1611  /* Sanity checks */
1612  ASSERT(Token->TokenType == TokenPrimary);
1613  ASSERT(!Token->TokenInUse);
1614 
1615  /* Clean any previous token */
1616  if (Process->Token.Object) SeDeassignPrimaryToken(Process);
1617 
1618  /* Set the new token */
1620  Token->TokenInUse = TRUE;
1622 }
1623 
1698 NTSTATUS
1699 NTAPI
1707  _In_ PLUID AuthenticationId,
1708  _In_ PLARGE_INTEGER ExpirationTime,
1710  _In_ ULONG GroupCount,
1712  _In_ ULONG GroupsLength,
1713  _In_ ULONG PrivilegeCount,
1717  _In_opt_ PACL DefaultDacl,
1719  _In_ BOOLEAN SystemToken)
1720 {
1721  NTSTATUS Status;
1722  PTOKEN AccessToken;
1723  ULONG TokenFlags = 0;
1724  ULONG PrimaryGroupIndex, DefaultOwnerIndex;
1725  LUID TokenId;
1726  LUID ModifiedId;
1727  PVOID EndMem;
1728  ULONG PrivilegesLength;
1729  ULONG UserGroupsLength;
1730  ULONG VariableLength;
1731  ULONG TotalSize;
1732  ULONG i;
1733 
1734  PAGED_CODE();
1735 
1736  /* Loop all groups */
1737  for (i = 0; i < GroupCount; i++)
1738  {
1739  /* Check for mandatory groups */
1741  {
1742  /* Force them to be enabled */
1744  }
1745 
1746  /* Check of the group is an admin group */
1748  {
1749  /* Remember this so we can optimize queries later */
1750  TokenFlags |= TOKEN_HAS_ADMIN_GROUP;
1751  }
1752  }
1753 
1754  /* Allocate unique IDs for the token */
1755  ExAllocateLocallyUniqueId(&TokenId);
1756  ExAllocateLocallyUniqueId(&ModifiedId);
1757 
1758  /* Compute how much size we need to allocate for the token */
1759 
1760  /* Privileges size */
1761  PrivilegesLength = PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
1762  PrivilegesLength = ALIGN_UP_BY(PrivilegesLength, sizeof(PVOID));
1763 
1764  /* User and groups size */
1765  UserGroupsLength = (1 + GroupCount) * sizeof(SID_AND_ATTRIBUTES);
1766  UserGroupsLength += RtlLengthSid(User->Sid);
1767  for (i = 0; i < GroupCount; i++)
1768  {
1769  UserGroupsLength += RtlLengthSid(Groups[i].Sid);
1770  }
1771  UserGroupsLength = ALIGN_UP_BY(UserGroupsLength, sizeof(PVOID));
1772 
1773  /* Add the additional groups array length */
1774  UserGroupsLength += ALIGN_UP_BY(GroupsLength, sizeof(PVOID));
1775 
1776  VariableLength = PrivilegesLength + UserGroupsLength;
1777  TotalSize = FIELD_OFFSET(TOKEN, VariablePart) + VariableLength;
1778 
1782  PreviousMode,
1783  NULL,
1784  TotalSize,
1785  0,
1786  0,
1787  (PVOID*)&AccessToken);
1788  if (!NT_SUCCESS(Status))
1789  {
1790  DPRINT1("ObCreateObject() failed (Status 0x%lx)\n", Status);
1791  return Status;
1792  }
1793 
1794  /* Zero out the buffer and initialize the token */
1795  RtlZeroMemory(AccessToken, TotalSize);
1796 
1797  RtlCopyLuid(&AccessToken->TokenId, &TokenId);
1798 
1799  AccessToken->TokenType = TokenType;
1800  AccessToken->ImpersonationLevel = ImpersonationLevel;
1801 
1802  /* Initialise the lock for the access token */
1803  Status = SepCreateTokenLock(AccessToken);
1804  if (!NT_SUCCESS(Status))
1805  goto Quit;
1806 
1807  RtlCopyLuid(&AccessToken->TokenSource.SourceIdentifier,
1808  &TokenSource->SourceIdentifier);
1809  RtlCopyMemory(AccessToken->TokenSource.SourceName,
1810  TokenSource->SourceName,
1811  sizeof(TokenSource->SourceName));
1812 
1813  AccessToken->ExpirationTime = *ExpirationTime;
1814  RtlCopyLuid(&AccessToken->ModifiedId, &ModifiedId);
1815 
1816  AccessToken->TokenFlags = TokenFlags & ~TOKEN_SESSION_NOT_REFERENCED;
1817 
1818  /* Copy and reference the logon session */
1819  RtlCopyLuid(&AccessToken->AuthenticationId, AuthenticationId);
1820  Status = SepRmReferenceLogonSession(&AccessToken->AuthenticationId);
1821  if (!NT_SUCCESS(Status))
1822  {
1823  /* No logon session could be found, bail out */
1824  DPRINT1("SepRmReferenceLogonSession() failed (Status 0x%lx)\n", Status);
1825  /* Set the flag for proper cleanup by the delete procedure */
1826  AccessToken->TokenFlags |= TOKEN_SESSION_NOT_REFERENCED;
1827  goto Quit;
1828  }
1829 
1830  /* Insert the referenced logon session into the token */
1832  if (!NT_SUCCESS(Status))
1833  {
1834  /* Failed to insert the logon session into the token, bail out */
1835  DPRINT1("SepRmInsertLogonSessionIntoToken() failed (Status 0x%lx)\n", Status);
1836  goto Quit;
1837  }
1838 
1839  /* Assign the data that reside in the TOKEN's variable information area */
1840  AccessToken->VariableLength = VariableLength;
1841  EndMem = (PVOID)&AccessToken->VariablePart;
1842 
1843  /* Copy the privileges */
1844  AccessToken->PrivilegeCount = PrivilegeCount;
1845  AccessToken->Privileges = NULL;
1846  if (PrivilegeCount > 0)
1847  {
1848  AccessToken->Privileges = EndMem;
1849  EndMem = (PVOID)((ULONG_PTR)EndMem + PrivilegesLength);
1850  VariableLength -= PrivilegesLength;
1851 
1852  if (PreviousMode != KernelMode)
1853  {
1854  _SEH2_TRY
1855  {
1856  RtlCopyMemory(AccessToken->Privileges,
1857  Privileges,
1858  PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
1859  }
1861  {
1863  }
1864  _SEH2_END;
1865  }
1866  else
1867  {
1868  RtlCopyMemory(AccessToken->Privileges,
1869  Privileges,
1870  PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
1871  }
1872 
1873  if (!NT_SUCCESS(Status))
1874  goto Quit;
1875  }
1876 
1877  /* Update the privilege flags */
1878  SepUpdatePrivilegeFlagsToken(AccessToken);
1879 
1880  /* Copy the user and groups */
1881  AccessToken->UserAndGroupCount = 1 + GroupCount;
1882  AccessToken->UserAndGroups = EndMem;
1883  EndMem = &AccessToken->UserAndGroups[AccessToken->UserAndGroupCount];
1884  VariableLength -= ((ULONG_PTR)EndMem - (ULONG_PTR)AccessToken->UserAndGroups);
1885 
1887  User,
1888  VariableLength,
1889  &AccessToken->UserAndGroups[0],
1890  EndMem,
1891  &EndMem,
1892  &VariableLength);
1893  if (!NT_SUCCESS(Status))
1894  goto Quit;
1895 
1896  Status = RtlCopySidAndAttributesArray(GroupCount,
1897  Groups,
1898  VariableLength,
1899  &AccessToken->UserAndGroups[1],
1900  EndMem,
1901  &EndMem,
1902  &VariableLength);
1903  if (!NT_SUCCESS(Status))
1904  goto Quit;
1905 
1906  /* Find the token primary group and default owner */
1908  PrimaryGroup,
1909  Owner,
1910  &PrimaryGroupIndex,
1911  &DefaultOwnerIndex);
1912  if (!NT_SUCCESS(Status))
1913  {
1914  DPRINT1("SepFindPrimaryGroupAndDefaultOwner failed (Status 0x%lx)\n", Status);
1915  goto Quit;
1916  }
1917 
1918  AccessToken->PrimaryGroup = AccessToken->UserAndGroups[PrimaryGroupIndex].Sid;
1919  AccessToken->DefaultOwnerIndex = DefaultOwnerIndex;
1920 
1921  /* Now allocate the TOKEN's dynamic information area and set the data */
1922  AccessToken->DynamicAvailable = 0; // Unused memory in the dynamic area.
1923  AccessToken->DynamicPart = NULL;
1924  if (DefaultDacl != NULL)
1925  {
1926  AccessToken->DynamicPart = ExAllocatePoolWithTag(PagedPool,
1927  DefaultDacl->AclSize,
1929  if (AccessToken->DynamicPart == NULL)
1930  {
1932  goto Quit;
1933  }
1934  EndMem = (PVOID)AccessToken->DynamicPart;
1935 
1936  AccessToken->DefaultDacl = EndMem;
1937 
1938  RtlCopyMemory(AccessToken->DefaultDacl,
1939  DefaultDacl,
1940  DefaultDacl->AclSize);
1941  }
1942 
1943  /* Insert the token only if it's not the system token, otherwise return it directly */
1944  if (!SystemToken)
1945  {
1946  Status = ObInsertObject(AccessToken,
1947  NULL,
1948  DesiredAccess,
1949  0,
1950  NULL,
1951  TokenHandle);
1952  if (!NT_SUCCESS(Status))
1953  {
1954  DPRINT1("ObInsertObject() failed (Status 0x%lx)\n", Status);
1955  }
1956  }
1957  else
1958  {
1959  /* Return pointer instead of handle */
1960  *TokenHandle = (HANDLE)AccessToken;
1961  }
1962 
1963 Quit:
1964  if (!NT_SUCCESS(Status))
1965  {
1966  /* Dereference the token, the delete procedure will clean it up */
1967  ObDereferenceObject(AccessToken);
1968  }
1969 
1970  return Status;
1971 }
1972 
1981 CODE_SEG("INIT")
1982 PTOKEN
1983 NTAPI
1985 {
1987  ULONG GroupAttributes, OwnerAttributes;
1989  LARGE_INTEGER Expiration;
1990  SID_AND_ATTRIBUTES UserSid;
1991  ULONG GroupsLength;
1994  PSID Owner;
1995  ULONG i;
1996  PTOKEN Token;
1997  NTSTATUS Status;
1998 
1999  /* Don't ever expire */
2000  Expiration.QuadPart = -1;
2001 
2002  /* All groups mandatory and enabled */
2005 
2006  /* User is Local System */
2007  UserSid.Sid = SeLocalSystemSid;
2008  UserSid.Attributes = 0;
2009 
2010  /* Primary group is Local System */
2012 
2013  /* Owner is Administrators */
2015 
2016  /* Groups are Administrators, World, and Authenticated Users */
2017  Groups[0].Sid = SeAliasAdminsSid;
2018  Groups[0].Attributes = OwnerAttributes;
2019  Groups[1].Sid = SeWorldSid;
2020  Groups[1].Attributes = GroupAttributes;
2022  Groups[2].Attributes = GroupAttributes;
2023  GroupsLength = sizeof(SID_AND_ATTRIBUTES) +
2024  SeLengthSid(Groups[0].Sid) +
2025  SeLengthSid(Groups[1].Sid) +
2026  SeLengthSid(Groups[2].Sid);
2027  ASSERT(GroupsLength <= sizeof(Groups));
2028 
2029  /* Setup the privileges */
2030  i = 0;
2032  Privileges[i++].Luid = SeTcbPrivilege;
2033 
2034  Privileges[i].Attributes = 0;
2036 
2037  Privileges[i].Attributes = 0;
2039 
2042 
2045 
2046  Privileges[i].Attributes = 0;
2048 
2049  Privileges[i].Attributes = 0;
2051 
2054 
2057 
2059  Privileges[i++].Luid = SeDebugPrivilege;
2060 
2062  Privileges[i++].Luid = SeAuditPrivilege;
2063 
2064  Privileges[i].Attributes = 0;
2065  Privileges[i++].Luid = SeSecurityPrivilege;
2066 
2067  Privileges[i].Attributes = 0;
2069 
2072 
2073  Privileges[i].Attributes = 0;
2074  Privileges[i++].Luid = SeBackupPrivilege;
2075 
2076  Privileges[i].Attributes = 0;
2077  Privileges[i++].Luid = SeRestorePrivilege;
2078 
2079  Privileges[i].Attributes = 0;
2080  Privileges[i++].Luid = SeShutdownPrivilege;
2081 
2082  Privileges[i].Attributes = 0;
2084 
2087 
2088  Privileges[i].Attributes = 0;
2090  ASSERT(i == 20);
2091 
2092  /* Setup the object attributes */
2095 
2096  /* Create the token */
2098  KernelMode,
2099  0,
2101  TokenPrimary,
2104  &Expiration,
2105  &UserSid,
2106  3,
2107  Groups,
2108  GroupsLength,
2109  20,
2110  Privileges,
2111  Owner,
2112  PrimaryGroup,
2115  TRUE);
2117 
2118  /* Return the token */
2119  return Token;
2120 }
2121 
2132 CODE_SEG("INIT")
2133 PTOKEN
2135 {
2136  SID_AND_ATTRIBUTES Groups[32], UserSid;
2138  PTOKEN Token;
2139  ULONG GroupsLength;
2140  LARGE_INTEGER Expiration;
2142  NTSTATUS Status;
2143 
2144  /* The token never expires */
2145  Expiration.QuadPart = -1;
2146 
2147  /* The user is the anonymous logon */
2148  UserSid.Sid = SeAnonymousLogonSid;
2149  UserSid.Attributes = 0;
2150 
2151  /* The primary group is also the anonymous logon */
2153 
2154  /* The only group for the token is the World */
2155  Groups[0].Sid = SeWorldSid;
2157  GroupsLength = sizeof(SID_AND_ATTRIBUTES) +
2158  SeLengthSid(Groups[0].Sid);
2159  ASSERT(GroupsLength <= sizeof(Groups));
2160 
2161  /* Initialise the object attributes for the token */
2164 
2165  /* Create token */
2167  KernelMode,
2168  0,
2170  TokenPrimary,
2173  &Expiration,
2174  &UserSid,
2175  1,
2176  Groups,
2177  GroupsLength,
2178  0,
2179  NULL,
2180  NULL,
2181  PrimaryGroup,
2184  TRUE);
2186 
2187  /* Return the anonymous logon token */
2188  return Token;
2189 }
2190 
2200 CODE_SEG("INIT")
2201 PTOKEN
2203 {
2204  SID_AND_ATTRIBUTES UserSid;
2206  PTOKEN Token;
2207  LARGE_INTEGER Expiration;
2209  NTSTATUS Status;
2210 
2211  /* The token never expires */
2212  Expiration.QuadPart = -1;
2213 
2214  /* The user is the anonymous logon */
2215  UserSid.Sid = SeAnonymousLogonSid;
2216  UserSid.Attributes = 0;
2217 
2218  /* The primary group is also the anonymous logon */
2220 
2221  /* Initialise the object attributes for the token */
2224 
2225  /* Create token */
2227  KernelMode,
2228  0,
2230  TokenPrimary,
2233  &Expiration,
2234  &UserSid,
2235  0,
2236  NULL,
2237  0,
2238  0,
2239  NULL,
2240  NULL,
2241  PrimaryGroup,
2244  TRUE);
2246 
2247  /* Return the anonymous (not including everyone) logon token */
2248  return Token;
2249 }
2250 
2251 /* PUBLIC FUNCTIONS ***********************************************************/
2252 
2281 NTSTATUS
2282 NTAPI
2284  _In_ PACCESS_TOKEN ExistingToken,
2285  _In_ ULONG Flags,
2286  _In_opt_ PTOKEN_GROUPS SidsToDisable,
2287  _In_opt_ PTOKEN_PRIVILEGES PrivilegesToDelete,
2288  _In_opt_ PTOKEN_GROUPS RestrictedSids,
2289  _Out_ PACCESS_TOKEN * FilteredToken)
2290 {
2291  UNIMPLEMENTED;
2292  return STATUS_NOT_IMPLEMENTED;
2293 }
2294 
2326 NTSTATUS
2327 NTAPI
2329  _In_ PACCESS_TOKEN AccessToken,
2331  _Outptr_result_buffer_(_Inexpressible_(token-dependent)) PVOID *TokenInformation)
2332 {
2333  NTSTATUS Status;
2334  PTOKEN Token = (PTOKEN)AccessToken;
2336  union
2337  {
2338  PSID PSid;
2339  ULONG Ulong;
2340  } Unused;
2341 
2342  PAGED_CODE();
2343 
2344  /* Lock the token */
2346 
2347  switch (TokenInformationClass)
2348  {
2349  case TokenUser:
2350  {
2351  PTOKEN_USER tu;
2352 
2353  DPRINT("SeQueryInformationToken(TokenUser)\n");
2354  RequiredLength = sizeof(TOKEN_USER) +
2355  RtlLengthSid(Token->UserAndGroups[0].Sid);
2356 
2357  /* Allocate the output buffer */
2359  if (tu == NULL)
2360  {
2362  break;
2363  }
2364 
2366  &Token->UserAndGroups[0],
2367  RequiredLength - sizeof(TOKEN_USER),
2368  &tu->User,
2369  (PSID)(tu + 1),
2370  &Unused.PSid,
2371  &Unused.Ulong);
2372 
2373  /* Return the structure */
2374  *TokenInformation = tu;
2376  break;
2377  }
2378 
2379  case TokenGroups:
2380  {
2381  PTOKEN_GROUPS tg;
2382  ULONG SidLen;
2383  PSID Sid;
2384 
2385  DPRINT("SeQueryInformationToken(TokenGroups)\n");
2386  RequiredLength = sizeof(tg->GroupCount) +
2387  RtlLengthSidAndAttributes(Token->UserAndGroupCount - 1, &Token->UserAndGroups[1]);
2388 
2389  SidLen = RequiredLength - sizeof(tg->GroupCount) -
2390  ((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES));
2391 
2392  /* Allocate the output buffer */
2394  if (tg == NULL)
2395  {
2397  break;
2398  }
2399 
2400  Sid = (PSID)((ULONG_PTR)tg + sizeof(tg->GroupCount) +
2401  ((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES)));
2402 
2403  tg->GroupCount = Token->UserAndGroupCount - 1;
2404  Status = RtlCopySidAndAttributesArray(Token->UserAndGroupCount - 1,
2405  &Token->UserAndGroups[1],
2406  SidLen,
2407  &tg->Groups[0],
2408  Sid,
2409  &Unused.PSid,
2410  &Unused.Ulong);
2411 
2412  /* Return the structure */
2413  *TokenInformation = tg;
2415  break;
2416  }
2417 
2418  case TokenPrivileges:
2419  {
2421 
2422  DPRINT("SeQueryInformationToken(TokenPrivileges)\n");
2423  RequiredLength = sizeof(tp->PrivilegeCount) +
2424  (Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
2425 
2426  /* Allocate the output buffer */
2428  if (tp == NULL)
2429  {
2431  break;
2432  }
2433 
2434  tp->PrivilegeCount = Token->PrivilegeCount;
2435  RtlCopyLuidAndAttributesArray(Token->PrivilegeCount,
2436  Token->Privileges,
2437  &tp->Privileges[0]);
2438 
2439  /* Return the structure */
2440  *TokenInformation = tp;
2442  break;
2443  }
2444 
2445  case TokenOwner:
2446  {
2447  PTOKEN_OWNER to;
2448  ULONG SidLen;
2449 
2450  DPRINT("SeQueryInformationToken(TokenOwner)\n");
2451  SidLen = RtlLengthSid(Token->UserAndGroups[Token->DefaultOwnerIndex].Sid);
2452  RequiredLength = sizeof(TOKEN_OWNER) + SidLen;
2453 
2454  /* Allocate the output buffer */
2456  if (to == NULL)
2457  {
2459  break;
2460  }
2461 
2462  to->Owner = (PSID)(to + 1);
2463  Status = RtlCopySid(SidLen,
2464  to->Owner,
2465  Token->UserAndGroups[Token->DefaultOwnerIndex].Sid);
2466 
2467  /* Return the structure */
2468  *TokenInformation = to;
2470  break;
2471  }
2472 
2473  case TokenPrimaryGroup:
2474  {
2476  ULONG SidLen;
2477 
2478  DPRINT("SeQueryInformationToken(TokenPrimaryGroup)\n");
2479  SidLen = RtlLengthSid(Token->PrimaryGroup);
2480  RequiredLength = sizeof(TOKEN_PRIMARY_GROUP) + SidLen;
2481 
2482  /* Allocate the output buffer */
2484  if (tpg == NULL)
2485  {
2487  break;
2488  }
2489 
2490  tpg->PrimaryGroup = (PSID)(tpg + 1);
2491  Status = RtlCopySid(SidLen,
2492  tpg->PrimaryGroup,
2493  Token->PrimaryGroup);
2494 
2495  /* Return the structure */
2496  *TokenInformation = tpg;
2498  break;
2499  }
2500 
2501  case TokenDefaultDacl:
2502  {
2503  PTOKEN_DEFAULT_DACL tdd;
2504 
2505  DPRINT("SeQueryInformationToken(TokenDefaultDacl)\n");
2507 
2508  if (Token->DefaultDacl != NULL)
2509  RequiredLength += Token->DefaultDacl->AclSize;
2510 
2511  /* Allocate the output buffer */
2513  if (tdd == NULL)
2514  {
2516  break;
2517  }
2518 
2519  if (Token->DefaultDacl != NULL)
2520  {
2521  tdd->DefaultDacl = (PACL)(tdd + 1);
2523  Token->DefaultDacl,
2524  Token->DefaultDacl->AclSize);
2525  }
2526  else
2527  {
2528  tdd->DefaultDacl = NULL;
2529  }
2530 
2531  /* Return the structure */
2532  *TokenInformation = tdd;
2534  break;
2535  }
2536 
2537  case TokenSource:
2538  {
2539  PTOKEN_SOURCE ts;
2540 
2541  DPRINT("SeQueryInformationToken(TokenSource)\n");
2542  RequiredLength = sizeof(TOKEN_SOURCE);
2543 
2544  /* Allocate the output buffer */
2546  if (ts == NULL)
2547  {
2549  break;
2550  }
2551 
2552  *ts = Token->TokenSource;
2553 
2554  /* Return the structure */
2555  *TokenInformation = ts;
2557  break;
2558  }
2559 
2560  case TokenType:
2561  {
2562  PTOKEN_TYPE tt;
2563 
2564  DPRINT("SeQueryInformationToken(TokenType)\n");
2565  RequiredLength = sizeof(TOKEN_TYPE);
2566 
2567  /* Allocate the output buffer */
2569  if (tt == NULL)
2570  {
2572  break;
2573  }
2574 
2575  *tt = Token->TokenType;
2576 
2577  /* Return the structure */
2578  *TokenInformation = tt;
2580  break;
2581  }
2582 
2584  {
2586 
2587  DPRINT("SeQueryInformationToken(TokenImpersonationLevel)\n");
2589 
2590  /* Fail if the token is not an impersonation token */
2591  if (Token->TokenType != TokenImpersonation)
2592  {
2594  break;
2595  }
2596 
2597  /* Allocate the output buffer */
2599  if (sil == NULL)
2600  {
2602  break;
2603  }
2604 
2605  *sil = Token->ImpersonationLevel;
2606 
2607  /* Return the structure */
2608  *TokenInformation = sil;
2610  break;
2611  }
2612 
2613  case TokenStatistics:
2614  {
2615  PTOKEN_STATISTICS ts;
2616 
2617  DPRINT("SeQueryInformationToken(TokenStatistics)\n");
2618  RequiredLength = sizeof(TOKEN_STATISTICS);
2619 
2620  /* Allocate the output buffer */
2622  if (ts == NULL)
2623  {
2625  break;
2626  }
2627 
2628  ts->TokenId = Token->TokenId;
2629  ts->AuthenticationId = Token->AuthenticationId;
2630  ts->ExpirationTime = Token->ExpirationTime;
2631  ts->TokenType = Token->TokenType;
2632  ts->ImpersonationLevel = Token->ImpersonationLevel;
2633  ts->DynamicCharged = Token->DynamicCharged;
2634  ts->DynamicAvailable = Token->DynamicAvailable;
2635  ts->GroupCount = Token->UserAndGroupCount - 1;
2636  ts->PrivilegeCount = Token->PrivilegeCount;
2637  ts->ModifiedId = Token->ModifiedId;
2638 
2639  /* Return the structure */
2640  *TokenInformation = ts;
2642  break;
2643  }
2644 
2645  case TokenSessionId:
2646  {
2647  DPRINT("SeQueryInformationToken(TokenSessionId)\n");
2648  Status = SeQuerySessionIdToken(Token, (PULONG)TokenInformation);
2649  break;
2650  }
2651 
2652  default:
2653  DPRINT1("SeQueryInformationToken(%d) invalid information class\n", TokenInformationClass);
2655  break;
2656  }
2657 
2658  /* Release the lock of the token */
2660 
2661  return Status;
2662 }
2663 
2677 NTSTATUS
2678 NTAPI
2681  _Out_ PULONG pSessionId)
2682 {
2683  PAGED_CODE();
2684 
2685  /* Lock the token */
2687 
2688  *pSessionId = ((PTOKEN)Token)->SessionId;
2689 
2690  /* Unlock the token */
2692 
2693  return STATUS_SUCCESS;
2694 }
2695 
2709 NTSTATUS
2710 NTAPI
2714 {
2715  PAGED_CODE();
2716 
2717  *LogonId = ((PTOKEN)Token)->AuthenticationId;
2718 
2719  return STATUS_SUCCESS;
2720 }
2721 
2733 NTAPI
2736 {
2737  PAGED_CODE();
2738 
2739  return ((PTOKEN)Token)->ImpersonationLevel;
2740 }
2741 
2753 TOKEN_TYPE
2754 NTAPI
2757 {
2758  PAGED_CODE();
2759 
2760  return ((PTOKEN)Token)->TokenType;
2761 }
2762 
2776 BOOLEAN
2777 NTAPI
2780 {
2781  PAGED_CODE();
2782 
2783  // NOTE: Win7+ instead really checks the list of groups in the token
2784  // (since TOKEN_HAS_ADMIN_GROUP == TOKEN_WRITE_RESTRICTED ...)
2785  return (((PTOKEN)Token)->TokenFlags & TOKEN_HAS_ADMIN_GROUP) != 0;
2786 }
2787 
2799 BOOLEAN
2800 NTAPI
2803 {
2804  PAGED_CODE();
2805 
2806  return (((PTOKEN)Token)->TokenFlags & TOKEN_IS_RESTRICTED) != 0;
2807 }
2808 
2824 BOOLEAN
2825 NTAPI
2828 {
2829  PAGED_CODE();
2830 
2831  // NOTE: NT 5.1 SP2 x86 checks the SE_BACKUP_PRIVILEGES_CHECKED flag
2832  // while Vista+ checks the TOKEN_WRITE_RESTRICTED flag as one expects.
2833  return (((PTOKEN)Token)->TokenFlags & SE_BACKUP_PRIVILEGES_CHECKED) != 0;
2834 }
2835 
2855 BOOLEAN
2856 NTAPI
2858  _In_ PTOKEN ProcessToken,
2859  _In_ PTOKEN TokenToImpersonate,
2861 {
2862  BOOLEAN CanImpersonate;
2863  PAGED_CODE();
2864 
2865  /*
2866  * SecurityAnonymous and SecurityIdentification levels do not
2867  * allow impersonation. If we get such levels from the call
2868  * then something's seriously wrong.
2869  */
2872 
2873  /* Time to lock our tokens */
2874  SepAcquireTokenLockShared(ProcessToken);
2875  SepAcquireTokenLockShared(TokenToImpersonate);
2876 
2877  /* What kind of authentication ID does the token have? */
2878  if (RtlEqualLuid(&TokenToImpersonate->AuthenticationId,
2880  {
2881  /*
2882  * OK, it looks like the token has an anonymous
2883  * authentication. Is that token created by the system?
2884  */
2885  if (TokenToImpersonate->TokenSource.SourceName != SeSystemTokenSource.SourceName &&
2886  !RtlEqualLuid(&TokenToImpersonate->TokenSource.SourceIdentifier, &SeSystemTokenSource.SourceIdentifier))
2887  {
2888  /* It isn't, we can't impersonate regular tokens */
2889  DPRINT("SeTokenCanImpersonate(): Token has an anonymous authentication ID, can't impersonate!\n");
2890  CanImpersonate = FALSE;
2891  goto Quit;
2892  }
2893  }
2894 
2895  /* Are the SID values from both tokens equal? */
2896  if (!RtlEqualSid(ProcessToken->UserAndGroups->Sid,
2897  TokenToImpersonate->UserAndGroups->Sid))
2898  {
2899  /* They aren't, bail out */
2900  DPRINT("SeTokenCanImpersonate(): Tokens SIDs are not equal!\n");
2901  CanImpersonate = FALSE;
2902  goto Quit;
2903  }
2904 
2905  /*
2906  * Make sure the tokens aren't diverged in terms of
2907  * restrictions, that is, one token is restricted
2908  * but the other one isn't.
2909  */
2910  if (SeTokenIsRestricted(ProcessToken) !=
2911  SeTokenIsRestricted(TokenToImpersonate))
2912  {
2913  /*
2914  * One token is restricted so we cannot
2915  * continue further at this point, bail out.
2916  */
2917  DPRINT("SeTokenCanImpersonate(): One token is restricted, can't continue!\n");
2918  CanImpersonate = FALSE;
2919  goto Quit;
2920  }
2921 
2922  /* If we've reached that far then we can impersonate! */
2923  DPRINT("SeTokenCanImpersonate(): We can impersonate.\n");
2924  CanImpersonate = TRUE;
2925 
2926 Quit:
2927  /* We're done, unlock the tokens now */
2928  SepReleaseTokenLock(ProcessToken);
2929  SepReleaseTokenLock(TokenToImpersonate);
2930 
2931  return CanImpersonate;
2932 }
2933 
2934 /* SYSTEM CALLS ***************************************************************/
2935 
2970 NTSTATUS
2971 NTAPI
2976  PVOID TokenInformation,
2979 {
2980  NTSTATUS Status;
2982  PTOKEN Token;
2984  union
2985  {
2986  PSID PSid;
2987  ULONG Ulong;
2988  } Unused;
2989 
2990  PAGED_CODE();
2991 
2993 
2994  /* Check buffers and class validity */
2998  TokenInformation,
3000  ReturnLength,
3001  NULL,
3002  PreviousMode,
3003  TRUE);
3004  if (!NT_SUCCESS(Status))
3005  {
3006  DPRINT("NtQueryInformationToken() failed, Status: 0x%x\n", Status);
3007  return Status;
3008  }
3009 
3013  PreviousMode,
3014  (PVOID*)&Token,
3015  NULL);
3016  if (NT_SUCCESS(Status))
3017  {
3018  /* Lock the token */
3020 
3021  switch (TokenInformationClass)
3022  {
3023  case TokenUser:
3024  {
3025  PTOKEN_USER tu = (PTOKEN_USER)TokenInformation;
3026 
3027  DPRINT("NtQueryInformationToken(TokenUser)\n");
3028  RequiredLength = sizeof(TOKEN_USER) +
3029  RtlLengthSid(Token->UserAndGroups[0].Sid);
3030 
3031  _SEH2_TRY
3032  {
3034  {
3036  &Token->UserAndGroups[0],
3037  RequiredLength - sizeof(TOKEN_USER),
3038  &tu->User,
3039  (PSID)(tu + 1),
3040  &Unused.PSid,
3041  &Unused.Ulong);
3042  }
3043  else
3044  {
3046  }
3047 
3048  if (ReturnLength != NULL)
3049  {
3051  }
3052  }
3054  {
3056  }
3057  _SEH2_END;
3058 
3059  break;
3060  }
3061 
3062  case TokenGroups:
3063  {
3064  PTOKEN_GROUPS tg = (PTOKEN_GROUPS)TokenInformation;
3065 
3066  DPRINT("NtQueryInformationToken(TokenGroups)\n");
3067  RequiredLength = sizeof(tg->GroupCount) +
3068  RtlLengthSidAndAttributes(Token->UserAndGroupCount - 1, &Token->UserAndGroups[1]);
3069 
3070  _SEH2_TRY
3071  {
3073  {
3074  ULONG SidLen = RequiredLength - sizeof(tg->GroupCount) -
3075  ((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES));
3076  PSID Sid = (PSID_AND_ATTRIBUTES)((ULONG_PTR)tg + sizeof(tg->GroupCount) +
3077  ((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES)));
3078 
3079  tg->GroupCount = Token->UserAndGroupCount - 1;
3080  Status = RtlCopySidAndAttributesArray(Token->UserAndGroupCount - 1,
3081  &Token->UserAndGroups[1],
3082  SidLen,
3083  &tg->Groups[0],
3084  Sid,
3085  &Unused.PSid,
3086  &Unused.Ulong);
3087  }
3088  else
3089  {
3091  }
3092 
3093  if (ReturnLength != NULL)
3094  {
3096  }
3097  }
3099  {
3101  }
3102  _SEH2_END;
3103 
3104  break;
3105  }
3106 
3107  case TokenPrivileges:
3108  {
3109  PTOKEN_PRIVILEGES tp = (PTOKEN_PRIVILEGES)TokenInformation;
3110 
3111  DPRINT("NtQueryInformationToken(TokenPrivileges)\n");
3112  RequiredLength = sizeof(tp->PrivilegeCount) +
3113  (Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
3114 
3115  _SEH2_TRY
3116  {
3118  {
3119  tp->PrivilegeCount = Token->PrivilegeCount;
3120  RtlCopyLuidAndAttributesArray(Token->PrivilegeCount,
3121  Token->Privileges,
3122  &tp->Privileges[0]);
3123  }
3124  else
3125  {
3127  }
3128 
3129  if (ReturnLength != NULL)
3130  {
3132  }
3133  }
3135  {
3137  }
3138  _SEH2_END;
3139 
3140  break;
3141  }
3142 
3143  case TokenOwner:
3144  {
3145  PTOKEN_OWNER to = (PTOKEN_OWNER)TokenInformation;
3146  ULONG SidLen;
3147 
3148  DPRINT("NtQueryInformationToken(TokenOwner)\n");
3149  SidLen = RtlLengthSid(Token->UserAndGroups[Token->DefaultOwnerIndex].Sid);
3150  RequiredLength = sizeof(TOKEN_OWNER) + SidLen;
3151 
3152  _SEH2_TRY
3153  {
3155  {
3156  to->Owner = (PSID)(to + 1);
3157  Status = RtlCopySid(SidLen,
3158  to->Owner,
3159  Token->UserAndGroups[Token->DefaultOwnerIndex].Sid);
3160  }
3161  else
3162  {
3164  }
3165 
3166  if (ReturnLength != NULL)
3167  {
3169  }
3170  }
3172  {
3174  }
3175  _SEH2_END;
3176 
3177  break;
3178  }
3179 
3180  case TokenPrimaryGroup:
3181  {
3182  PTOKEN_PRIMARY_GROUP tpg = (PTOKEN_PRIMARY_GROUP)TokenInformation;
3183  ULONG SidLen;
3184 
3185  DPRINT("NtQueryInformationToken(TokenPrimaryGroup)\n");
3186  SidLen = RtlLengthSid(Token->PrimaryGroup);
3187  RequiredLength = sizeof(TOKEN_PRIMARY_GROUP) + SidLen;
3188 
3189  _SEH2_TRY
3190  {
3192  {
3193  tpg->PrimaryGroup = (PSID)(tpg + 1);
3194  Status = RtlCopySid(SidLen,
3195  tpg->PrimaryGroup,
3196  Token->PrimaryGroup);
3197  }
3198  else
3199  {
3201  }
3202 
3203  if (ReturnLength != NULL)
3204  {
3206  }
3207  }
3209  {
3211  }
3212  _SEH2_END;
3213 
3214  break;
3215  }
3216 
3217  case TokenDefaultDacl:
3218  {
3219  PTOKEN_DEFAULT_DACL tdd = (PTOKEN_DEFAULT_DACL)TokenInformation;
3220 
3221  DPRINT("NtQueryInformationToken(TokenDefaultDacl)\n");
3223 
3224  if (Token->DefaultDacl != NULL)
3225  RequiredLength += Token->DefaultDacl->AclSize;
3226 
3227  _SEH2_TRY
3228  {
3230  {
3231  if (Token->DefaultDacl != NULL)
3232  {
3233  tdd->DefaultDacl = (PACL)(tdd + 1);
3235  Token->DefaultDacl,
3236  Token->DefaultDacl->AclSize);
3237  }
3238  else
3239  {
3240  tdd->DefaultDacl = NULL;
3241  }
3242  }
3243  else
3244  {
3246  }
3247 
3248  if (ReturnLength != NULL)
3249  {
3251  }
3252  }
3254  {
3256  }
3257  _SEH2_END;
3258 
3259  break;
3260  }
3261 
3262  case TokenSource:
3263  {
3264  PTOKEN_SOURCE ts = (PTOKEN_SOURCE)TokenInformation;
3265 
3266  DPRINT("NtQueryInformationToken(TokenSource)\n");
3267  RequiredLength = sizeof(TOKEN_SOURCE);
3268 
3269  _SEH2_TRY
3270  {
3272  {
3273  *ts = Token->TokenSource;
3274  }
3275  else
3276  {
3278  }
3279 
3280  if (ReturnLength != NULL)
3281  {
3283  }
3284  }
3286  {
3288  }
3289  _SEH2_END;
3290 
3291  break;
3292  }
3293 
3294  case TokenType:
3295  {
3296  PTOKEN_TYPE tt = (PTOKEN_TYPE)TokenInformation;
3297 
3298  DPRINT("NtQueryInformationToken(TokenType)\n");
3299  RequiredLength = sizeof(TOKEN_TYPE);
3300 
3301  _SEH2_TRY
3302  {
3304  {
3305  *tt = Token->TokenType;
3306  }
3307  else
3308  {
3310  }
3311 
3312  if (ReturnLength != NULL)
3313  {
3315  }
3316  }
3318  {
3320  }
3321  _SEH2_END;
3322 
3323  break;
3324  }
3325 
3327  {
3329 
3330  DPRINT("NtQueryInformationToken(TokenImpersonationLevel)\n");
3331 
3332  /* Fail if the token is not an impersonation token */
3333  if (Token->TokenType != TokenImpersonation)
3334  {
3336  break;
3337  }
3338 
3340 
3341  _SEH2_TRY
3342  {
3344  {
3345  *sil = Token->ImpersonationLevel;
3346  }
3347  else
3348  {
3350  }
3351 
3352  if (ReturnLength != NULL)
3353  {
3355  }
3356  }
3358  {
3360  }
3361  _SEH2_END;
3362 
3363  break;
3364  }
3365 
3366  case TokenStatistics:
3367  {
3368  PTOKEN_STATISTICS ts = (PTOKEN_STATISTICS)TokenInformation;
3369 
3370  DPRINT("NtQueryInformationToken(TokenStatistics)\n");
3371  RequiredLength = sizeof(TOKEN_STATISTICS);
3372 
3373  _SEH2_TRY
3374  {
3376  {
3377  ts->TokenId = Token->TokenId;
3378  ts->AuthenticationId = Token->AuthenticationId;
3379  ts->ExpirationTime = Token->ExpirationTime;
3380  ts->TokenType = Token->TokenType;
3381  ts->ImpersonationLevel = Token->ImpersonationLevel;
3382  ts->DynamicCharged = Token->DynamicCharged;
3383  ts->DynamicAvailable = Token->DynamicAvailable;
3384  ts->GroupCount = Token->UserAndGroupCount - 1;
3385  ts->PrivilegeCount = Token->PrivilegeCount;
3386  ts->ModifiedId = Token->ModifiedId;
3387  }
3388  else
3389  {
3391  }
3392 
3393  if (ReturnLength != NULL)
3394  {
3396  }
3397  }
3399  {
3401  }
3402  _SEH2_END;
3403 
3404  break;
3405  }
3406 
3407  case TokenOrigin:
3408  {
3409  PTOKEN_ORIGIN to = (PTOKEN_ORIGIN)TokenInformation;
3410 
3411  DPRINT("NtQueryInformationToken(TokenOrigin)\n");
3412  RequiredLength = sizeof(TOKEN_ORIGIN);
3413 
3414  _SEH2_TRY
3415  {
3417  {
3419  &Token->AuthenticationId);
3420  }
3421  else
3422  {
3424  }
3425 
3426  if (ReturnLength != NULL)
3427  {
3429  }
3430  }
3432  {
3434  }
3435  _SEH2_END;
3436 
3437  break;
3438  }
3439 
3441  DPRINT1("NtQueryInformationToken(TokenGroupsAndPrivileges) not implemented\n");
3443  break;
3444 
3445  case TokenRestrictedSids:
3446  {
3447  PTOKEN_GROUPS tg = (PTOKEN_GROUPS)TokenInformation;
3448 
3449  DPRINT("NtQueryInformationToken(TokenRestrictedSids)\n");
3450  RequiredLength = sizeof(tg->GroupCount) +
3451  RtlLengthSidAndAttributes(Token->RestrictedSidCount, Token->RestrictedSids);
3452 
3453  _SEH2_TRY
3454  {
3456  {
3457  ULONG SidLen = RequiredLength - sizeof(tg->GroupCount) -
3458  (Token->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES));
3459  PSID Sid = (PSID)((ULONG_PTR)tg + sizeof(tg->GroupCount) +
3460  (Token->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES)));
3461 
3462  tg->GroupCount = Token->RestrictedSidCount;
3463  Status = RtlCopySidAndAttributesArray(Token->RestrictedSidCount,
3464  Token->RestrictedSids,
3465  SidLen,
3466  &tg->Groups[0],
3467  Sid,
3468  &Unused.PSid,
3469  &Unused.Ulong);
3470  }
3471  else
3472  {
3474  }
3475 
3476  if (ReturnLength != NULL)
3477  {
3479  }
3480  }
3482  {
3484  }
3485  _SEH2_END;
3486 
3487  break;
3488  }
3489 
3490  case TokenSandBoxInert:
3491  DPRINT1("NtQueryInformationToken(TokenSandboxInert) not implemented\n");
3493  break;
3494 
3495  case TokenSessionId:
3496  {
3497  ULONG SessionId = 0;
3498 
3499  DPRINT("NtQueryInformationToken(TokenSessionId)\n");
3500 
3502  if (NT_SUCCESS(Status))
3503  {
3504  _SEH2_TRY
3505  {
3506  /* Buffer size was already verified, no need to check here again */
3507  *(PULONG)TokenInformation = SessionId;
3508 
3509  if (ReturnLength != NULL)
3510  {
3511  *ReturnLength = sizeof(ULONG);
3512  }
3513  }
3515  {
3517  }
3518  _SEH2_END;
3519  }
3520 
3521  break;
3522  }
3523 
3524  default:
3525  DPRINT1("NtQueryInformationToken(%d) invalid information class\n", TokenInformationClass);
3527  break;
3528  }
3529 
3530  /* Unlock and dereference the token */
3533  }
3534 
3535  return Status;
3536 }
3537 
3572 NTSTATUS
3573 NTAPI
3577  _In_reads_bytes_(TokenInformationLength) PVOID TokenInformation,
3579 {
3580  NTSTATUS Status;
3581  PTOKEN Token;
3583  ULONG NeededAccess = TOKEN_ADJUST_DEFAULT;
3584 
3585  PAGED_CODE();
3586 
3588 
3592  TokenInformation,
3594  PreviousMode);
3595  if (!NT_SUCCESS(Status))
3596  {
3597  /* Invalid buffers */
3598  DPRINT("NtSetInformationToken() failed, Status: 0x%x\n", Status);
3599  return Status;
3600  }
3601 
3603  {
3604  NeededAccess |= TOKEN_ADJUST_SESSIONID;
3605  }
3606 
3608  NeededAccess,
3610  PreviousMode,
3611  (PVOID*)&Token,
3612  NULL);
3613  if (NT_SUCCESS(Status))
3614  {
3615  switch (TokenInformationClass)
3616  {
3617  case TokenOwner:
3618  {
3619  if (TokenInformationLength >= sizeof(TOKEN_OWNER))
3620  {
3621  PTOKEN_OWNER to = (PTOKEN_OWNER)TokenInformation;
3622  PSID InputSid = NULL, CapturedSid;
3623  ULONG DefaultOwnerIndex;
3624 
3625  _SEH2_TRY
3626  {
3627  InputSid = to->Owner;
3628  }
3630  {
3632  _SEH2_YIELD(goto Cleanup);
3633  }
3634  _SEH2_END;
3635 
3636  Status = SepCaptureSid(InputSid,
3637  PreviousMode,
3638  PagedPool,
3639  FALSE,
3640  &CapturedSid);
3641  if (NT_SUCCESS(Status))
3642  {
3643  /* Lock the token */
3645 
3646  /* Find the owner amongst the existing token user and groups */
3648  NULL,
3649  CapturedSid,
3650  NULL,
3651  &DefaultOwnerIndex);
3652  if (NT_SUCCESS(Status))
3653  {
3654  /* Found it */
3655  Token->DefaultOwnerIndex = DefaultOwnerIndex;
3656  ExAllocateLocallyUniqueId(&Token->ModifiedId);
3657  }
3658 
3659  /* Unlock the token */
3661 
3662  SepReleaseSid(CapturedSid,
3663  PreviousMode,
3664  FALSE);
3665  }
3666  }
3667  else
3668  {
3670  }
3671  break;
3672  }
3673 
3674  case TokenPrimaryGroup:
3675  {
3677  {
3678  PTOKEN_PRIMARY_GROUP tpg = (PTOKEN_PRIMARY_GROUP)TokenInformation;
3679  PSID InputSid = NULL, CapturedSid;
3680  ULONG PrimaryGroupIndex;
3681 
3682  _SEH2_TRY
3683  {
3684  InputSid = tpg->PrimaryGroup;
3685  }
3687  {
3689  _SEH2_YIELD(goto Cleanup);
3690  }
3691  _SEH2_END;
3692 
3693  Status = SepCaptureSid(InputSid,
3694  PreviousMode,
3695  PagedPool,
3696  FALSE,
3697  &CapturedSid);
3698  if (NT_SUCCESS(Status))
3699  {
3700  /* Lock the token */
3702 
3703  /* Find the primary group amongst the existing token user and groups */
3705  CapturedSid,
3706  NULL,
3707  &PrimaryGroupIndex,
3708  NULL);
3709  if (NT_SUCCESS(Status))
3710  {
3711  /* Found it */
3712  Token->PrimaryGroup = Token->UserAndGroups[PrimaryGroupIndex].Sid;
3713  ExAllocateLocallyUniqueId(&Token->ModifiedId);
3714  }
3715 
3716  /* Unlock the token */
3718 
3719  SepReleaseSid(CapturedSid,
3720  PreviousMode,
3721  FALSE);
3722  }
3723  }
3724  else
3725  {
3727  }
3728  break;
3729  }
3730 
3731  case TokenDefaultDacl:
3732  {
3734  {
3735  PTOKEN_DEFAULT_DACL tdd = (PTOKEN_DEFAULT_DACL)TokenInformation;
3736  PACL InputAcl = NULL;
3737 
3738  _SEH2_TRY
3739  {
3740  InputAcl = tdd->DefaultDacl;
3741  }
3743  {
3745  _SEH2_YIELD(goto Cleanup);
3746  }
3747  _SEH2_END;
3748 
3749  if (InputAcl != NULL)
3750  {
3751  PACL CapturedAcl;
3752 
3753  /* Capture and copy the dacl */
3754  Status = SepCaptureAcl(InputAcl,
3755  PreviousMode,
3756  PagedPool,
3757  TRUE,
3758  &CapturedAcl);
3759  if (NT_SUCCESS(Status))
3760  {
3761  ULONG DynamicLength;
3762 
3763  /* Lock the token */
3765 
3766  //
3767  // NOTE: So far our dynamic area only contains
3768  // the default dacl, so this makes the following
3769  // code pretty simple. The day where it stores
3770  // other data, the code will require adaptations.
3771  //
3772 
3773  DynamicLength = Token->DynamicAvailable;
3774  // Add here any other data length present in the dynamic area...
3775  if (Token->DefaultDacl)
3776  DynamicLength += Token->DefaultDacl->AclSize;
3777 
3778  /* Reallocate the dynamic area if it is too small */
3780  if ((DynamicLength < CapturedAcl->AclSize) ||
3781  (Token->DynamicPart == NULL))
3782  {
3783  PVOID NewDynamicPart;
3784 
3785  NewDynamicPart = ExAllocatePoolWithTag(PagedPool,
3786  CapturedAcl->AclSize,
3788  if (NewDynamicPart == NULL)
3789  {
3791  }
3792  else
3793  {
3794  if (Token->DynamicPart != NULL)
3795  {
3796  // RtlCopyMemory(NewDynamicPart, Token->DynamicPart, DynamicLength);
3797  ExFreePoolWithTag(Token->DynamicPart, TAG_TOKEN_DYNAMIC);
3798  }
3799  Token->DynamicPart = NewDynamicPart;
3800  Token->DynamicAvailable = 0;
3801  }
3802  }
3803  else
3804  {
3805  Token->DynamicAvailable = DynamicLength - CapturedAcl->AclSize;
3806  }
3807 
3808  if (NT_SUCCESS(Status))
3809  {
3810  /* Set the new dacl */
3811  Token->DefaultDacl = (PVOID)Token->DynamicPart;
3812  RtlCopyMemory(Token->DefaultDacl,
3813  CapturedAcl,
3814  CapturedAcl->AclSize);
3815 
3816  ExAllocateLocallyUniqueId(&Token->ModifiedId);
3817  }
3818 
3819  /* Unlock the token */
3821 
3822  ExFreePoolWithTag(CapturedAcl, TAG_ACL);
3823  }
3824  }
3825  else
3826  {
3827  /* Lock the token */
3829 
3830  /* Clear the default dacl if present */
3831  if (Token->DefaultDacl != NULL)
3832  {
3833  Token->DynamicAvailable += Token->DefaultDacl->AclSize;
3834  RtlZeroMemory(Token->DefaultDacl, Token->DefaultDacl->AclSize);
3835  Token->DefaultDacl = NULL;
3836 
3837  ExAllocateLocallyUniqueId(&Token->ModifiedId);
3838  }
3839 
3840  /* Unlock the token */
3842  }
3843  }
3844  else
3845  {
3847  }
3848  break;
3849  }
3850 
3851  case TokenSessionId:
3852  {
3853  ULONG SessionId = 0;
3854 
3855  _SEH2_TRY
3856  {
3857  /* Buffer size was already verified, no need to check here again */
3858  SessionId = *(PULONG)TokenInformation;
3859  }
3861  {
3863  _SEH2_YIELD(goto Cleanup);
3864  }
3865  _SEH2_END;
3866 
3867  /* Check for TCB privilege */
3869  {
3871  break;
3872  }
3873 
3874  /* Lock the token */
3876 
3877  Token->SessionId = SessionId;
3878  ExAllocateLocallyUniqueId(&Token->ModifiedId);
3879 
3880  /* Unlock the token */
3882 
3883  break;
3884  }
3885 
3886  case TokenSessionReference:
3887  {
3888  ULONG SessionReference;
3889 
3890  _SEH2_TRY
3891  {
3892  /* Buffer size was already verified, no need to check here again */
3893  SessionReference = *(PULONG)TokenInformation;
3894  }
3896  {
3898  _SEH2_YIELD(goto Cleanup);
3899  }
3900  _SEH2_END;
3901 
3902  /* Check for TCB privilege */
3904  {
3906  goto Cleanup;
3907  }
3908 
3909  /* Check if it is 0 */
3910  if (SessionReference == 0)
3911  {
3912  ULONG OldTokenFlags;
3913 
3914  /* Lock the token */
3916 
3917  /* Atomically set the flag in the token */
3918  OldTokenFlags = RtlInterlockedSetBits(&Token->TokenFlags,
3920  /*
3921  * If the flag was already set, do not dereference again
3922  * the logon session. Use SessionReference as an indicator
3923  * to know whether to really dereference the session.
3924  */
3925  if (OldTokenFlags == Token->TokenFlags)
3926  SessionReference = ULONG_MAX;
3927 
3928  /*
3929  * Otherwise if the flag was never set but just for this first time then
3930  * remove the referenced logon session data from the token and dereference
3931  * the logon session when needed.
3932  */
3933  if (SessionReference == 0)
3934  {
3936  SepRmDereferenceLogonSession(&Token->AuthenticationId);
3937  }
3938 
3939  /* Unlock the token */
3941  }
3942  break;
3943  }
3944 
3945  case TokenAuditPolicy:
3946  {
3947  PTOKEN_AUDIT_POLICY_INFORMATION PolicyInformation =
3948  (PTOKEN_AUDIT_POLICY_INFORMATION)TokenInformation;
3949  SEP_AUDIT_POLICY AuditPolicy;
3950  ULONG i;
3951 
3952  _SEH2_TRY
3953  {
3954  ProbeForRead(PolicyInformation,
3956  Policies[PolicyInformation->PolicyCount]),
3957  sizeof(ULONG));
3958 
3959  /* Loop all policies in the structure */
3960  for (i = 0; i < PolicyInformation->PolicyCount; i++)
3961  {
3962  /* Set the corresponding bits in the packed structure */
3963  switch (PolicyInformation->Policies[i].Category)
3964  {
3965  case AuditCategorySystem:
3966  AuditPolicy.PolicyElements.System = PolicyInformation->Policies[i].Value;
3967  break;
3968 
3969  case AuditCategoryLogon:
3970  AuditPolicy.PolicyElements.Logon = PolicyInformation->Policies[i].Value;
3971  break;
3972 
3974  AuditPolicy.PolicyElements.ObjectAccess = PolicyInformation->Policies[i].Value;
3975  break;
3976 
3978  AuditPolicy.PolicyElements.PrivilegeUse = PolicyInformation->Policies[i].Value;
3979  break;
3980 
3982  AuditPolicy.PolicyElements.DetailedTracking = PolicyInformation->Policies[i].Value;
3983  break;
3984 
3986  AuditPolicy.PolicyElements.PolicyChange = PolicyInformation->Policies[i].Value;
3987  break;
3988 
3990  AuditPolicy.PolicyElements.AccountManagement = PolicyInformation->Policies[i].Value;
3991  break;
3992 
3994  AuditPolicy.PolicyElements.DirectoryServiceAccess = PolicyInformation->Policies[i].Value;
3995  break;
3996 
3998  AuditPolicy.PolicyElements.AccountLogon = PolicyInformation->Policies[i].Value;
3999  break;
4000  }
4001  }
4002  }
4004  {
4006  _SEH2_YIELD(goto Cleanup);
4007  }
4008  _SEH2_END;
4009 
4010  /* Check for TCB privilege */
4012  {
4014  break;
4015  }
4016 
4017  /* Lock the token */
4019 
4020  /* Set the new audit policy */
4021  Token->AuditPolicy = AuditPolicy;
4022  ExAllocateLocallyUniqueId(&Token->ModifiedId);
4023 
4024  /* Unlock the token */
4026 
4027  break;
4028  }
4029 
4030  case TokenOrigin:
4031  {
4033 
4034  _SEH2_TRY
4035  {
4036  /* Copy the token origin */
4037  TokenOrigin = *(PTOKEN_ORIGIN)TokenInformation;
4038  }
4040  {
4042  _SEH2_YIELD(goto Cleanup);
4043  }
4044  _SEH2_END;
4045 
4046  /* Check for TCB privilege */
4048  {
4050  break;
4051  }
4052 
4053  /* Lock the token */
4055 
4056  /* Check if there is no token origin set yet */
4057  if (RtlIsZeroLuid(&Token->OriginatingLogonSession))
4058  {
4059  /* Set the token origin */
4060  Token->OriginatingLogonSession =
4061  TokenOrigin.OriginatingLogonSession;
4062 
4063  ExAllocateLocallyUniqueId(&Token->ModifiedId);
4064  }
4065 
4066  /* Unlock the token */
4068 
4069  break;
4070  }
4071 
4072  default:
4073  {
4074  DPRINT1("Invalid TokenInformationClass: 0x%lx\n",
4077  break;
4078  }
4079  }
4080 Cleanup:
4082  }
4083 
4084  if (!NT_SUCCESS(Status))
4085  {
4086  DPRINT1("NtSetInformationToken failed with Status 0x%lx\n", Status);
4087  }
4088 
4089  return Status;
4090 }
4091 
4131 NTSTATUS
4132 NTAPI
4134  _In_ HANDLE ExistingTokenHandle,
4140 {
4142  HANDLE hToken;
4143  PTOKEN Token;
4144  PTOKEN NewToken;
4145  PSECURITY_QUALITY_OF_SERVICE CapturedSecurityQualityOfService;
4146  BOOLEAN QoSPresent;
4148  NTSTATUS Status;
4149 
4150  PAGED_CODE();
4151 
4152  if (TokenType != TokenImpersonation &&
4154  {
4155  return STATUS_INVALID_PARAMETER;
4156  }
4157 
4159 
4160  if (PreviousMode != KernelMode)
4161  {
4162  _SEH2_TRY
4163  {
4165  }
4167  {
4168  /* Return the exception code */
4170  }
4171  _SEH2_END;
4172  }
4173 
4175  PreviousMode,
4176  PagedPool,
4177  FALSE,
4178  &CapturedSecurityQualityOfService,
4179  &QoSPresent);
4180  if (!NT_SUCCESS(Status))
4181  {
4182  DPRINT1("NtDuplicateToken() failed to capture QoS! Status: 0x%x\n", Status);
4183  return Status;
4184  }
4185 
4186  Status = ObReferenceObjectByHandle(ExistingTokenHandle,
4189  PreviousMode,
4190  (PVOID*)&Token,
4192  if (!NT_SUCCESS(Status))
4193  {
4194  DPRINT1("Failed to reference token (Status 0x%lx)\n", Status);
4195  SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
4196  PreviousMode,
4197  FALSE);
4198  return Status;
4199  }
4200 
4201  /*
4202  * Fail, if the original token is an impersonation token and the caller
4203  * tries to raise the impersonation level of the new token above the
4204  * impersonation level of the original token.
4205  */
4206  if (Token->TokenType == TokenImpersonation)
4207  {
4208  if (QoSPresent &&
4209  CapturedSecurityQualityOfService->ImpersonationLevel >Token->ImpersonationLevel)
4210  {
4212  SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
4213  PreviousMode,
4214  FALSE);
4216  }
4217  }
4218 
4219  /*
4220  * Fail, if a primary token is to be created from an impersonation token
4221  * and and the impersonation level of the impersonation token is below SecurityImpersonation.
4222  */
4223  if (Token->TokenType == TokenImpersonation &&
4224  TokenType == TokenPrimary &&
4225  Token->ImpersonationLevel < SecurityImpersonation)
4226  {
4228  SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
4229  PreviousMode,
4230  FALSE);
4232  }
4233 
4236  EffectiveOnly,
4237  TokenType,
4238  (QoSPresent ? CapturedSecurityQualityOfService->ImpersonationLevel : SecurityAnonymous),
4239  PreviousMode,
4240  &NewToken);
4241 
4243 
4244  if (NT_SUCCESS(Status))
4245  {
4246  Status = ObInsertObject(NewToken,
4247  NULL,
4248  (DesiredAccess ? DesiredAccess : HandleInformation.GrantedAccess),
4249  0,
4250  NULL,
4251  &hToken);
4252  if (NT_SUCCESS(Status))
4253  {
4254  _SEH2_TRY
4255  {
4256  *NewTokenHandle = hToken;
4257  }
4259  {
4261  }
4262  _SEH2_END;
4263  }
4264  }
4265 
4266  /* Free the captured structure */
4267  SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
4268  PreviousMode,
4269  FALSE);
4270 
4271  return Status;
4272 }
4273 
4346 static
4347 NTSTATUS
4349  _In_ PTOKEN Token,
4350  _In_opt_ PSID_AND_ATTRIBUTES NewState,
4351  _In_ ULONG NewStateCount,
4353  _In_ BOOLEAN ResetToDefaultStates,
4354  _Out_ PBOOLEAN ChangesMade,
4355  _Out_opt_ PTOKEN_GROUPS PreviousGroupsState,
4356  _Out_ PULONG ChangedGroups)
4357 {
4358  ULONG GroupsInToken, GroupsInList;
4359  ULONG ChangeCount, GroupsCount, NewAttributes;
4360 
4361  PAGED_CODE();
4362 
4363  /* Ensure that the token we get is not plain garbage */
4364  ASSERT(Token);
4365 
4366  /* Initialize the counters and begin the work */
4367  *ChangesMade = FALSE;
4368  GroupsCount = 0;
4369  ChangeCount = 0;
4370 
4371  /* Begin looping all the groups in the token */
4372  for (GroupsInToken = 0; GroupsInToken < Token->UserAndGroupCount; GroupsInToken++)
4373  {
4374  /* Does the caller want to reset groups to default states? */
4375  if (ResetToDefaultStates)
4376  {
4377  /*
4378  * SE_GROUP_ENABLED_BY_DEFAULT is a special indicator that informs us
4379  * if a certain group has been enabled by default or not. In case
4380  * a group is enabled by default but it is not currently enabled then
4381  * at that point we must enable it back by default. For now just
4382  * assign the respective SE_GROUP_ENABLED attribute as we'll do the
4383  * eventual work later.
4384  */
4385  if ((Token->UserAndGroups[GroupsInToken].Attributes & SE_GROUP_ENABLED_BY_DEFAULT) &&
4386  (Token->UserAndGroups[GroupsInToken].Attributes & SE_GROUP_ENABLED) == 0)
4387  {
4388  NewAttributes = Token->UserAndGroups[GroupsInToken].Attributes |= SE_GROUP_ENABLED;
4389  }
4390 
4391  /*
4392  * Unlike the case above, a group that hasn't been enabled by
4393  * default but it's currently enabled then we must disable
4394  * it back.
4395  */
4396  if ((Token->UserAndGroups[GroupsInToken].Attributes & SE_GROUP_ENABLED_BY_DEFAULT) == 0 &&
4397  (Token->UserAndGroups[GroupsInToken].Attributes & SE_GROUP_ENABLED))
4398  {
4399  NewAttributes = Token->UserAndGroups[GroupsInToken].Attributes & ~SE_GROUP_ENABLED;
4400  }
4401  }
4402  else
4403  {
4404  /* Loop the provided groups in the list then */
4405  for (GroupsInList = 0; GroupsInList < NewStateCount; GroupsInList++)
4406  {
4407  /* Does this group exist in the token? */
4408  if (RtlEqualSid(&Token->UserAndGroups[GroupsInToken].Sid,
4409  &NewState[GroupsInList].Sid))
4410  {
4411  /*
4412  * This is the group that we're looking for.
4413  * However, it could be that the group is a
4414  * mandatory group which we are not allowed
4415  * and cannot disable it.
4416  */
4417  if ((Token->UserAndGroups[GroupsInToken].Attributes & SE_GROUP_MANDATORY) &&
4418  (NewState[GroupsInList].Attributes & SE_GROUP_ENABLED) == 0)
4419  {
4420  /* It is mandatory, forget about this group */
4421  DPRINT1("SepAdjustGroups(): The SID group is mandatory!\n");
4423  }
4424 
4425  /*
4426  * We've to ensure that apart the group mustn't be
4427  * mandatory, it mustn't be a restricted group as
4428  * well. That is, the group is marked with
4429  * SE_GROUP_USE_FOR_DENY_ONLY flag and no one
4430  * can enable it because it's for "deny" use only.
4431  */
4432  if ((Token->UserAndGroups[GroupsInToken].Attributes & SE_GROUP_USE_FOR_DENY_ONLY) &&
4433  (NewState[GroupsInList].Attributes & SE_GROUP_ENABLED))
4434  {
4435  /* This group is restricted, forget about it */
4436  DPRINT1("SepAdjustGroups(): The SID group is for use deny only!\n");
4438  }
4439 
4440  /* Copy the attributes and stop searching */
4441  NewAttributes = NewState[GroupsInList].Attributes;
4442  NewAttributes &= SE_GROUP_ENABLED;
4443  NewAttributes = Token->UserAndGroups[GroupsInToken].Attributes & ~SE_GROUP_ENABLED;
4444  break;
4445  }
4446 
4447  /* Did we find the specific group we wanted? */
4448  if (GroupsInList == NewStateCount)
4449  {
4450  /* We didn't, continue with the next token's group */
4451  continue;
4452  }
4453  }
4454 
4455  /* Count the group that we found it */
4456  GroupsCount++;
4457 
4458  /* Does the token have the same attributes as the caller requested them? */
4459  if (Token->UserAndGroups[GroupsInToken].Attributes != NewAttributes)
4460  {
4461  /*
4462  * No, then it's time to make some adjustment to the
4463  * token's groups. Does the caller want the previous states
4464  * of groups?
4465  */
4466  if (PreviousGroupsState != NULL)
4467  {
4468  PreviousGroupsState->Groups[ChangeCount] = Token->UserAndGroups[GroupsInToken];
4469  }
4470 
4471  /* Time to apply the changes now? */
4472  if (ApplyChanges)
4473  {
4474  /* The caller gave us consent, apply and report that we made changes! */
4475  Token->UserAndGroups[GroupsInToken].Attributes = NewAttributes;
4476  *ChangesMade = TRUE;
4477  }
4478 
4479  /* Increment the count change */
4480  ChangeCount++;
4481  }
4482  }
4483  }
4484 
4485  /* Report the number of previous saved groups */
4486  if (PreviousGroupsState != NULL)
4487  {
4488  PreviousGroupsState->GroupCount = ChangeCount;
4489  }
4490 
4491  /* Report the number of changed groups */
4492  *ChangedGroups = ChangeCount;
4493 
4494  /* Did we miss some groups? */
4495  if (!ResetToDefaultStates && (GroupsCount < NewStateCount))
4496  {
4497  /*
4498  * If we're at this stage then we are in a situation
4499  * where the adjust changes done to token's groups is
4500  * not deterministic as the caller might have wanted
4501  * as per NewState parameter.
4502  */
4503  DPRINT1("SepAdjustGroups(): The token hasn't all the groups assigned!\n");
4504  return STATUS_NOT_ALL_ASSIGNED;
4505  }
4506 
4507  return STATUS_SUCCESS;
4508 }
4509 
4554 NTSTATUS
4555 NTAPI
4558  _In_ BOOLEAN ResetToDefault,
4559  _In_ PTOKEN_GROUPS NewState,
4564 {
4565  PTOKEN Token;
4566  NTSTATUS Status;
4568  ULONG ChangeCount, RequiredLength;
4569  ULONG CapturedCount = 0;
4570  ULONG CapturedLength = 0;
4571  ULONG NewStateSize = 0;
4572  PSID_AND_ATTRIBUTES CapturedGroups = NULL;
4573  BOOLEAN ChangesMade = FALSE;
4574  BOOLEAN LockAndReferenceAcquired = FALSE;
4575 
4576  PAGED_CODE();
4577 
4578  /*
4579  * If the caller doesn't want to reset the groups of an
4580  * access token to default states then at least we must
4581  * expect a list of groups to be adjusted based on NewState
4582  * parameter. Otherwise bail out because the caller has
4583  * no idea what they're doing.
4584  */
4585  if (!ResetToDefault && !NewState)
4586  {
4587  DPRINT1("NtAdjustGroupsToken(): The caller hasn't provided any list of groups to adjust!\n");
4588  return STATUS_INVALID_PARAMETER;
4589  }
4590 
4592 
4593  if (PreviousMode != KernelMode)
4594  {
4595  _SEH2_TRY
4596  {
4597  /* Probe NewState */
4598  if (!ResetToDefault)
4599  {
4600  /* Probe the header */
4601  ProbeForRead(NewState, sizeof(*NewState), sizeof(ULONG));
4602 
4603  CapturedCount = NewState->GroupCount;
4604  NewStateSize = FIELD_OFFSET(TOKEN_GROUPS, Groups[CapturedCount]);
4605 
4606  ProbeForRead(NewState, NewStateSize, sizeof(ULONG));
4607  }
4608 
4609  if (PreviousState != NULL)
4610  {
4612  ProbeForWrite(ReturnLength, sizeof(*ReturnLength), sizeof(ULONG));
4613  }
4614  }
4616  {
4617  /* Return the exception code */
4619  }
4620  _SEH2_END;
4621  }
4622  else
4623  {
4624  /*
4625  * We're calling directly from the kernel, just retrieve
4626  * the number count of captured groups outright.
4627  */
4628  if (!ResetToDefault)
4629  {
4630  CapturedCount = NewState->GroupCount;
4631  }
4632  }
4633 
4634  /* Time to capture the NewState list */
4635  if (!ResetToDefault)
4636  {
4637  _SEH2_TRY
4638  {
4639  Status = SeCaptureSidAndAttributesArray(NewState->Groups,
4640  CapturedCount,
4641  PreviousMode,
4642  NULL,
4643  0,
4644  PagedPool,
4645  TRUE,
4646  &CapturedGroups,
4647  &CapturedLength);
4648  }
4650  {
4652  }
4653  _SEH2_END;
4654 
4655  if (!NT_SUCCESS(Status))
4656  {
4657  DPRINT1("NtAdjustGroupsToken(): Failed to capture the NewState list of groups (Status 0x%lx)\n", Status);
4658  return Status;
4659  }
4660  }
4661 
4662  /* Time to reference the token */
4666  PreviousMode,
4667  (PVOID*)&Token,
4668  NULL);
4669  if (!NT_SUCCESS(Status))
4670  {
4671  /* We couldn't reference the access token, bail out */
4672  DPRINT1("NtAdjustGroupsToken(): Failed to reference the token (Status 0x%lx)\n", Status);
4673 
4674  if (CapturedGroups != NULL)
4675  {
4676  SeReleaseSidAndAttributesArray(CapturedGroups,
4677  PreviousMode,
4678  TRUE);
4679  }
4680 
4681  goto Quit;
4682  }
4683 
4684  /* Lock the token */
4686  LockAndReferenceAcquired = TRUE;
4687 
4688  /* Count the number of groups to be changed */
4690  CapturedGroups,
4691  CapturedCount,
4692  FALSE,
4693  ResetToDefault,
4694  &ChangesMade,
4695  NULL,
4696  &ChangeCount);
4697 
4698  /* Does the caller want the previous state of groups? */
4699  if (PreviousState != NULL)
4700  {
4701  /* Calculate the required length */
4703 
4704  /* Return the required length to the caller */
4705  _SEH2_TRY
4706  {
4708  }
4710  {
4711  /* Bail out and return the exception code */
4713  _SEH2_YIELD(goto Quit);
4714  }
4715  _SEH2_END;
4716 
4717  /* The buffer length provided is smaller than the required length, bail out */
4719  {
4721  goto Quit;
4722  }
4723  }
4724 
4725  /*
4726  * Now it's time to apply changes. Wrap the code
4727  * in SEH as we are returning the old groups state
4728  * list to the caller since PreviousState is a
4729  * UM pointer.
4730  */
4731  _SEH2_TRY
4732  {
4734  CapturedGroups,
4735  CapturedCount,
4736  TRUE,
4737  ResetToDefault,
4738  &ChangesMade,
4739  PreviousState,
4740  &ChangeCount);
4741  }
4743  {
4744  /* Bail out and return the exception code */
4746 
4747  /* Force the write as we touched the token still */
4748  ChangesMade = TRUE;
4749  _SEH2_YIELD(goto Quit);
4750  }
4751  _SEH2_END;
4752 
4753 Quit:
4754  /* Allocate a new ID for the token as we made changes */
4755  if (ChangesMade)
4756  {
4757  ExAllocateLocallyUniqueId(&Token->ModifiedId);
4758  }
4759 
4760  /* Have we successfully acquired the lock and referenced the token before? */
4761  if (LockAndReferenceAcquired)
4762  {
4763  /* Unlock and dereference the token */
4766  }
4767 
4768  /* Release the captured groups */
4769  if (CapturedGroups != NULL)
4770  {
4771  SeReleaseSidAndAttributesArray(CapturedGroups,
4772  PreviousMode,
4773  TRUE);
4774  }
4775 
4776  return Status;
4777 }
4778 
4816 static
4817 NTSTATUS
4820  _In_ BOOLEAN DisableAllPrivileges,
4821  _In_opt_ PLUID_AND_ATTRIBUTES NewState,
4822  _In_ ULONG NewStateCount,
4825  _Out_ PULONG ChangedPrivileges,
4826  _Out_ PBOOLEAN ChangesMade)
4827 {
4828  ULONG i, j, PrivilegeCount, ChangeCount, NewAttributes;
4829 
4830  PAGED_CODE();
4831 
4832  /* Count the found privileges and those that need to be changed */
4833  PrivilegeCount = 0;
4834  ChangeCount = 0;
4835  *ChangesMade = FALSE;
4836 
4837  /* Loop all privileges in the token */
4838  for (i = 0; i < Token->PrivilegeCount; i++)
4839  {
4840  /* Shall all of them be disabled? */
4841  if (DisableAllPrivileges)
4842  {
4843  /* The new attributes are the old ones, but disabled */
4844  NewAttributes = Token->Privileges[i].Attributes & ~SE_PRIVILEGE_ENABLED;
4845  }
4846  else
4847  {
4848  /* Otherwise loop all provided privileges */
4849  for (j = 0; j < NewStateCount; j++)
4850  {
4851  /* Check if this is the LUID we are looking for */
4852  if (RtlEqualLuid(&Token->Privileges[i].Luid, &NewState[j].Luid))
4853  {
4854  DPRINT("Found privilege\n");
4855 
4856  /* Copy SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_REMOVED */
4857  NewAttributes = NewState[j].Attributes;
4858  NewAttributes &= (SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_REMOVED);
4859  NewAttributes |= Token->Privileges[i].Attributes & ~SE_PRIVILEGE_ENABLED;
4860 
4861  /* Stop looking */
4862  break;
4863  }
4864  }
4865 
4866  /* Check if we didn't find the privilege */
4867  if (j == NewStateCount)
4868  {
4869  /* Continue with the token's next privilege */
4870  continue;
4871  }
4872  }
4873 
4874  /* We found a privilege, count it */
4875  PrivilegeCount++;
4876 
4877  /* Does the privilege need to be changed? */
4878  if (Token->Privileges[i].Attributes != NewAttributes)
4879  {
4880  /* Does the caller want the old privileges? */
4881  if (PreviousState != NULL)
4882  {
4883  /* Copy the old privilege */
4884  PreviousState->Privileges[ChangeCount] = Token->Privileges[i];
4885  }
4886 
4887  /* Does the caller want to apply the changes? */
4888  if (ApplyChanges)
4889  {
4890  /* Shall we remove the privilege? */
4891  if (NewAttributes & SE_PRIVILEGE_REMOVED)
4892  {
4893  /* Set the token as disabled and update flags for it */
4894  Token->Privileges[i].Attributes &= ~SE_PRIVILEGE_ENABLED;
4896 
4897  /* Remove the privilege */
4899 
4900  *ChangesMade = TRUE;
4901 
4902  /* Fix the running index and continue with next one */
4903  i--;
4904  continue;
4905  }
4906 
4907  /* Set the new attributes and update flags */
4908  Token->Privileges[i].Attributes = NewAttributes;
4910  *ChangesMade = TRUE;
4911  }
4912 
4913  /* Increment the change count */
4914  ChangeCount++;
4915  }
4916  }
4917 
4918  /* Set the number of saved privileges */
4919  if (PreviousState != NULL)
4920  PreviousState->PrivilegeCount = ChangeCount;
4921 
4922  /* Return the number of changed privileges */
4923  *ChangedPrivileges = ChangeCount;
4924 
4925  /* Check if we missed some */
4926  if (!DisableAllPrivileges && (PrivilegeCount < NewStateCount))
4927  {
4928  return STATUS_NOT_ALL_ASSIGNED;
4929  }
4930 
4931  return STATUS_SUCCESS;
4932 }
4933 
4973 NTSTATUS
4974 NTAPI
4977  _In_ BOOLEAN DisableAllPrivileges,
4978  _In_opt_ PTOKEN_PRIVILEGES NewState,
4983 {
4984  NTSTATUS Status;
4986  PTOKEN Token;
4987  PLUID_AND_ATTRIBUTES CapturedPrivileges = NULL;
4988  ULONG CapturedCount = 0;
4989  ULONG CapturedLength = 0;
4990  ULONG NewStateSize = 0;
4991  ULONG ChangeCount;
4993  BOOLEAN ChangesMade = FALSE;
4994 
4995  PAGED_CODE();
4996 
4997  DPRINT("NtAdjustPrivilegesToken() called\n");
4998 
4999  /* Fail, if we do not disable all privileges but NewState is NULL */
5000  if (DisableAllPrivileges == FALSE && NewState == NULL)
5001  return STATUS_INVALID_PARAMETER;
5002 
5004  if (PreviousMode != KernelMode)
5005  {
5006  _SEH2_TRY
5007  {
5008  /* Probe NewState */
5009  if (DisableAllPrivileges == FALSE)
5010  {
5011  /* First probe the header */
5012  ProbeForRead(NewState, sizeof(TOKEN_PRIVILEGES), sizeof(ULONG));
5013 
5014  CapturedCount = NewState->PrivilegeCount;
5015  NewStateSize = FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges[CapturedCount]);
5016 
5017  ProbeForRead(NewState, NewStateSize, sizeof(ULONG));
5018  }
5019 
5020  /* Probe PreviousState and ReturnLength */
5021  if (PreviousState != NULL)
5022  {
5024  ProbeForWrite(ReturnLength, sizeof(ULONG), sizeof(ULONG));
5025  }
5026  }
5028  {
5029  /* Return the exception code */
5031  }
5032  _SEH2_END;
5033  }
5034  else
5035  {
5036  /* This is kernel mode, we trust the caller */
5037  if (DisableAllPrivileges == FALSE)
5038  CapturedCount = NewState->PrivilegeCount;
5039  }
5040 
5041  /* Do we need to capture the new state? */
5042  if (DisableAllPrivileges == FALSE)
5043  {
5044  _SEH2_TRY
5045  {
5046  /* Capture the new state array of privileges */
5047  Status = SeCaptureLuidAndAttributesArray(NewState->Privileges,
5048  CapturedCount,
5049  PreviousMode,
5050  NULL,
5051  0,
5052  PagedPool,
5053  TRUE,
5054  &CapturedPrivileges,
5055  &CapturedLength);
5056  }
5058  {
5059  /* Return the exception code */
5061  }
5062  _SEH2_END;
5063 
5064  if (!NT_SUCCESS(Status))
5065  return Status;
5066  }
5067 
5068  /* Reference the token */
5072  PreviousMode,
5073  (PVOID*)&Token,
5074  NULL);
5075  if (!NT_SUCCESS(Status))
5076  {
5077  DPRINT1("Failed to reference token (Status 0x%lx)\n", Status);
5078 
5079  /* Release the captured privileges */
5080  if (CapturedPrivileges != NULL)
5081  {
5082  SeReleaseLuidAndAttributesArray(CapturedPrivileges,
5083  PreviousMode,
5084  TRUE);
5085  }
5086 
5087  return Status;
5088  }
5089 
5090  /* Lock the token */
5092 
5093  /* Count the privileges that need to be changed, do not apply them yet */
5095  DisableAllPrivileges,
5096  CapturedPrivileges,
5097  CapturedCount,
5098  NULL,
5099  FALSE,
5100  &ChangeCount,
5101  &ChangesMade);
5102 
5103  /* Check if the caller asked for the previous state */
5104  if (PreviousState != NULL)
5105  {
5106  /* Calculate the required length */
5108 
5109  /* Try to return the required buffer length */
5110  _SEH2_TRY
5111  {
5113  }
5115  {
5116  /* Do cleanup and return the exception code */
5118  _SEH2_YIELD(goto Cleanup);
5119  }
5120  _SEH2_END;
5121 
5122  /* Fail, if the buffer length is smaller than the required length */
5124  {
5126  goto Cleanup;
5127  }
5128  }
5129 
5130  /* Now enter SEH, since we might return the old privileges */
5131  _SEH2_TRY
5132  {
5133  /* This time apply the changes */
5135  DisableAllPrivileges,
5136  CapturedPrivileges,
5137  CapturedCount,
5138  PreviousState,
5139  TRUE,
5140  &ChangeCount,
5141  &ChangesMade);
5142  }
5144  {
5145  /* Do cleanup and return the exception code */
5147  ChangesMade = TRUE; // Force write.
5148  _SEH2_YIELD(goto Cleanup);
5149  }
5150  _SEH2_END;
5151 
5152 Cleanup:
5153  /* Touch the token if we made changes */
5154  if (ChangesMade)
5155  ExAllocateLocallyUniqueId(&Token->ModifiedId);
5156 
5157  /* Unlock and dereference the token */
5160 
5161  /* Release the captured privileges */
5162  if (CapturedPrivileges != NULL)
5163  {
5164  SeReleaseLuidAndAttributesArray(CapturedPrivileges,
5165  PreviousMode,
5166  TRUE);
5167  }
5168 
5169  DPRINT ("NtAdjustPrivilegesToken() done\n");
5170  return Status;
5171 }
5172 
5222 NTSTATUS
5223 NTAPI
5229  _In_ PLUID AuthenticationId,
5230  _In_ PLARGE_INTEGER ExpirationTime,
5238 {
5239  HANDLE hToken;
5241  ULONG PrivilegeCount, GroupCount;
5242  PSID OwnerSid, PrimaryGroupSid;
5243  PACL DefaultDacl;
5244  LARGE_INTEGER LocalExpirationTime = {{0, 0}};
5245  LUID LocalAuthenticationId;
5246  TOKEN_SOURCE LocalTokenSource;
5247  SECURITY_QUALITY_OF_SERVICE LocalSecurityQos;
5248  PLUID_AND_ATTRIBUTES CapturedPrivileges = NULL;
5249  PSID_AND_ATTRIBUTES CapturedUser = NULL;
5250  PSID_AND_ATTRIBUTES CapturedGroups = NULL;
5251  PSID CapturedOwnerSid = NULL;
5252  PSID CapturedPrimaryGroupSid = NULL;
5253  PACL CapturedDefaultDacl = NULL;
5254  ULONG PrivilegesLength, UserLength, GroupsLength;
5255  NTSTATUS Status;
5256 
5257  PAGED_CODE();
5258 
5260 
5261  if (PreviousMode != KernelMode)
5262  {
5263  _SEH2_TRY
5264  {
5266 
5267  if (ObjectAttributes != NULL)
5268  {
5270  sizeof(OBJECT_ATTRIBUTES),
5271  sizeof(ULONG));
5272  LocalSecurityQos = *(SECURITY_QUALITY_OF_SERVICE*)ObjectAttributes->SecurityQualityOfService;
5273  }
5274 
5275  ProbeForRead(AuthenticationId,
5276  sizeof(LUID),
5277  sizeof(ULONG));
5278  LocalAuthenticationId = *AuthenticationId;
5279 
5280  LocalExpirationTime = ProbeForReadLargeInteger(ExpirationTime);
5281 
5283  sizeof(TOKEN_USER),
5284  sizeof(ULONG));
5285 
5287  sizeof(TOKEN_GROUPS),
5288  sizeof(ULONG));
5289  GroupCount = TokenGroups->GroupCount;
5290 
5292  sizeof(TOKEN_PRIVILEGES),
5293  sizeof(ULONG));
5294  PrivilegeCount = TokenPrivileges->PrivilegeCount;
5295 
5296  if (TokenOwner != NULL)
5297  {
5299  sizeof(TOKEN_OWNER),
5300  sizeof(ULONG));
5301  OwnerSid = TokenOwner->Owner;
5302  }
5303  else
5304  {
5305  OwnerSid = NULL;
5306  }
5307 
5309  sizeof(TOKEN_PRIMARY_GROUP),
5310  sizeof(ULONG));
5311  PrimaryGroupSid = TokenPrimaryGroup->PrimaryGroup;
5312 
5313  if (TokenDefaultDacl != NULL)
5314  {
5316  sizeof(TOKEN_DEFAULT_DACL),
5317  sizeof(ULONG));
5318  DefaultDacl = TokenDefaultDacl->DefaultDacl;
5319  }
5320  else
5321  {
5322  DefaultDacl = NULL;
5323  }
5324 
5326  sizeof(TOKEN_SOURCE),
5327  sizeof(ULONG));
5328  LocalTokenSource = *TokenSource;
5329  }
5331  {
5332  /* Return the exception code */
5334  }
5335  _SEH2_END;
5336  }
5337  else
5338  {
5339  if (ObjectAttributes != NULL)
5340  LocalSecurityQos = *(SECURITY_QUALITY_OF_SERVICE*)ObjectAttributes->SecurityQualityOfService;
5341  LocalAuthenticationId = *AuthenticationId;
5342  LocalExpirationTime = *ExpirationTime;
5343  GroupCount = TokenGroups->GroupCount;
5344  PrivilegeCount = TokenPrivileges->PrivilegeCount;
5345  OwnerSid = TokenOwner ? TokenOwner->Owner : NULL;
5346  PrimaryGroupSid = TokenPrimaryGroup->PrimaryGroup;
5347  DefaultDacl = TokenDefaultDacl ? TokenDefaultDacl->DefaultDacl : NULL;
5348  LocalTokenSource = *TokenSource;
5349  }
5350 
5351  /* Check token type */
5352  if ((TokenType < TokenPrimary) ||
5354  {
5355  return STATUS_BAD_TOKEN_TYPE;
5356  }
5357 
5358  /* Check for token creation privilege */
5360  {
5362  }
5363 
5364  /* Capture the user SID and attributes */
5366  1,
5367  PreviousMode,
5368  NULL,
5369  0,
5370  PagedPool,
5371  FALSE,
5372  &CapturedUser,
5373  &UserLength);
5374  if (!NT_SUCCESS(Status))
5375  {
5376  goto Cleanup;
5377  }
5378 
5379  /* Capture the groups SID and attributes array */
5381  GroupCount,
5382  PreviousMode,
5383  NULL,
5384  0,
5385  PagedPool,
5386  FALSE,
5387  &CapturedGroups,
5388  &GroupsLength);
5389  if (!NT_SUCCESS(Status))
5390  {
5391  goto Cleanup;
5392  }
5393 
5394  /* Capture privileges */
5396  PrivilegeCount,
5397  PreviousMode,
5398  NULL,
5399  0,
5400  PagedPool,
5401  FALSE,
5402  &CapturedPrivileges,
5403  &PrivilegesLength);
5404  if (!NT_SUCCESS(Status))
5405  {
5406  goto Cleanup;
5407  }
5408 
5409  /* Capture the token owner SID */
5410  if (TokenOwner != NULL)
5411  {
5412  Status = SepCaptureSid(OwnerSid,
5413  PreviousMode,
5414  PagedPool,
5415  FALSE,
5416  &CapturedOwnerSid);
5417  if (!NT_SUCCESS(Status))
5418  {
5419  goto Cleanup;
5420  }
5421  }
5422 
5423  /* Capture the token primary group SID */
5424  Status = SepCaptureSid(PrimaryGroupSid,
5425  PreviousMode,
5426  PagedPool,
5427  FALSE,
5428  &CapturedPrimaryGroupSid);
5429  if (!NT_SUCCESS(Status))
5430  {
5431  goto Cleanup;
5432  }
5433 
5434  /* Capture DefaultDacl */
5435  if (DefaultDacl != NULL)
5436  {
5437  Status = SepCaptureAcl(DefaultDacl,
5438  PreviousMode,
5439  NonPagedPool,
5440  FALSE,
5441  &CapturedDefaultDacl);
5442  if (!NT_SUCCESS(Status))
5443  {
5444  goto Cleanup;
5445  }
5446  }
5447 
5448  /* Call the internal function */
5449  Status = SepCreateToken(&hToken,
5450  PreviousMode,
5451  DesiredAccess,
5453  TokenType,
5454  LocalSecurityQos.ImpersonationLevel,
5455  &LocalAuthenticationId,
5456  &LocalExpirationTime,
5457  CapturedUser,
5458  GroupCount,
5459  CapturedGroups,
5460  GroupsLength,
5461  PrivilegeCount,
5462  CapturedPrivileges,
5463  CapturedOwnerSid,
5464  CapturedPrimaryGroupSid,
5465  CapturedDefaultDacl,
5466  &LocalTokenSource,
5467  FALSE);
5468  if (NT_SUCCESS(Status))
5469  {
5470  _SEH2_TRY
5471  {
5472  *TokenHandle = hToken;
5473  }
5475  {
5477  }
5478  _SEH2_END;
5479  }
5480 
5481 Cleanup:
5482 
5483  /* Release what we captured */
5486  SeReleaseLuidAndAttributesArray(CapturedPrivileges, PreviousMode, FALSE);
5487  SepReleaseSid(CapturedOwnerSid, PreviousMode, FALSE);
5488  SepReleaseSid(CapturedPrimaryGroupSid, PreviousMode, FALSE);
5489  SepReleaseAcl(CapturedDefaultDacl, PreviousMode, FALSE);
5490 
5491  return Status;
5492 }
5493 
5521 NTSTATUS
5522 NTAPI
5524  _In_ HANDLE ThreadHandle,
5529 {
5530  PETHREAD Thread;
5531  HANDLE hToken;
5532  PTOKEN Token, NewToken = NULL, PrimaryToken;
5538  PACL Dacl = NULL;
5540  NTSTATUS Status;
5541  BOOLEAN RestoreImpersonation = FALSE;
5542 
5543  PAGED_CODE();
5544 
5546 
5547  if (PreviousMode != KernelMode)
5548  {
5549  _SEH2_TRY
5550  {
5552  }
5554  {
5555  /* Return the exception code */
5557  }
5558  _SEH2_END;
5559  }
5560 
5561  /* Validate object attributes */
5563 
5564  /*
5565  * At first open the thread token for information access and verify
5566  * that the token associated with thread is valid.
5567  */
5568 
5571  NULL);
5572  if (!NT_SUCCESS(Status))
5573  {
5574  return Status;
5575  }
5576 
5579  if (Token == NULL)
5580  {
5582  return STATUS_NO_TOKEN;
5583  }
5584 
5586  {
5590  }
5591 
5592  /*
5593  * Revert to self if OpenAsSelf is specified.
5594  */
5595 
5596  if (OpenAsSelf)
5597  {
5598  RestoreImpersonation = PsDisableImpersonation(PsGetCurrentThread(),
5600  }
5601 
5602  if (CopyOnOpen)
5603  {
5604  PrimaryToken = PsReferencePrimaryToken(Thread->ThreadsProcess);
5605 
5606  Status = SepCreateImpersonationTokenDacl(Token, PrimaryToken, &Dacl);
5607 
5608  ObFastDereferenceObject(&Thread->ThreadsProcess->Token, PrimaryToken);
5609 
5610  if (NT_SUCCESS(Status))
5611  {
5612  if (Dacl)
5613  {
5616  if (!NT_SUCCESS(Status))
5617  {
5618  DPRINT1("NtOpenThreadTokenEx(): Failed to create a security descriptor (Status 0x%lx)\n", Status);
5619  }
5620 
5622  FALSE);
5623  if (!NT_SUCCESS(Status))
5624  {
5625  DPRINT1("NtOpenThreadTokenEx(): Failed to set a DACL to the security descriptor (Status 0x%lx)\n", Status);
5626  }
5627  }
5628 
5631 
5634  KernelMode, &NewToken);
5635  if (!NT_SUCCESS(Status))
5636  {
5637  DPRINT1("NtOpenThreadTokenEx(): Failed to duplicate the token (Status 0x%lx)\n");
5638  }
5639 
5640  ObReferenceObject(NewToken);
5641  Status = ObInsertObject(NewToken, NULL, DesiredAccess, 0, NULL,
5642  &hToken);
5643  if (!NT_SUCCESS(Status))
5644  {
5645  DPRINT1("NtOpenThreadTokenEx(): Failed to insert the token object (Status 0x%lx)\n", Status);
5646  }
5647  }
5648  else
5649  {
5650  DPRINT1("NtOpenThreadTokenEx(): Failed to impersonate token from DACL (Status 0x%lx)\n", Status);
5651  }
5652  }
5653  else
5654  {
5657  PreviousMode, &hToken);
5658  if (!NT_SUCCESS(Status))
5659  {
5660  DPRINT1("NtOpenThreadTokenEx(): Failed to open the object (Status 0x%lx)\n", Status);
5661  }
5662  }
5663 
5665 
5666  if (RestoreImpersonation)
5667  {
5669  }
5670 
5672 
5673  if (NT_SUCCESS(Status) && CopyOnOpen)
5674  {
5676  if (!NT_SUCCESS(Status))
5677  {
5678  DPRINT1("NtOpenThreadTokenEx(): Failed to impersonate the client (Status 0x%lx)\n");
5679  }
5680  }
5681 
5682  if (NewToken) ObDereferenceObject(NewToken);
5683 
5685 
5686  if (NT_SUCCESS(Status))
5687  {
5688  _SEH2_TRY
5689  {
5690  *TokenHandle = hToken;
5691  }
5693  {
5695  }
5696  _SEH2_END;
5697  }
5698 
5699  return Status;
5700 }
5701 
5723 NTSTATUS
5724 NTAPI
5726  _In_ HANDLE ThreadHandle,
5730 {
5731  return NtOpenThreadTokenEx(ThreadHandle, DesiredAccess, OpenAsSelf, 0,
5732  TokenHandle);
5733 }
5734 
5752 NTSTATUS
5753 NTAPI
5755  _In_ HANDLE FirstTokenHandle,
5756  _In_ HANDLE SecondTokenHandle,
5757  _Out_ PBOOLEAN Equal)
5758 {
5760  PTOKEN FirstToken, SecondToken;
5761  BOOLEAN IsEqual;
5762  NTSTATUS Status;
5763 
5764  PAGED_CODE();
5765 
5767 
5768  if (PreviousMode != KernelMode)
5769  {
5770  _SEH2_TRY
5771  {
5772  ProbeForWriteBoolean(Equal);
5773  }
5775  {
5776  /* Return the exception code */
5778  }
5779  _SEH2_END;
5780  }
5781 
5782  Status = ObReferenceObjectByHandle(FirstTokenHandle,
5783  TOKEN_QUERY,
5785  PreviousMode,
5786  (PVOID*)&FirstToken,
5787  NULL);
5788  if (!NT_SUCCESS(Status))
5789  {
5790  DPRINT1("ObReferenceObjectByHandle() failed (Status 0x%lx)\n", Status);
5791  return Status;
5792  }
5793 
5794  Status = ObReferenceObjectByHandle(SecondTokenHandle,
5795  TOKEN_QUERY,
5797  PreviousMode,
5798  (PVOID*)&SecondToken,
5799  NULL);
5800  if (!NT_SUCCESS(Status))
5801  {
5802  DPRINT1("ObReferenceObjectByHandle() failed (Status 0x%lx)\n", Status);
5803  ObDereferenceObject(FirstToken);
5804  return Status;
5805  }
5806 
5807  if (FirstToken != SecondToken)
5808  {
5809  Status = SepCompareTokens(FirstToken,
5810  SecondToken,
5811  &IsEqual);
5812  }
5813  else
5814  {
5815  IsEqual = TRUE;
5816  }
5817 
5818  ObDereferenceObject(SecondToken);
5819  ObDereferenceObject(FirstToken);
5820 
5821  if (NT_SUCCESS(Status))
5822  {
5823  _SEH2_TRY
5824  {
5825  *Equal = IsEqual;
5826  }
5828  {
5830  }
5831  _SEH2_END;
5832  }
5833 
5834  return Status;
5835 }
5836 
5864 NTSTATUS
5865 NTAPI
5867  _In_ HANDLE ExistingTokenHandle,
5868  _In_ ULONG Flags,
5869  _In_opt_ PTOKEN_GROUPS SidsToDisable,
5870  _In_opt_ PTOKEN_PRIVILEGES PrivilegesToDelete,
5871  _In_opt_ PTOKEN_GROUPS RestrictedSids,
5873 {
5874  UNIMPLEMENTED;
5875  return STATUS_NOT_IMPLEMENTED;
5876 }
5877 
5902 NTSTATUS
5903 NTAPI
5905  _In_ HANDLE ThreadHandle)
5906 {
5907  PETHREAD Thread;
5909  NTSTATUS Status;
5910  PAGED_CODE();
5911 
5913 
5914  /* Obtain the thread object from the handle */
5915  Status = ObReferenceObjectByHandle(ThreadHandle,
5917  PsThreadType,
5918  PreviousMode,
5919  (PVOID*)&Thread,
5920  NULL);
5921  if (!NT_SUCCESS(Status))
5922  {
5923  DPRINT1("NtImpersonateAnonymousToken(): Failed to reference the object (Status 0x%lx)\n", Status);
5924  return Status;
5925  }
5926 
5927  /* Call the private routine to impersonate the token */
5929  if (!NT_SUCCESS(Status))
5930  {
5931  DPRINT1("NtImpersonateAnonymousToken(): Failed to impersonate the token (Status 0x%lx)\n", Status);
5932  }
5933 
5935  return Status;
5936 }
5937 
5938 /* EOF */
LUID AuthenticationId
Definition: setypes.h:1052
PTOKEN SeAnonymousLogonTokenNoEveryone
Definition: semgr.c:20
#define OBJ_OPENLINK
Definition: winternl.h:230
TOKEN_TYPE TokenType
Definition: setypes.h:221
const LUID SeSystemEnvironmentPrivilege
Definition: priv.c:41
enum _SECURITY_IMPERSONATION_LEVEL * PSECURITY_IMPERSONATION_LEVEL
#define SepAcquireTokenLockExclusive(Token)
Definition: se.h:220
NTSTATUS NTAPI NtOpenThreadTokenEx(_In_ HANDLE ThreadHandle, _In_ ACCESS_MASK DesiredAccess, _In_ BOOLEAN OpenAsSelf, _In_ ULONG HandleAttributes, _Out_ PHANDLE TokenHandle)
Opens a token that is tied to a thread handle.
Definition: token.c:5523
static NTSTATUS SepFindPrimaryGroupAndDefaultOwner(_In_ PTOKEN Token, _In_ PSID PrimaryGroup, _In_opt_ PSID DefaultOwner, _Out_opt_ PULONG PrimaryGroupIndex, _Out_opt_ PULONG DefaultOwnerIndex)
Finds the primary group and default owner entity based on the submitted primary group instance and an...
Definition: token.c:869
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:35
NTSTATUS NTAPI PsImpersonateClient(IN PETHREAD Thread, IN PACCESS_TOKEN Token, IN BOOLEAN CopyOnOpen, IN BOOLEAN EffectiveOnly, IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
Definition: security.c:610
IN CINT OUT PVOID IN ULONG OUT PULONG ReturnLength
Definition: dumpinfo.c:39
#define STATUS_NOT_ALL_ASSIGNED
Definition: ntstatus.h:85
_In_ HANDLE _In_opt_ HANDLE _Out_opt_ PHANDLE _In_ ACCESS_MASK _In_ ULONG HandleAttributes
Definition: obfuncs.h:429
_Must_inspect_result_ typedef _In_ PVOID Unused
Definition: iotypes.h:1166
NTSTATUS NTAPI SepRegQueryHelper(_In_ PCWSTR KeyName, _In_ PCWSTR ValueName, _In_ ULONG ValueType, _In_ ULONG DataLength, _Out_ PVOID ValueData)
A private registry helper that returns the desired value data based on the specifics requested by the...
Definition: srm.c:93
_Must_inspect_result_ _In_ WDFDEVICE _In_ DEVICE_REGISTRY_PROPERTY _In_ ULONG BufferLength
Definition: wdfdevice.h:3767
#define STATUS_PRIVILEGE_NOT_HELD
Definition: DriverTester.h:9
NTSTATUS NTAPI ObCreateObjectType(IN PUNICODE_STRING TypeName, IN POBJECT_TYPE_INITIALIZER ObjectTypeInitializer, IN PVOID Reserved, OUT POBJECT_TYPE *ObjectType)
Definition: oblife.c:1048
_Must_inspect_result_ _In_ WDFDEVICE _In_ ULONG _In_ ACCESS_MASK DesiredAccess
Definition: wdfdevice.h:2654
#define STATUS_BAD_IMPERSONATION_LEVEL
Definition: ntstatus.h:401
const LUID SeSystemtimePrivilege
Definition: priv.c:31
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
NTSTATUS NTAPI SepRmInsertLogonSessionIntoToken(_Inout_ PTOKEN Token)
Inserts a logon session into an access token specified by the caller.
Definition: srm.c:368
#define _In_opt_
Definition: ms_sal.h:309
#define STATUS_INFO_LENGTH_MISMATCH
Definition: udferr_usr.h:133
NTSTATUS NTAPI SeQueryInformationToken(_In_ PACCESS_TOKEN AccessToken, _In_ TOKEN_INFORMATION_CLASS TokenInformationClass, _Outptr_result_buffer_(_Inexpressible_(token-dependent)) PVOID *TokenInformation)
Queries information details about the given token to the call. The difference between NtQueryInformat...
Definition: token.c:2328
BOOLEAN NTAPI SeTokenCanImpersonate(_In_ PTOKEN ProcessToken, _In_ PTOKEN TokenToImpersonate, _In_ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
Ensures that client impersonation can occur by checking if the token we're going to assign as the imp...
Definition: token.c:2857
_Inout_ PSE_IMPERSONATION_STATE ImpersonationState
Definition: psfuncs.h:189
#define _Inout_
Definition: ms_sal.h:378
const LUID SeIncreaseQuotaPrivilege
Definition: priv.c:24
#define TOKEN_WRITE
Definition: setypes.h:918
VOID NTAPI SepReleaseAcl(_In_ PACL CapturedAcl, _In_ KPROCESSOR_MODE AccessMode, _In_ BOOLEAN CaptureIfKernel)
Releases (frees) a captured ACL from the memory pool.
Definition: acl.c:459
#define PsGetCurrentThread()
Definition: env_spec_w32.h:81
#define THREAD_IMPERSONATE
Definition: pstypes.h:151
const LUID SeCreateTokenPrivilege
Definition: priv.c:21
VOID NTAPI SeReleaseSidAndAttributesArray(_In_ _Post_invalid_ PSID_AND_ATTRIBUTES CapturedSidAndAttributes, _In_ KPROCESSOR_MODE AccessMode, _In_ BOOLEAN CaptureIfKernel)
Releases a captured SID with attributes.
Definition: sid.c:676
struct _TOKEN_PRIMARY_GROUP * PTOKEN_PRIMARY_GROUP
#define _Out_
Definition: ms_sal.h:345
const LUID SeCreatePermanentPrivilege
Definition: priv.c:35
const LUID SeDebugPrivilege
Definition: priv.c:39
NTSTATUS NTAPI SeCaptureLuidAndAttributesArray(_In_ PLUID_AND_ATTRIBUTES Src, _In_ ULONG PrivilegeCount, _In_ KPROCESSOR_MODE PreviousMode, _In_ PLUID_AND_ATTRIBUTES AllocatedMem, _In_ ULONG AllocatedLength, _In_ POOL_TYPE PoolType, _In_ BOOLEAN CaptureIfKernel, _Out_ PLUID_AND_ATTRIBUTES *Dest, _Inout_ PULONG Length)
const LUID SeBackupPrivilege
Definition: priv.c:36
_In_ TOKEN_INFORMATION_CLASS _In_ ULONG TokenInformationLength
Definition: sefuncs.h:299
#define TRUE
Definition: types.h:120
_In_ USHORT _In_ ULONG _In_ PSOCKADDR _In_ PSOCKADDR _Reserved_ ULONG _In_opt_ PVOID _In_opt_ const WSK_CLIENT_CONNECTION_DISPATCH _In_opt_ PEPROCESS _In_opt_ PETHREAD _In_opt_ PSECURITY_DESCRIPTOR SecurityDescriptor
Definition: wsk.h:182
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
USHORT AclSize
Definition: ms-dtyp.idl:296
struct _TOKEN_DEFAULT_DACL TOKEN_DEFAULT_DACL
PACL SeSystemDefaultDacl
Definition: acl.c:17
BOOL ApplyChanges(HWND hwndDlg)
Definition: sounds.c:961
enum _TOKEN_TYPE * PTOKEN_TYPE
$ULONG GroupCount
Definition: setypes.h:1058
NTSTATUS NTAPI SepCaptureSid(_In_ PSID InputSid, _In_ KPROCESSOR_MODE AccessMode, _In_ POOL_TYPE PoolType, _In_ BOOLEAN CaptureIfKernel, _Out_ PSID *CapturedSid)
Captures a SID.
Definition: sid.c:308
$ULONG DynamicCharged
Definition: setypes.h:1056
LUID AuthenticationId
Definition: setypes.h:201
ULONG SessionId
Definition: dllmain.c:28
NTSYSAPI NTSTATUS NTAPI RtlCopySidAndAttributesArray(_In_ ULONG Count, _In_ PSID_AND_ATTRIBUTES Src, _In_ ULONG SidAreaSize, _In_ PSID_AND_ATTRIBUTES Dest, _In_ PSID SidArea, _Out_ PSID *RemainingSidArea, _Out_ PULONG RemainingSidAreaSize)
#define KeGetPreviousMode()
Definition: ketypes.h:1107
#define STATUS_CANT_OPEN_ANONYMOUS
Definition: ntstatus.h:402
LONG NTSTATUS
Definition: precomp.h:26
_IRQL_requires_same_ _In_ PLSA_STRING _In_ SECURITY_LOGON_TYPE _In_ ULONG _In_ ULONG _In_opt_ PTOKEN_GROUPS _In_ PTOKEN_SOURCE _Out_ PVOID _Out_ PULONG _Inout_ PLUID _Out_ PHANDLE Token
#define SE_RESTORE_PRIVILEGE
Definition: security.c:672
struct _LUID_AND_ATTRIBUTES LUID_AND_ATTRIBUTES
static NTSTATUS SepImpersonateAnonymousToken(_In_ PETHREAD Thread, _In_ KPROCESSOR_MODE PreviousMode)
Private function that impersonates the system's anonymous logon token. The major bulk of the imperson...
Definition: token.c:379
NTSTATUS NTAPI NtCompareTokens(_In_ HANDLE FirstTokenHandle, _In_ HANDLE SecondTokenHandle, _Out_ PBOOLEAN Equal)
Compares tokens if they're equal or not.
Definition: token.c:5754
LUID SeSystemAuthenticationId
Definition: token.c:22
_Out_ PBOOLEAN CopyOnOpen
Definition: psfuncs.h:154
NTSTATUS ExInitializeResourceLite(PULONG res)
Definition: env_spec_w32.h:641
NTSTATUS NTAPI ExDeleteResourceLite(IN PERESOURCE Resource)
Definition: resource.c:1456
PVOID PACCESS_TOKEN
Definition: setypes.h:11
#define SE_PRIVILEGE_REMOVED
Definition: setypes.h:64
PTOKEN SeAnonymousLogonToken
Definition: semgr.c:19
#define TOKEN_HAS_TRAVERSE_PRIVILEGE
Definition: setypes.h:1143
KPROCESSOR_MODE NTAPI ExGetPreviousMode(VOID)
Definition: sysinfo.c:3070
_IRQL_requires_same_ typedef _In_ ULONG _In_ UCHAR Level
Definition: wmitypes.h:55
const LUID SeAssignPrimaryTokenPrivilege
Definition: priv.c:22
#define TOKEN_IMPERSONATE
Definition: setypes.h:892
NTSYSAPI NTSTATUS NTAPI RtlCreateSecurityDescriptor(_Out_ PSECURITY_DESCRIPTOR SecurityDescriptor, _In_ ULONG Revision)
#define _When_(expr, annos)
Definition: ms_sal.h:254