ReactOS  0.4.15-dev-4921-g25fcdc5
tokenlif.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: Access token lifetime management implementation (Creation/Duplication/Filtering)
5  * COPYRIGHT: Copyright David Welch <welch@cwcom.net>
6  * Copyright 2021-2022 George BiČ™oc <george.bisoc@reactos.org>
7  */
8 
9 /* INCLUDES *******************************************************************/
10 
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14 
15 /* DEFINES ********************************************************************/
16 
17 #define SE_TOKEN_DYNAMIC_SLIM 500
18 
19 /* PRIVATE FUNCTIONS *********************************************************/
20 
96 NTAPI
104  _In_ PLUID AuthenticationId,
105  _In_ PLARGE_INTEGER ExpirationTime,
107  _In_ ULONG GroupCount,
109  _In_ ULONG GroupsLength,
110  _In_ ULONG PrivilegeCount,
114  _In_opt_ PACL DefaultDacl,
116  _In_ BOOLEAN SystemToken)
117 {
119  PTOKEN AccessToken;
120  ULONG TokenFlags = 0;
121  ULONG PrimaryGroupIndex, DefaultOwnerIndex;
122  LUID TokenId;
123  LUID ModifiedId;
124  PVOID EndMem;
125  ULONG PrivilegesLength;
126  ULONG UserGroupsLength;
127  ULONG VariableLength;
128  ULONG DynamicPartSize, TotalSize;
129  ULONG TokenPagedCharges;
130  ULONG i;
131 
132  PAGED_CODE();
133 
134  /* Loop all groups */
135  for (i = 0; i < GroupCount; i++)
136  {
137  /* Check for mandatory groups */
139  {
140  /* Force them to be enabled */
142  }
143 
144  /* Check of the group is an admin group */
146  {
147  /* Remember this so we can optimize queries later */
148  TokenFlags |= TOKEN_HAS_ADMIN_GROUP;
149  }
150  }
151 
152  /* Allocate unique IDs for the token */
153  ExAllocateLocallyUniqueId(&TokenId);
154  ExAllocateLocallyUniqueId(&ModifiedId);
155 
156  /* Compute how much size we need to allocate for the token */
157 
158  /* Privileges size */
159  PrivilegesLength = PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
160  PrivilegesLength = ALIGN_UP_BY(PrivilegesLength, sizeof(PVOID));
161 
162  /* User and groups size */
163  UserGroupsLength = (1 + GroupCount) * sizeof(SID_AND_ATTRIBUTES);
164  UserGroupsLength += RtlLengthSid(User->Sid);
165  for (i = 0; i < GroupCount; i++)
166  {
167  UserGroupsLength += RtlLengthSid(Groups[i].Sid);
168  }
169  UserGroupsLength = ALIGN_UP_BY(UserGroupsLength, sizeof(PVOID));
170 
171  /* Add the additional groups array length */
172  UserGroupsLength += ALIGN_UP_BY(GroupsLength, sizeof(PVOID));
173 
174  VariableLength = PrivilegesLength + UserGroupsLength;
175  TotalSize = FIELD_OFFSET(TOKEN, VariablePart) + VariableLength;
176 
177  /*
178  * A token is considered slim if it has the default dynamic
179  * contents, or in other words, the primary group and ACL.
180  * We judge if such contents are default by checking their
181  * total size if it's over the range. On Windows this range
182  * is 0x1F4 (aka 500). If the size of the whole dynamic contents
183  * is over that range then the token is considered fat and
184  * the token will be charged the whole of its token body length
185  * plus the dynamic size.
186  */
187  DynamicPartSize = DefaultDacl ? DefaultDacl->AclSize : 0;
188  DynamicPartSize += RtlLengthSid(PrimaryGroup);
189  if (DynamicPartSize > SE_TOKEN_DYNAMIC_SLIM)
190  {
191  TokenPagedCharges = DynamicPartSize + TotalSize;
192  }
193  else
194  {
195  TokenPagedCharges = SE_TOKEN_DYNAMIC_SLIM + TotalSize;
196  }
197 
201  PreviousMode,
202  NULL,
203  TotalSize,
204  TokenPagedCharges,
205  0,
206  (PVOID*)&AccessToken);
207  if (!NT_SUCCESS(Status))
208  {
209  DPRINT1("ObCreateObject() failed (Status 0x%lx)\n", Status);
210  return Status;
211  }
212 
213  /* Zero out the buffer and initialize the token */
214  RtlZeroMemory(AccessToken, TotalSize);
215 
216  AccessToken->TokenId = TokenId;
217  AccessToken->TokenType = TokenType;
218  AccessToken->ImpersonationLevel = ImpersonationLevel;
219 
220  /* Initialise the lock for the access token */
221  Status = SepCreateTokenLock(AccessToken);
222  if (!NT_SUCCESS(Status))
223  goto Quit;
224 
225  AccessToken->TokenSource.SourceIdentifier = TokenSource->SourceIdentifier;
226  RtlCopyMemory(AccessToken->TokenSource.SourceName,
227  TokenSource->SourceName,
228  sizeof(TokenSource->SourceName));
229 
230  AccessToken->ExpirationTime = *ExpirationTime;
231  AccessToken->ModifiedId = ModifiedId;
232  AccessToken->DynamicCharged = TokenPagedCharges - TotalSize;
233 
234  AccessToken->TokenFlags = TokenFlags & ~TOKEN_SESSION_NOT_REFERENCED;
235 
236  /* Copy and reference the logon session */
237  AccessToken->AuthenticationId = *AuthenticationId;
238  Status = SepRmReferenceLogonSession(&AccessToken->AuthenticationId);
239  if (!NT_SUCCESS(Status))
240  {
241  /* No logon session could be found, bail out */
242  DPRINT1("SepRmReferenceLogonSession() failed (Status 0x%lx)\n", Status);
243  /* Set the flag for proper cleanup by the delete procedure */
244  AccessToken->TokenFlags |= TOKEN_SESSION_NOT_REFERENCED;
245  goto Quit;
246  }
247 
248  /* Insert the referenced logon session into the token */
250  if (!NT_SUCCESS(Status))
251  {
252  /* Failed to insert the logon session into the token, bail out */
253  DPRINT1("SepRmInsertLogonSessionIntoToken() failed (Status 0x%lx)\n", Status);
254  goto Quit;
255  }
256 
257  /* Fill in token debug information */
258 #if DBG
259  /*
260  * We must determine ourselves that the current
261  * process is not the initial CPU one. The initial
262  * process is not a "real" process, that is, the
263  * Process Manager has not yet been initialized and
264  * as a matter of fact we are creating a token before
265  * any process gets created by Ps. If it turns out
266  * that the current process is the initial CPU process
267  * where token creation execution takes place, don't
268  * do anything.
269  */
271  {
272  RtlCopyMemory(AccessToken->ImageFileName,
273  PsGetCurrentProcess()->ImageFileName,
274  min(sizeof(AccessToken->ImageFileName), sizeof(PsGetCurrentProcess()->ImageFileName)));
275 
276  AccessToken->ProcessCid = PsGetCurrentProcessId();
277  AccessToken->ThreadCid = PsGetCurrentThreadId();
278  }
279 
280  AccessToken->CreateMethod = TOKEN_CREATE_METHOD;
281 #endif
282 
283  /* Assign the data that reside in the token's variable information area */
284  AccessToken->VariableLength = VariableLength;
285  EndMem = (PVOID)&AccessToken->VariablePart;
286 
287  /* Copy the privileges */
288  AccessToken->PrivilegeCount = PrivilegeCount;
289  AccessToken->Privileges = NULL;
290  if (PrivilegeCount > 0)
291  {
292  AccessToken->Privileges = EndMem;
293  EndMem = (PVOID)((ULONG_PTR)EndMem + PrivilegesLength);
294  VariableLength -= PrivilegesLength;
295 
296  if (PreviousMode != KernelMode)
297  {
298  _SEH2_TRY
299  {
300  RtlCopyMemory(AccessToken->Privileges,
301  Privileges,
302  PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
303  }
305  {
307  }
308  _SEH2_END;
309  }
310  else
311  {
312  RtlCopyMemory(AccessToken->Privileges,
313  Privileges,
314  PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
315  }
316 
317  if (!NT_SUCCESS(Status))
318  goto Quit;
319  }
320 
321  /* Update the privilege flags */
322  SepUpdatePrivilegeFlagsToken(AccessToken);
323 
324  /* Copy the user and groups */
325  AccessToken->UserAndGroupCount = 1 + GroupCount;
326  AccessToken->UserAndGroups = EndMem;
327  EndMem = &AccessToken->UserAndGroups[AccessToken->UserAndGroupCount];
328  VariableLength -= ((ULONG_PTR)EndMem - (ULONG_PTR)AccessToken->UserAndGroups);
329 
331  User,
332  VariableLength,
333  &AccessToken->UserAndGroups[0],
334  EndMem,
335  &EndMem,
336  &VariableLength);
337  if (!NT_SUCCESS(Status))
338  goto Quit;
339 
341  Groups,
342  VariableLength,
343  &AccessToken->UserAndGroups[1],
344  EndMem,
345  &EndMem,
346  &VariableLength);
347  if (!NT_SUCCESS(Status))
348  goto Quit;
349 
350  /* Find the token primary group and default owner */
352  PrimaryGroup,
353  Owner,
354  &PrimaryGroupIndex,
355  &DefaultOwnerIndex);
356  if (!NT_SUCCESS(Status))
357  {
358  DPRINT1("SepFindPrimaryGroupAndDefaultOwner failed (Status 0x%lx)\n", Status);
359  goto Quit;
360  }
361 
362  /*
363  * Now allocate the token's dynamic information area
364  * and set the data. The dynamic part consists of two
365  * contents, the primary group SID and the default DACL
366  * of the token, in this strict order.
367  */
368  AccessToken->DynamicPart = ExAllocatePoolWithTag(PagedPool,
369  DynamicPartSize,
371  if (AccessToken->DynamicPart == NULL)
372  {
374  goto Quit;
375  }
376 
377  /* Unused memory in the dynamic area */
378  AccessToken->DynamicAvailable = 0;
379 
380  /*
381  * Assign the primary group to the token
382  * and put it in the dynamic part as well.
383  */
384  EndMem = (PVOID)AccessToken->DynamicPart;
385  AccessToken->PrimaryGroup = EndMem;
386  RtlCopySid(RtlLengthSid(AccessToken->UserAndGroups[PrimaryGroupIndex].Sid),
387  EndMem,
388  AccessToken->UserAndGroups[PrimaryGroupIndex].Sid);
389  AccessToken->DefaultOwnerIndex = DefaultOwnerIndex;
390  EndMem = (PVOID)((ULONG_PTR)EndMem + RtlLengthSid(AccessToken->UserAndGroups[PrimaryGroupIndex].Sid));
391 
392  /*
393  * We have assigned a primary group and put it in the
394  * dynamic part, now it's time to copy the provided
395  * default DACL (if it's provided to begin with) into
396  * the DACL field of the token and put it at the end
397  * tail of the dynamic part too.
398  */
399  if (DefaultDacl != NULL)
400  {
401  AccessToken->DefaultDacl = EndMem;
402 
403  RtlCopyMemory(EndMem,
404  DefaultDacl,
405  DefaultDacl->AclSize);
406  }
407 
408  /* Insert the token only if it's not the system token, otherwise return it directly */
409  if (!SystemToken)
410  {
411  Status = ObInsertObject(AccessToken,
412  NULL,
414  0,
415  NULL,
416  TokenHandle);
417  if (!NT_SUCCESS(Status))
418  {
419  DPRINT1("ObInsertObject() failed (Status 0x%lx)\n", Status);
420  }
421  }
422  else
423  {
424  /* Return pointer instead of handle */
425  *TokenHandle = (HANDLE)AccessToken;
426  }
427 
428 Quit:
429  if (!NT_SUCCESS(Status))
430  {
431  /* Dereference the token, the delete procedure will clean it up */
432  ObDereferenceObject(AccessToken);
433  }
434 
435  return Status;
436 }
437 
469 NTSTATUS
470 NTAPI
472  _In_ PTOKEN Token,
478  _Out_ PTOKEN* NewAccessToken)
479 {
481  PTOKEN AccessToken;
482  PVOID EndMem;
483  ULONG PrimaryGroupIndex;
484  ULONG VariableLength;
485  ULONG DynamicPartSize, TotalSize;
486  ULONG PrivilegesIndex, GroupsIndex;
487 
488  PAGED_CODE();
489 
490  /* Compute how much size we need to allocate for the token */
491  VariableLength = Token->VariableLength;
492  TotalSize = FIELD_OFFSET(TOKEN, VariablePart) + VariableLength;
493 
494  /*
495  * Compute how much size we need to allocate
496  * the dynamic part of the newly duplicated
497  * token.
498  */
499  DynamicPartSize = Token->DefaultDacl ? Token->DefaultDacl->AclSize : 0;
500  DynamicPartSize += RtlLengthSid(Token->PrimaryGroup);
501 
505  PreviousMode,
506  NULL,
507  TotalSize,
508  Token->DynamicCharged,
509  TotalSize,
510  (PVOID*)&AccessToken);
511  if (!NT_SUCCESS(Status))
512  {
513  DPRINT1("ObCreateObject() failed (Status 0x%lx)\n", Status);
514  return Status;
515  }
516 
517  /* Zero out the buffer and initialize the token */
518  RtlZeroMemory(AccessToken, TotalSize);
519 
520  ExAllocateLocallyUniqueId(&AccessToken->TokenId);
521 
522  AccessToken->TokenType = TokenType;
523  AccessToken->ImpersonationLevel = Level;
524 
525  /* Initialise the lock for the access token */
526  Status = SepCreateTokenLock(AccessToken);
527  if (!NT_SUCCESS(Status))
528  {
529  ObDereferenceObject(AccessToken);
530  return Status;
531  }
532 
533  /* Copy the immutable fields */
534  AccessToken->TokenSource.SourceIdentifier = Token->TokenSource.SourceIdentifier;
535  RtlCopyMemory(AccessToken->TokenSource.SourceName,
536  Token->TokenSource.SourceName,
537  sizeof(Token->TokenSource.SourceName));
538 
539  AccessToken->AuthenticationId = Token->AuthenticationId;
540  AccessToken->ParentTokenId = Token->ParentTokenId;
541  AccessToken->ExpirationTime = Token->ExpirationTime;
542  AccessToken->OriginatingLogonSession = Token->OriginatingLogonSession;
543  AccessToken->DynamicCharged = Token->DynamicCharged;
544 
545  /* Lock the source token and copy the mutable fields */
547 
548  AccessToken->SessionId = Token->SessionId;
549  AccessToken->ModifiedId = Token->ModifiedId;
550 
551  AccessToken->TokenFlags = Token->TokenFlags & ~TOKEN_SESSION_NOT_REFERENCED;
552 
553  /* Reference the logon session */
554  Status = SepRmReferenceLogonSession(&AccessToken->AuthenticationId);
555  if (!NT_SUCCESS(Status))
556  {
557  /* No logon session could be found, bail out */
558  DPRINT1("SepRmReferenceLogonSession() failed (Status 0x%lx)\n", Status);
559  /* Set the flag for proper cleanup by the delete procedure */
560  AccessToken->TokenFlags |= TOKEN_SESSION_NOT_REFERENCED;
561  goto Quit;
562  }
563 
564  /* Insert the referenced logon session into the token */
566  if (!NT_SUCCESS(Status))
567  {
568  /* Failed to insert the logon session into the token, bail out */
569  DPRINT1("SepRmInsertLogonSessionIntoToken() failed (Status 0x%lx)\n", Status);
570  goto Quit;
571  }
572 
573  /* Fill in token debug information */
574 #if DBG
575  RtlCopyMemory(AccessToken->ImageFileName,
576  PsGetCurrentProcess()->ImageFileName,
577  min(sizeof(AccessToken->ImageFileName), sizeof(PsGetCurrentProcess()->ImageFileName)));
578 
579  AccessToken->ProcessCid = PsGetCurrentProcessId();
580  AccessToken->ThreadCid = PsGetCurrentThreadId();
581  AccessToken->CreateMethod = TOKEN_DUPLICATE_METHOD;
582 #endif
583 
584  /* Assign the data that reside in the token's variable information area */
585  AccessToken->VariableLength = VariableLength;
586  EndMem = (PVOID)&AccessToken->VariablePart;
587 
588  /* Copy the privileges */
589  AccessToken->PrivilegeCount = 0;
590  AccessToken->Privileges = NULL;
591  if (Token->Privileges && (Token->PrivilegeCount > 0))
592  {
593  ULONG PrivilegesLength = Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
594  PrivilegesLength = ALIGN_UP_BY(PrivilegesLength, sizeof(PVOID));
595 
596  ASSERT(VariableLength >= PrivilegesLength);
597 
598  AccessToken->PrivilegeCount = Token->PrivilegeCount;
599  AccessToken->Privileges = EndMem;
600  EndMem = (PVOID)((ULONG_PTR)EndMem + PrivilegesLength);
601  VariableLength -= PrivilegesLength;
602 
603  RtlCopyMemory(AccessToken->Privileges,
604  Token->Privileges,
605  AccessToken->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
606  }
607 
608  /* Copy the user and groups */
609  AccessToken->UserAndGroupCount = 0;
610  AccessToken->UserAndGroups = NULL;
611  if (Token->UserAndGroups && (Token->UserAndGroupCount > 0))
612  {
613  AccessToken->UserAndGroupCount = Token->UserAndGroupCount;
614  AccessToken->UserAndGroups = EndMem;
615  EndMem = &AccessToken->UserAndGroups[AccessToken->UserAndGroupCount];
616  VariableLength -= ((ULONG_PTR)EndMem - (ULONG_PTR)AccessToken->UserAndGroups);
617 
618  Status = RtlCopySidAndAttributesArray(AccessToken->UserAndGroupCount,
619  Token->UserAndGroups,
620  VariableLength,
621  AccessToken->UserAndGroups,
622  EndMem,
623  &EndMem,
624  &VariableLength);
625  if (!NT_SUCCESS(Status))
626  {
627  DPRINT1("RtlCopySidAndAttributesArray(UserAndGroups) failed (Status 0x%lx)\n", Status);
628  goto Quit;
629  }
630  }
631 
632  /* Find the token primary group */
634  Token->PrimaryGroup,
635  NULL,
636  &PrimaryGroupIndex,
637  NULL);
638  if (!NT_SUCCESS(Status))
639  {
640  DPRINT1("SepFindPrimaryGroupAndDefaultOwner failed (Status 0x%lx)\n", Status);
641  goto Quit;
642  }
643 
644  /* Copy the restricted SIDs */
645  AccessToken->RestrictedSidCount = 0;
646  AccessToken->RestrictedSids = NULL;
647  if (Token->RestrictedSids && (Token->RestrictedSidCount > 0))
648  {
649  AccessToken->RestrictedSidCount = Token->RestrictedSidCount;
650  AccessToken->RestrictedSids = EndMem;
651  EndMem = &AccessToken->RestrictedSids[AccessToken->RestrictedSidCount];
652  VariableLength -= ((ULONG_PTR)EndMem - (ULONG_PTR)AccessToken->RestrictedSids);
653 
654  Status = RtlCopySidAndAttributesArray(AccessToken->RestrictedSidCount,
655  Token->RestrictedSids,
656  VariableLength,
657  AccessToken->RestrictedSids,
658  EndMem,
659  &EndMem,
660  &VariableLength);
661  if (!NT_SUCCESS(Status))
662  {
663  DPRINT1("RtlCopySidAndAttributesArray(RestrictedSids) failed (Status 0x%lx)\n", Status);
664  goto Quit;
665  }
666  }
667 
668  /*
669  * Filter the token by removing the disabled privileges
670  * and groups if the caller wants to duplicate an access
671  * token as effective only.
672  */
673  if (EffectiveOnly)
674  {
675  /* Begin querying the groups and search for disabled ones */
676  for (GroupsIndex = 0; GroupsIndex < AccessToken->UserAndGroupCount; GroupsIndex++)
677  {
678  /*
679  * A group or user is considered disabled if its attributes is either
680  * 0 or SE_GROUP_ENABLED is not included in the attributes flags list.
681  * That is because a certain user and/or group can have several attributes
682  * that bear no influence on whether a user/group is enabled or not
683  * (SE_GROUP_ENABLED_BY_DEFAULT for example which is a mere indicator
684  * that the group has just been enabled by default). A mandatory
685  * group (that is, the group has SE_GROUP_MANDATORY attribute)
686  * by standards it's always enabled and no one can disable it.
687  */
688  if (AccessToken->UserAndGroups[GroupsIndex].Attributes == 0 ||
689  (AccessToken->UserAndGroups[GroupsIndex].Attributes & SE_GROUP_ENABLED) == 0)
690  {
691  /*
692  * If this group is an administrators group
693  * and the token belongs to such group,
694  * we've to take away TOKEN_HAS_ADMIN_GROUP
695  * for the fact that's not enabled and as
696  * such the token no longer belongs to
697  * this group.
698  */
700  &AccessToken->UserAndGroups[GroupsIndex].Sid))
701  {
702  AccessToken->TokenFlags &= ~TOKEN_HAS_ADMIN_GROUP;
703  }
704 
705  /*
706  * A group is not enabled, it's time to remove
707  * from the token and update the groups index
708  * accordingly and continue with the next group.
709  */
710  SepRemoveUserGroupToken(AccessToken, GroupsIndex);
711  GroupsIndex--;
712  }
713  }
714 
715  /* Begin querying the privileges and search for disabled ones */
716  for (PrivilegesIndex = 0; PrivilegesIndex < AccessToken->PrivilegeCount; PrivilegesIndex++)
717  {
718  /*
719  * A privilege is considered disabled if its attributes is either
720  * 0 or SE_PRIVILEGE_ENABLED is not included in the attributes flags list.
721  * That is because a certain privilege can have several attributes
722  * that bear no influence on whether a privilege is enabled or not
723  * (SE_PRIVILEGE_ENABLED_BY_DEFAULT for example which is a mere indicator
724  * that the privilege has just been enabled by default).
725  */
726  if (AccessToken->Privileges[PrivilegesIndex].Attributes == 0 ||
727  (AccessToken->Privileges[PrivilegesIndex].Attributes & SE_PRIVILEGE_ENABLED) == 0)
728  {
729  /*
730  * A privilege is not enabled, therefor it's time
731  * to strip it from the token and continue with the next
732  * privilege. Of course we must also want to update the
733  * privileges index accordingly.
734  */
735  SepRemovePrivilegeToken(AccessToken, PrivilegesIndex);
736  PrivilegesIndex--;
737  }
738  }
739  }
740 
741  /* Now allocate the token's dynamic information area and set the data */
742  AccessToken->DynamicPart = ExAllocatePoolWithTag(PagedPool,
743  DynamicPartSize,
745  if (AccessToken->DynamicPart == NULL)
746  {
748  goto Quit;
749  }
750 
751  /* Unused memory in the dynamic area */
752  AccessToken->DynamicAvailable = 0;
753 
754  /*
755  * Assign the primary group to the token
756  * and put it in the dynamic part as well.
757  */
758  EndMem = (PVOID)AccessToken->DynamicPart;
759  AccessToken->PrimaryGroup = EndMem;
760  RtlCopySid(RtlLengthSid(AccessToken->UserAndGroups[PrimaryGroupIndex].Sid),
761  EndMem,
762  AccessToken->UserAndGroups[PrimaryGroupIndex].Sid);
763  AccessToken->DefaultOwnerIndex = Token->DefaultOwnerIndex;
764  EndMem = (PVOID)((ULONG_PTR)EndMem + RtlLengthSid(AccessToken->UserAndGroups[PrimaryGroupIndex].Sid));
765 
766  /*
767  * The existing token has a default DACL only
768  * if it has an allocated dynamic part.
769  */
770  if (Token->DynamicPart && Token->DefaultDacl)
771  {
772  AccessToken->DefaultDacl = EndMem;
773 
774  RtlCopyMemory(EndMem,
775  Token->DefaultDacl,
776  Token->DefaultDacl->AclSize);
777  }
778 
779  /* Return the token to the caller */
780  *NewAccessToken = AccessToken;
782 
783 Quit:
784  if (!NT_SUCCESS(Status))
785  {
786  /* Dereference the token, the delete procedure will clean it up */
787  ObDereferenceObject(AccessToken);
788  }
789 
790  /* Unlock the source token */
792 
793  return Status;
794 }
795 
853 static
854 NTSTATUS
856  _In_ PTOKEN Token,
857  _In_opt_ PLUID_AND_ATTRIBUTES PrivilegesToBeDeleted,
858  _In_opt_ PSID_AND_ATTRIBUTES SidsToBeDisabled,
859  _In_opt_ PSID_AND_ATTRIBUTES RestrictedSidsIntoToken,
860  _When_(PrivilegesToBeDeleted != NULL, _In_) ULONG PrivilegesCount,
861  _When_(SidsToBeDisabled != NULL, _In_) ULONG RegularGroupsSidCount,
862  _When_(RestrictedSidsIntoToken != NULL, _In_) ULONG RestrictedSidsCount,
863  _In_ ULONG PrivilegeFlags,
865  _Out_ PTOKEN *FilteredToken)
866 {
868  PTOKEN AccessToken;
869  PVOID EndMem;
870  ULONG DynamicPartSize;
871  ULONG RestrictedSidsLength;
872  ULONG PrivilegesLength;
873  ULONG PrimaryGroupIndex;
874  ULONG RestrictedSidsInList;
875  ULONG RestrictedSidsInToken;
876  ULONG VariableLength, TotalSize;
877  ULONG PrivsInToken, PrivsInList;
878  ULONG GroupsInToken, GroupsInList;
879  BOOLEAN WantPrivilegesDisabled;
880  BOOLEAN FoundPrivilege;
881  BOOLEAN FoundGroup;
882 
883  PAGED_CODE();
884 
885  /* Ensure that the source token is valid, and lock it */
886  ASSERT(Token);
888 
889  /* Assume the caller doesn't want privileges disabled */
890  WantPrivilegesDisabled = FALSE;
891 
892  /* Assume we haven't found anything */
893  FoundPrivilege = FALSE;
894  FoundGroup = FALSE;
895 
896  /*
897  * Take the size that we need for filtered token
898  * allocation based upon the existing access token
899  * we've been given.
900  */
901  VariableLength = Token->VariableLength;
902 
903  if (RestrictedSidsIntoToken != NULL)
904  {
905  /*
906  * If the caller provided a list of restricted SIDs
907  * to be added onto the filtered access token then
908  * we must compute the size which is the total space
909  * of the current token and the length of the restricted
910  * SIDs for the filtered token.
911  */
912  RestrictedSidsLength = RestrictedSidsCount * sizeof(SID_AND_ATTRIBUTES);
913  RestrictedSidsLength += RtlLengthSidAndAttributes(RestrictedSidsCount, RestrictedSidsIntoToken);
914  RestrictedSidsLength = ALIGN_UP_BY(RestrictedSidsLength, sizeof(PVOID));
915 
916  /*
917  * The variable length of the token is not just
918  * the actual space length of the existing token
919  * but also the sum of the restricted SIDs length.
920  */
921  VariableLength += RestrictedSidsLength;
922  TotalSize = FIELD_OFFSET(TOKEN, VariablePart) + VariableLength + RestrictedSidsLength;
923  }
924  else
925  {
926  /* Otherwise the size is of the actual current token */
927  TotalSize = FIELD_OFFSET(TOKEN, VariablePart) + VariableLength;
928  }
929 
930  /*
931  * Compute how much size we need to allocate
932  * the dynamic part of the newly duplicated
933  * token.
934  */
935  DynamicPartSize = Token->DefaultDacl ? Token->DefaultDacl->AclSize : 0;
936  DynamicPartSize += RtlLengthSid(Token->PrimaryGroup);
937 
938  /* Set up a filtered token object */
941  NULL,
942  PreviousMode,
943  NULL,
944  TotalSize,
945  Token->DynamicCharged,
946  TotalSize,
947  (PVOID*)&AccessToken);
948  if (!NT_SUCCESS(Status))
949  {
950  DPRINT1("SepPerformTokenFiltering(): Failed to create the filtered token object (Status 0x%lx)\n", Status);
951 
952  /* Unlock the source token and bail out */
954  return Status;
955  }
956 
957  /* Initialize the token and begin filling stuff to it */
958  RtlZeroMemory(AccessToken, TotalSize);
959 
960  /* Set up a lock for the new token */
961  Status = SepCreateTokenLock(AccessToken);
962  if (!NT_SUCCESS(Status))
963  goto Quit;
964 
965  /* Allocate new IDs for the token */
966  ExAllocateLocallyUniqueId(&AccessToken->TokenId);
967  ExAllocateLocallyUniqueId(&AccessToken->ModifiedId);
968 
969  /* Copy the type and impersonation level from the token */
970  AccessToken->TokenType = Token->TokenType;
971  AccessToken->ImpersonationLevel = Token->ImpersonationLevel;
972 
973  /* Copy the immutable fields */
974  AccessToken->TokenSource.SourceIdentifier = Token->TokenSource.SourceIdentifier;
975  RtlCopyMemory(AccessToken->TokenSource.SourceName,
976  Token->TokenSource.SourceName,
977  sizeof(Token->TokenSource.SourceName));
978 
979  AccessToken->AuthenticationId = Token->AuthenticationId;
980  AccessToken->ParentTokenId = Token->TokenId;
981  AccessToken->OriginatingLogonSession = Token->OriginatingLogonSession;
982  AccessToken->DynamicCharged = Token->DynamicCharged;
983 
984  AccessToken->ExpirationTime = Token->ExpirationTime;
985 
986  /* Copy the mutable fields */
987  AccessToken->SessionId = Token->SessionId;
988  AccessToken->TokenFlags = Token->TokenFlags & ~TOKEN_SESSION_NOT_REFERENCED;
989 
990  /* Reference the logon session */
991  Status = SepRmReferenceLogonSession(&AccessToken->AuthenticationId);
992  if (!NT_SUCCESS(Status))
993  {
994  /* We failed, bail out*/
995  DPRINT1("SepPerformTokenFiltering(): Failed to reference the logon session (Status 0x%lx)\n", Status);
996  AccessToken->TokenFlags |= TOKEN_SESSION_NOT_REFERENCED;
997  goto Quit;
998  }
999 
1000  /* Insert the referenced logon session into the token */
1002  if (!NT_SUCCESS(Status))
1003  {
1004  /* Failed to insert the logon session into the token, bail out */
1005  DPRINT1("SepPerformTokenFiltering(): Failed to insert the logon session into token (Status 0x%lx)\n", Status);
1006  goto Quit;
1007  }
1008 
1009  /* Fill in token debug information */
1010 #if DBG
1011  RtlCopyMemory(AccessToken->ImageFileName,
1012  PsGetCurrentProcess()->ImageFileName,
1013  min(sizeof(AccessToken->ImageFileName), sizeof(PsGetCurrentProcess()->ImageFileName)));
1014 
1015  AccessToken->ProcessCid = PsGetCurrentProcessId();
1016  AccessToken->ThreadCid = PsGetCurrentThreadId();
1017  AccessToken->CreateMethod = TOKEN_FILTER_METHOD;
1018 #endif
1019 
1020  /* Assign the data that reside in the token's variable information area */
1021  AccessToken->VariableLength = VariableLength;
1022  EndMem = (PVOID)&AccessToken->VariablePart;
1023 
1024  /* Copy the privileges from the existing token */
1025  AccessToken->PrivilegeCount = 0;
1026  AccessToken->Privileges = NULL;
1027  if (Token->Privileges && (Token->PrivilegeCount > 0))
1028  {
1029  PrivilegesLength = Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
1030  PrivilegesLength = ALIGN_UP_BY(PrivilegesLength, sizeof(PVOID));
1031 
1032  /*
1033  * Ensure that the token can actually hold all
1034  * the privileges from the existing token.
1035  * Otherwise something's seriously wrong and
1036  * we've to guard ourselves.
1037  */
1038  ASSERT(VariableLength >= PrivilegesLength);
1039 
1040  AccessToken->PrivilegeCount = Token->PrivilegeCount;
1041  AccessToken->Privileges = EndMem;
1042  EndMem = (PVOID)((ULONG_PTR)EndMem + PrivilegesLength);
1043  VariableLength -= PrivilegesLength;
1044 
1045  RtlCopyMemory(AccessToken->Privileges,
1046  Token->Privileges,
1047  AccessToken->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
1048  }
1049 
1050  /* Copy the user and groups */
1051  AccessToken->UserAndGroupCount = 0;
1052  AccessToken->UserAndGroups = NULL;
1053  if (Token->UserAndGroups && (Token->UserAndGroupCount > 0))
1054  {
1055  AccessToken->UserAndGroupCount = Token->UserAndGroupCount;
1056  AccessToken->UserAndGroups = EndMem;
1057  EndMem = &AccessToken->UserAndGroups[AccessToken->UserAndGroupCount];
1058  VariableLength -= ((ULONG_PTR)EndMem - (ULONG_PTR)AccessToken->UserAndGroups);
1059 
1060  Status = RtlCopySidAndAttributesArray(AccessToken->UserAndGroupCount,
1061  Token->UserAndGroups,
1062  VariableLength,
1063  AccessToken->UserAndGroups,
1064  EndMem,
1065  &EndMem,
1066  &VariableLength);
1067  if (!NT_SUCCESS(Status))
1068  {
1069  DPRINT1("SepPerformTokenFiltering(): Failed to copy the groups into token (Status 0x%lx)\n", Status);
1070  goto Quit;
1071  }
1072  }
1073 
1074  /* Copy the restricted SIDs */
1075  AccessToken->RestrictedSidCount = 0;
1076  AccessToken->RestrictedSids = NULL;
1077  if (Token->RestrictedSids && (Token->RestrictedSidCount > 0))
1078  {
1079  AccessToken->RestrictedSidCount = Token->RestrictedSidCount;
1080  AccessToken->RestrictedSids = EndMem;
1081  EndMem = &AccessToken->RestrictedSids[AccessToken->RestrictedSidCount];
1082  VariableLength -= ((ULONG_PTR)EndMem - (ULONG_PTR)AccessToken->RestrictedSids);
1083 
1084  Status = RtlCopySidAndAttributesArray(AccessToken->RestrictedSidCount,
1085  Token->RestrictedSids,
1086  VariableLength,
1087  AccessToken->RestrictedSids,
1088  EndMem,
1089  &EndMem,
1090  &VariableLength);
1091  if (!NT_SUCCESS(Status))
1092  {
1093  DPRINT1("SepPerformTokenFiltering(): Failed to copy the restricted SIDs into token (Status 0x%lx)\n", Status);
1094  goto Quit;
1095  }
1096  }
1097 
1098  /*
1099  * Insert the restricted SIDs into the token on
1100  * the request by the caller.
1101  */
1102  if (RestrictedSidsIntoToken != NULL)
1103  {
1104  for (RestrictedSidsInList = 0; RestrictedSidsInList < RestrictedSidsCount; RestrictedSidsInList++)
1105  {
1106  /* Did the caller assign attributes to the restricted SIDs? */
1107  if (RestrictedSidsIntoToken[RestrictedSidsInList].Attributes != 0)
1108  {
1109  /* There mustn't be any attributes, bail out */
1110  DPRINT1("SepPerformTokenFiltering(): There mustn't be any attributes to restricted SIDs!\n");
1112  goto Quit;
1113  }
1114  }
1115 
1116  /*
1117  * Ensure that the token can hold the restricted SIDs
1118  * (the variable length is calculated at the beginning
1119  * of the routine call).
1120  */
1121  ASSERT(VariableLength >= RestrictedSidsLength);
1122 
1123  /*
1124  * Now let's begin inserting the restricted SIDs into the filtered
1125  * access token from the list the caller gave us.
1126  */
1127  AccessToken->RestrictedSidCount = RestrictedSidsCount;
1128  AccessToken->RestrictedSids = EndMem;
1129  EndMem = (PVOID)((ULONG_PTR)EndMem + RestrictedSidsLength);
1130  VariableLength -= RestrictedSidsLength;
1131 
1132  RtlCopyMemory(AccessToken->RestrictedSids,
1133  RestrictedSidsIntoToken,
1134  AccessToken->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES));
1135 
1136  /*
1137  * As we've copied the restricted SIDs into
1138  * the token, we must assign them the following
1139  * combination of attributes SE_GROUP_ENABLED,
1140  * SE_GROUP_ENABLED_BY_DEFAULT and SE_GROUP_MANDATORY.
1141  * With such attributes we estabilish that restricting
1142  * SIDs into the token are enabled for access checks.
1143  */
1144  for (RestrictedSidsInToken = 0; RestrictedSidsInToken < AccessToken->RestrictedSidCount; RestrictedSidsInToken++)
1145  {
1146  AccessToken->RestrictedSids[RestrictedSidsInToken].Attributes |= (SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_MANDATORY);
1147  }
1148 
1149  /*
1150  * As we added restricted SIDs into the token, mark
1151  * it as restricted.
1152  */
1153  AccessToken->TokenFlags |= TOKEN_IS_RESTRICTED;
1154  }
1155 
1156  /* Search for the primary group */
1158  Token->PrimaryGroup,
1159  NULL,
1160  &PrimaryGroupIndex,
1161  NULL);
1162  if (!NT_SUCCESS(Status))
1163  {
1164  DPRINT1("SepPerformTokenFiltering(): Failed searching for the primary group (Status 0x%lx)\n", Status);
1165  goto Quit;
1166  }
1167 
1168  /* Now allocate the token's dynamic information area and set the data */
1169  AccessToken->DynamicPart = ExAllocatePoolWithTag(PagedPool,
1170  DynamicPartSize,
1172  if (AccessToken->DynamicPart == NULL)
1173  {
1175  goto Quit;
1176  }
1177 
1178  /* Unused memory in the dynamic area */
1179  AccessToken->DynamicAvailable = 0;
1180 
1181  /*
1182  * Assign the primary group to the token
1183  * and put it in the dynamic part as well.
1184  */
1185  EndMem = (PVOID)AccessToken->DynamicPart;
1186  AccessToken->PrimaryGroup = EndMem;
1187  RtlCopySid(RtlLengthSid(AccessToken->UserAndGroups[PrimaryGroupIndex].Sid),
1188  EndMem,
1189  AccessToken->UserAndGroups[PrimaryGroupIndex].Sid);
1190  AccessToken->DefaultOwnerIndex = Token->DefaultOwnerIndex;
1191  EndMem = (PVOID)((ULONG_PTR)EndMem + RtlLengthSid(AccessToken->UserAndGroups[PrimaryGroupIndex].Sid));
1192 
1193  /*
1194  * The existing token has a default DACL only
1195  * if it has an allocated dynamic part.
1196  */
1197  if (Token->DynamicPart && Token->DefaultDacl)
1198  {
1199  AccessToken->DefaultDacl = EndMem;
1200 
1201  RtlCopyMemory(EndMem,
1202  Token->DefaultDacl,
1203  Token->DefaultDacl->AclSize);
1204  }
1205 
1206  /*
1207  * Now figure out what does the caller
1208  * want with the privileges.
1209  */
1210  if (PrivilegeFlags & DISABLE_MAX_PRIVILEGE)
1211  {
1212  /*
1213  * The caller wants them disabled, cache this request
1214  * for later operations.
1215  */
1216  WantPrivilegesDisabled = TRUE;
1217  }
1218 
1219  if (PrivilegeFlags & SANDBOX_INERT)
1220  {
1221  /* The caller wants an inert token, store the TOKEN_SANDBOX_INERT flag now */
1222  AccessToken->TokenFlags |= TOKEN_SANDBOX_INERT;
1223  }
1224 
1225  /*
1226  * Now it's time to filter the token's privileges.
1227  * Loop all the privileges in the token.
1228  */
1229  for (PrivsInToken = 0; PrivsInToken < AccessToken->PrivilegeCount; PrivsInToken++)
1230  {
1231  if (WantPrivilegesDisabled)
1232  {
1233  /*
1234  * We got the acknowledgement that the caller wants
1235  * to disable all the privileges so let's just do it.
1236  * However, as per the general documentation is stated
1237  * that only SE_CHANGE_NOTIFY_PRIVILEGE must be kept
1238  * therefore in that case we must skip this privilege.
1239  */
1240  if (AccessToken->Privileges[PrivsInToken].Luid.LowPart == SE_CHANGE_NOTIFY_PRIVILEGE)
1241  {
1242  continue;
1243  }
1244  else
1245  {
1246  /*
1247  * The act of disabling privileges actually means
1248  * "deleting" them from the access token entirely.
1249  * First we must disable them so that we can update
1250  * token flags accordingly.
1251  */
1252  AccessToken->Privileges[PrivsInToken].Attributes &= ~SE_PRIVILEGE_ENABLED;
1253  SepUpdateSinglePrivilegeFlagToken(AccessToken, PrivsInToken);
1254 
1255  /* Remove the privileges now */
1256  SepRemovePrivilegeToken(AccessToken, PrivsInToken);
1257  PrivsInToken--;
1258  }
1259  }
1260  else
1261  {
1262  if (PrivilegesToBeDeleted != NULL)
1263  {
1264  /* Loop the privileges we've got to delete */
1265  for (PrivsInList = 0; PrivsInList < PrivilegesCount; PrivsInList++)
1266  {
1267  /* Does this privilege exist in the token? */
1268  if (RtlEqualLuid(&AccessToken->Privileges[PrivsInToken].Luid,
1269  &PrivilegesToBeDeleted[PrivsInList].Luid))
1270  {
1271  /* Mark that we found it */
1272  FoundPrivilege = TRUE;
1273  break;
1274  }
1275  }
1276 
1277  /* Did we find the privilege? */
1278  if (PrivsInList == PrivilegesCount)
1279  {
1280  /* We didn't, continue with next one */
1281  continue;
1282  }
1283  }
1284  }
1285 
1286  /*
1287  * If we have found the target privilege in the token
1288  * based on the privileges list given by the caller
1289  * then begin deleting it.
1290  */
1291  if (FoundPrivilege)
1292  {
1293  /* Disable the privilege and update the flags */
1294  AccessToken->Privileges[PrivsInToken].Attributes &= ~SE_PRIVILEGE_ENABLED;
1295  SepUpdateSinglePrivilegeFlagToken(AccessToken, PrivsInToken);
1296 
1297  /* Delete the privilege */
1298  SepRemovePrivilegeToken(AccessToken, PrivsInToken);
1299 
1300  /*
1301  * Adjust the index and reset the FoundPrivilege indicator
1302  * so that we can continue with the next privilege to delete.
1303  */
1304  PrivsInToken--;
1305  FoundPrivilege = FALSE;
1306  continue;
1307  }
1308  }
1309 
1310  /*
1311  * Loop the group SIDs that we want to disable as
1312  * per on the request by the caller.
1313  */
1314  if (SidsToBeDisabled != NULL)
1315  {
1316  for (GroupsInToken = 0; GroupsInToken < AccessToken->UserAndGroupCount; GroupsInToken++)
1317  {
1318  for (GroupsInList = 0; GroupsInList < RegularGroupsSidCount; GroupsInList++)
1319  {
1320  /* Does this group SID exist in the token? */
1321  if (RtlEqualSid(&AccessToken->UserAndGroups[GroupsInToken].Sid,
1322  &SidsToBeDisabled[GroupsInList].Sid))
1323  {
1324  /* Mark that we found it */
1325  FoundGroup = TRUE;
1326  break;
1327  }
1328  }
1329 
1330  /* Did we find the group? */
1331  if (GroupsInList == RegularGroupsSidCount)
1332  {
1333  /* We didn't, continue with next one */
1334  continue;
1335  }
1336 
1337  /* If we have found the group, disable it */
1338  if (FoundGroup)
1339  {
1340  /*
1341  * If the acess token belongs to the administrators
1342  * group and this is the target group, we must take
1343  * away TOKEN_HAS_ADMIN_GROUP flag from the token.
1344  */
1346  &AccessToken->UserAndGroups[GroupsInToken].Sid))
1347  {
1348  AccessToken->TokenFlags &= ~TOKEN_HAS_ADMIN_GROUP;
1349  }
1350 
1351  /*
1352  * If the target group that we have found it is the
1353  * owner then from now on it no longer is but the user.
1354  * Therefore assign the default owner index as the user.
1355  */
1356  if (AccessToken->DefaultOwnerIndex == GroupsInToken)
1357  {
1358  AccessToken->DefaultOwnerIndex = 0;
1359  }
1360 
1361  /*
1362  * The principle of disabling a group SID is by
1363  * taking away SE_GROUP_ENABLED_BY_DEFAULT and
1364  * SE_GROUP_ENABLED attributes and assign
1365  * SE_GROUP_USE_FOR_DENY_ONLY. This renders
1366  * SID a "Deny only" SID.
1367  */
1368  AccessToken->UserAndGroups[GroupsInToken].Attributes &= ~(SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT);
1369  AccessToken->UserAndGroups[GroupsInToken].Attributes |= SE_GROUP_USE_FOR_DENY_ONLY;
1370 
1371  /* Adjust the index and continue with the next group */
1372  GroupsInToken--;
1373  FoundGroup = FALSE;
1374  continue;
1375  }
1376  }
1377  }
1378 
1379  /* We've finally filtered the token, return it to the caller */
1380  *FilteredToken = AccessToken;
1382  DPRINT("SepPerformTokenFiltering(): The token has been filtered!\n");
1383 
1384 Quit:
1385  if (!NT_SUCCESS(Status))
1386  {
1387  /* Dereference the created token */
1388  ObDereferenceObject(AccessToken);
1389  }
1390 
1391  /* Unlock the source token */
1393 
1394  return Status;
1395 }
1396 
1397 /* PUBLIC FUNCTIONS ***********************************************************/
1398 
1432 NTSTATUS
1433 NTAPI
1435  _In_ PACCESS_TOKEN ExistingToken,
1436  _In_ ULONG Flags,
1437  _In_opt_ PTOKEN_GROUPS SidsToDisable,
1438  _In_opt_ PTOKEN_PRIVILEGES PrivilegesToDelete,
1439  _In_opt_ PTOKEN_GROUPS RestrictedSids,
1440  _Out_ PACCESS_TOKEN *FilteredToken)
1441 {
1442  NTSTATUS Status;
1443  PTOKEN AccessToken;
1444  ULONG PrivilegesCount = 0;
1445  ULONG SidsCount = 0;
1446  ULONG RestrictedSidsCount = 0;
1447 
1448  PAGED_CODE();
1449 
1450  /* Begin copying the counters */
1451  if (SidsToDisable != NULL)
1452  {
1453  SidsCount = SidsToDisable->GroupCount;
1454  }
1455 
1456  if (PrivilegesToDelete != NULL)
1457  {
1458  PrivilegesCount = PrivilegesToDelete->PrivilegeCount;
1459  }
1460 
1461  if (RestrictedSids != NULL)
1462  {
1463  RestrictedSidsCount = RestrictedSids->GroupCount;
1464  }
1465 
1466  /* Call the internal API */
1467  Status = SepPerformTokenFiltering(ExistingToken,
1468  PrivilegesToDelete->Privileges,
1469  SidsToDisable->Groups,
1470  RestrictedSids->Groups,
1471  PrivilegesCount,
1472  SidsCount,
1473  RestrictedSidsCount,
1474  Flags,
1475  KernelMode,
1476  &AccessToken);
1477  if (!NT_SUCCESS(Status))
1478  {
1479  DPRINT1("SeFilterToken(): Failed to filter the token (Status 0x%lx)\n", Status);
1480  return Status;
1481  }
1482 
1483  /* Insert the filtered token */
1484  Status = ObInsertObject(AccessToken,
1485  NULL,
1486  0,
1487  0,
1488  NULL,
1489  NULL);
1490  if (!NT_SUCCESS(Status))
1491  {
1492  DPRINT1("SeFilterToken(): Failed to insert the filtered token (Status 0x%lx)\n", Status);
1493  return Status;
1494  }
1495 
1496  /* Return it to the caller */
1497  *FilteredToken = AccessToken;
1498  return Status;
1499 }
1500 
1501 /* SYSTEM CALLS ***************************************************************/
1502 
1552 NTSTATUS
1553 NTAPI
1559  _In_ PLUID AuthenticationId,
1560  _In_ PLARGE_INTEGER ExpirationTime,
1568 {
1569  HANDLE hToken;
1571  ULONG PrivilegeCount, GroupCount;
1572  PSID OwnerSid, PrimaryGroupSid;
1573  PACL DefaultDacl;
1574  LARGE_INTEGER LocalExpirationTime = {{0, 0}};
1575  LUID LocalAuthenticationId;
1576  TOKEN_SOURCE LocalTokenSource;
1577  SECURITY_QUALITY_OF_SERVICE LocalSecurityQos;
1578  PLUID_AND_ATTRIBUTES CapturedPrivileges = NULL;
1579  PSID_AND_ATTRIBUTES CapturedUser = NULL;
1580  PSID_AND_ATTRIBUTES CapturedGroups = NULL;
1581  PSID CapturedOwnerSid = NULL;
1582  PSID CapturedPrimaryGroupSid = NULL;
1583  PACL CapturedDefaultDacl = NULL;
1584  ULONG PrivilegesLength, UserLength, GroupsLength;
1585  NTSTATUS Status;
1586 
1587  PAGED_CODE();
1588 
1590 
1591  if (PreviousMode != KernelMode)
1592  {
1593  _SEH2_TRY
1594  {
1596 
1597  if (ObjectAttributes != NULL)
1598  {
1600  sizeof(OBJECT_ATTRIBUTES),
1601  sizeof(ULONG));
1602  LocalSecurityQos = *(SECURITY_QUALITY_OF_SERVICE*)ObjectAttributes->SecurityQualityOfService;
1603  }
1604 
1605  ProbeForRead(AuthenticationId,
1606  sizeof(LUID),
1607  sizeof(ULONG));
1608  LocalAuthenticationId = *AuthenticationId;
1609 
1610  LocalExpirationTime = ProbeForReadLargeInteger(ExpirationTime);
1611 
1613  sizeof(TOKEN_USER),
1614  sizeof(ULONG));
1615 
1617  sizeof(TOKEN_GROUPS),
1618  sizeof(ULONG));
1619  GroupCount = TokenGroups->GroupCount;
1620 
1622  sizeof(TOKEN_PRIVILEGES),
1623  sizeof(ULONG));
1624  PrivilegeCount = TokenPrivileges->PrivilegeCount;
1625 
1626  if (TokenOwner != NULL)
1627  {
1629  sizeof(TOKEN_OWNER),
1630  sizeof(ULONG));
1631  OwnerSid = TokenOwner->Owner;
1632  }
1633  else
1634  {
1635  OwnerSid = NULL;
1636  }
1637 
1639  sizeof(TOKEN_PRIMARY_GROUP),
1640  sizeof(ULONG));
1641  PrimaryGroupSid = TokenPrimaryGroup->PrimaryGroup;
1642 
1643  if (TokenDefaultDacl != NULL)
1644  {
1646  sizeof(TOKEN_DEFAULT_DACL),
1647  sizeof(ULONG));
1648  DefaultDacl = TokenDefaultDacl->DefaultDacl;
1649  }
1650  else
1651  {
1652  DefaultDacl = NULL;
1653  }
1654 
1656  sizeof(TOKEN_SOURCE),
1657  sizeof(ULONG));
1658  LocalTokenSource = *TokenSource;
1659  }
1661  {
1662  /* Return the exception code */
1664  }
1665  _SEH2_END;
1666  }
1667  else
1668  {
1669  if (ObjectAttributes != NULL)
1670  LocalSecurityQos = *(SECURITY_QUALITY_OF_SERVICE*)ObjectAttributes->SecurityQualityOfService;
1671  LocalAuthenticationId = *AuthenticationId;
1672  LocalExpirationTime = *ExpirationTime;
1673  GroupCount = TokenGroups->GroupCount;
1674  PrivilegeCount = TokenPrivileges->PrivilegeCount;
1675  OwnerSid = TokenOwner ? TokenOwner->Owner : NULL;
1676  PrimaryGroupSid = TokenPrimaryGroup->PrimaryGroup;
1677  DefaultDacl = TokenDefaultDacl ? TokenDefaultDacl->DefaultDacl : NULL;
1678  LocalTokenSource = *TokenSource;
1679  }
1680 
1681  /* Check token type */
1682  if ((TokenType < TokenPrimary) ||
1684  {
1685  return STATUS_BAD_TOKEN_TYPE;
1686  }
1687 
1688  /* Check for token creation privilege */
1690  {
1692  }
1693 
1694  /* Capture the user SID and attributes */
1696  1,
1697  PreviousMode,
1698  NULL,
1699  0,
1700  PagedPool,
1701  FALSE,
1702  &CapturedUser,
1703  &UserLength);
1704  if (!NT_SUCCESS(Status))
1705  {
1706  goto Cleanup;
1707  }
1708 
1709  /* Capture the groups SID and attributes array */
1711  GroupCount,
1712  PreviousMode,
1713  NULL,
1714  0,
1715  PagedPool,
1716  FALSE,
1717  &CapturedGroups,
1718  &GroupsLength);
1719  if (!NT_SUCCESS(Status))
1720  {
1721  goto Cleanup;
1722  }
1723 
1724  /* Capture privileges */
1726  PrivilegeCount,
1727  PreviousMode,
1728  NULL,
1729  0,
1730  PagedPool,
1731  FALSE,
1732  &CapturedPrivileges,
1733  &PrivilegesLength);
1734  if (!NT_SUCCESS(Status))
1735  {
1736  goto Cleanup;
1737  }
1738 
1739  /* Capture the token owner SID */
1740  if (TokenOwner != NULL)
1741  {
1742  Status = SepCaptureSid(OwnerSid,
1743  PreviousMode,
1744  PagedPool,
1745  FALSE,
1746  &CapturedOwnerSid);
1747  if (!NT_SUCCESS(Status))
1748  {
1749  goto Cleanup;
1750  }
1751  }
1752 
1753  /* Capture the token primary group SID */
1754  Status = SepCaptureSid(PrimaryGroupSid,
1755  PreviousMode,
1756  PagedPool,
1757  FALSE,
1758  &CapturedPrimaryGroupSid);
1759  if (!NT_SUCCESS(Status))
1760  {
1761  goto Cleanup;
1762  }
1763 
1764  /* Capture DefaultDacl */
1765  if (DefaultDacl != NULL)
1766  {
1767  Status = SepCaptureAcl(DefaultDacl,
1768  PreviousMode,
1769  NonPagedPool,
1770  FALSE,
1771  &CapturedDefaultDacl);
1772  if (!NT_SUCCESS(Status))
1773  {
1774  goto Cleanup;
1775  }
1776  }
1777 
1778  /* Call the internal function */
1779  Status = SepCreateToken(&hToken,
1780  PreviousMode,
1781  DesiredAccess,
1783  TokenType,
1784  LocalSecurityQos.ImpersonationLevel,
1785  &LocalAuthenticationId,
1786  &LocalExpirationTime,
1787  CapturedUser,
1788  GroupCount,
1789  CapturedGroups,
1790  GroupsLength,
1791  PrivilegeCount,
1792  CapturedPrivileges,
1793  CapturedOwnerSid,
1794  CapturedPrimaryGroupSid,
1795  CapturedDefaultDacl,
1796  &LocalTokenSource,
1797  FALSE);
1798  if (NT_SUCCESS(Status))
1799  {
1800  _SEH2_TRY
1801  {
1802  *TokenHandle = hToken;
1803  }
1805  {
1807  }
1808  _SEH2_END;
1809  }
1810 
1811 Cleanup:
1812 
1813  /* Release what we captured */
1816  SeReleaseLuidAndAttributesArray(CapturedPrivileges, PreviousMode, FALSE);
1817  SepReleaseSid(CapturedOwnerSid, PreviousMode, FALSE);
1818  SepReleaseSid(CapturedPrimaryGroupSid, PreviousMode, FALSE);
1819  SepReleaseAcl(CapturedDefaultDacl, PreviousMode, FALSE);
1820 
1821  return Status;
1822 }
1823 
1863 NTSTATUS
1864 NTAPI
1866  _In_ HANDLE ExistingTokenHandle,
1872 {
1874  HANDLE hToken;
1875  PTOKEN Token;
1876  PTOKEN NewToken;
1877  PSECURITY_QUALITY_OF_SERVICE CapturedSecurityQualityOfService;
1878  BOOLEAN QoSPresent;
1880  NTSTATUS Status;
1881 
1882  PAGED_CODE();
1883 
1884  if (TokenType != TokenImpersonation &&
1886  {
1887  return STATUS_INVALID_PARAMETER;
1888  }
1889 
1891 
1892  if (PreviousMode != KernelMode)
1893  {
1894  _SEH2_TRY
1895  {
1897  }
1899  {
1900  /* Return the exception code */
1902  }
1903  _SEH2_END;
1904  }
1905 
1907  PreviousMode,
1908  PagedPool,
1909  FALSE,
1910  &CapturedSecurityQualityOfService,
1911  &QoSPresent);
1912  if (!NT_SUCCESS(Status))
1913  {
1914  DPRINT1("NtDuplicateToken() failed to capture QoS! Status: 0x%x\n", Status);
1915  return Status;
1916  }
1917 
1918  Status = ObReferenceObjectByHandle(ExistingTokenHandle,
1921  PreviousMode,
1922  (PVOID*)&Token,
1924  if (!NT_SUCCESS(Status))
1925  {
1926  DPRINT1("Failed to reference token (Status 0x%lx)\n", Status);
1927  SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
1928  PreviousMode,
1929  FALSE);
1930  return Status;
1931  }
1932 
1933  /*
1934  * Fail, if the original token is an impersonation token and the caller
1935  * tries to raise the impersonation level of the new token above the
1936  * impersonation level of the original token.
1937  */
1938  if (Token->TokenType == TokenImpersonation)
1939  {
1940  if (QoSPresent &&
1941  CapturedSecurityQualityOfService->ImpersonationLevel >Token->ImpersonationLevel)
1942  {
1944  SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
1945  PreviousMode,
1946  FALSE);
1948  }
1949  }
1950 
1951  /*
1952  * Fail, if a primary token is to be created from an impersonation token
1953  * and and the impersonation level of the impersonation token is below SecurityImpersonation.
1954  */
1955  if (Token->TokenType == TokenImpersonation &&
1956  TokenType == TokenPrimary &&
1957  Token->ImpersonationLevel < SecurityImpersonation)
1958  {
1960  SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
1961  PreviousMode,
1962  FALSE);
1964  }
1965 
1968  EffectiveOnly,
1969  TokenType,
1970  (QoSPresent ? CapturedSecurityQualityOfService->ImpersonationLevel : SecurityAnonymous),
1971  PreviousMode,
1972  &NewToken);
1973 
1975 
1976  if (NT_SUCCESS(Status))
1977  {
1978  Status = ObInsertObject(NewToken,
1979  NULL,
1980  (DesiredAccess ? DesiredAccess : HandleInformation.GrantedAccess),
1981  0,
1982  NULL,
1983  &hToken);
1984  if (NT_SUCCESS(Status))
1985  {
1986  _SEH2_TRY
1987  {
1988  *NewTokenHandle = hToken;
1989  }
1991  {
1993  }
1994  _SEH2_END;
1995  }
1996  }
1997 
1998  /* Free the captured structure */
1999  SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
2000  PreviousMode,
2001  FALSE);
2002 
2003  return Status;
2004 }
2005 
2069 NTSTATUS
2070 NTAPI
2072  _In_ HANDLE ExistingTokenHandle,
2073  _In_ ULONG Flags,
2074  _In_opt_ PTOKEN_GROUPS SidsToDisable,
2075  _In_opt_ PTOKEN_PRIVILEGES PrivilegesToDelete,
2076  _In_opt_ PTOKEN_GROUPS RestrictedSids,
2078 {
2079  PTOKEN Token, FilteredToken;
2080  HANDLE FilteredTokenHandle;
2081  NTSTATUS Status;
2083  OBJECT_HANDLE_INFORMATION HandleInfo;
2085  ULONG CapturedSidsCount = 0;
2086  ULONG CapturedPrivilegesCount = 0;
2087  ULONG CapturedRestrictedSidsCount = 0;
2088  ULONG ProbeSize = 0;
2089  PSID_AND_ATTRIBUTES CapturedSids = NULL;
2090  PSID_AND_ATTRIBUTES CapturedRestrictedSids = NULL;
2091  PLUID_AND_ATTRIBUTES CapturedPrivileges = NULL;
2092 
2093  PAGED_CODE();
2094 
2096 
2097  _SEH2_TRY
2098  {
2099  /* Probe SidsToDisable */
2100  if (SidsToDisable != NULL)
2101  {
2102  /* Probe the header */
2103  ProbeForRead(SidsToDisable, sizeof(*SidsToDisable), sizeof(ULONG));
2104 
2105  CapturedSidsCount = SidsToDisable->GroupCount;
2106  ProbeSize = FIELD_OFFSET(TOKEN_GROUPS, Groups[CapturedSidsCount]);
2107 
2108  ProbeForRead(SidsToDisable, ProbeSize, sizeof(ULONG));
2109  }
2110 
2111  /* Probe PrivilegesToDelete */
2112  if (PrivilegesToDelete != NULL)
2113  {
2114  /* Probe the header */
2115  ProbeForRead(PrivilegesToDelete, sizeof(*PrivilegesToDelete), sizeof(ULONG));
2116 
2117  CapturedPrivilegesCount = PrivilegesToDelete->PrivilegeCount;
2118  ProbeSize = FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges[CapturedPrivilegesCount]);
2119 
2120  ProbeForRead(PrivilegesToDelete, ProbeSize, sizeof(ULONG));
2121  }
2122 
2123  /* Probe RestrictedSids */
2124  if (RestrictedSids != NULL)
2125  {
2126  /* Probe the header */
2127  ProbeForRead(RestrictedSids, sizeof(*RestrictedSids), sizeof(ULONG));
2128 
2129  CapturedRestrictedSidsCount = RestrictedSids->GroupCount;
2130  ProbeSize = FIELD_OFFSET(TOKEN_GROUPS, Groups[CapturedRestrictedSidsCount]);
2131 
2132  ProbeForRead(RestrictedSids, ProbeSize, sizeof(ULONG));
2133  }
2134 
2135  /* Probe the handle */
2137  }
2139  {
2140  /* Return the exception code */
2142  }
2143  _SEH2_END;
2144 
2145  /* Reference the token */
2146  Status = ObReferenceObjectByHandle(ExistingTokenHandle,
2149  PreviousMode,
2150  (PVOID*)&Token,
2151  &HandleInfo);
2152  if (!NT_SUCCESS(Status))
2153  {
2154  DPRINT1("NtFilterToken(): Failed to reference the token (Status 0x%lx)\n", Status);
2155  return Status;
2156  }
2157 
2158  /* Capture the group SIDs */
2159  if (SidsToDisable != NULL)
2160  {
2161  Status = SeCaptureSidAndAttributesArray(SidsToDisable->Groups,
2162  CapturedSidsCount,
2163  PreviousMode,
2164  NULL,
2165  0,
2166  PagedPool,
2167  TRUE,
2168  &CapturedSids,
2169  &ResultLength);
2170  if (!NT_SUCCESS(Status))
2171  {
2172  DPRINT1("NtFilterToken(): Failed to capture the SIDs (Status 0x%lx)\n", Status);
2173  goto Quit;
2174  }
2175  }
2176 
2177  /* Capture the privileges */
2178  if (PrivilegesToDelete != NULL)
2179  {
2180  Status = SeCaptureLuidAndAttributesArray(PrivilegesToDelete->Privileges,
2181  CapturedPrivilegesCount,
2182  PreviousMode,
2183  NULL,
2184  0,
2185  PagedPool,
2186  TRUE,
2187  &CapturedPrivileges,
2188  &ResultLength);
2189  if (!NT_SUCCESS(Status))
2190  {
2191  DPRINT1("NtFilterToken(): Failed to capture the privileges (Status 0x%lx)\n", Status);
2192  goto Quit;
2193  }
2194  }
2195 
2196  /* Capture the restricted SIDs */
2197  if (RestrictedSids != NULL)
2198  {
2199  Status = SeCaptureSidAndAttributesArray(RestrictedSids->Groups,
2200  CapturedRestrictedSidsCount,
2201  PreviousMode,
2202  NULL,
2203  0,
2204  PagedPool,
2205  TRUE,
2206  &CapturedRestrictedSids,
2207  &ResultLength);
2208  if (!NT_SUCCESS(Status))
2209  {
2210  DPRINT1("NtFilterToken(): Failed to capture the restricted SIDs (Status 0x%lx)\n", Status);
2211  goto Quit;
2212  }
2213  }
2214 
2215  /* Call the internal API */
2217  CapturedPrivileges,
2218  CapturedSids,
2219  CapturedRestrictedSids,
2220  CapturedPrivilegesCount,
2221  CapturedSidsCount,
2222  CapturedRestrictedSidsCount,
2223  Flags,
2224  PreviousMode,
2225  &FilteredToken);
2226  if (!NT_SUCCESS(Status))
2227  {
2228  DPRINT1("NtFilterToken(): Failed to filter the token (Status 0x%lx)\n", Status);
2229  goto Quit;
2230  }
2231 
2232  /* Insert the filtered token and retrieve a handle to it */
2233  Status = ObInsertObject(FilteredToken,
2234  NULL,
2235  HandleInfo.GrantedAccess,
2236  0,
2237  NULL,
2238  &FilteredTokenHandle);
2239  if (!NT_SUCCESS(Status))
2240  {
2241  DPRINT1("NtFilterToken(): Failed to insert the filtered token (Status 0x%lx)\n", Status);
2242  goto Quit;
2243  }
2244 
2245  /* And return it to the caller once we're done */
2246  _SEH2_TRY
2247  {
2248  *NewTokenHandle = FilteredTokenHandle;
2249  }
2251  {
2253  _SEH2_YIELD(goto Quit);
2254  }
2255  _SEH2_END;
2256 
2257 Quit:
2258  /* Dereference the token */
2260 
2261  /* Release all the captured data */
2262  if (CapturedSids != NULL)
2263  {
2264  SeReleaseSidAndAttributesArray(CapturedSids,
2265  PreviousMode,
2266  TRUE);
2267  }
2268 
2269  if (CapturedPrivileges != NULL)
2270  {
2271  SeReleaseLuidAndAttributesArray(CapturedPrivileges,
2272  PreviousMode,
2273  TRUE);
2274  }
2275 
2276  if (CapturedRestrictedSids != NULL)
2277  {
2278  SeReleaseSidAndAttributesArray(CapturedRestrictedSids,
2279  PreviousMode,
2280  TRUE);
2281  }
2282 
2283  return Status;
2284 }
2285 
2286 /* EOF */
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:35
static NTSTATUS SepPerformTokenFiltering(_In_ PTOKEN Token, _In_opt_ PLUID_AND_ATTRIBUTES PrivilegesToBeDeleted, _In_opt_ PSID_AND_ATTRIBUTES SidsToBeDisabled, _In_opt_ PSID_AND_ATTRIBUTES RestrictedSidsIntoToken, _When_(PrivilegesToBeDeleted !=NULL, _In_) ULONG PrivilegesCount, _When_(SidsToBeDisabled !=NULL, _In_) ULONG RegularGroupsSidCount, _When_(RestrictedSidsIntoToken !=NULL, _In_) ULONG RestrictedSidsCount, _In_ ULONG PrivilegeFlags, _In_ KPROCESSOR_MODE PreviousMode, _Out_ PTOKEN *FilteredToken)
Private helper function responsible for creating a restricted access token, that is,...
Definition: tokenlif.c:855
#define STATUS_PRIVILEGE_NOT_HELD
Definition: DriverTester.h:9
_Must_inspect_result_ _In_ WDFDEVICE _In_ ULONG _In_ ACCESS_MASK DesiredAccess
Definition: wdfdevice.h:2654
#define STATUS_BAD_IMPERSONATION_LEVEL
Definition: ntstatus.h:401
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
#define TOKEN_SANDBOX_INERT
Definition: setypes.h:1181
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
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:464
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:979
#define _Out_
Definition: ms_sal.h:345
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)
#define TRUE
Definition: types.h:120
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define SE_TOKEN_DYNAMIC_SLIM
Definition: tokenlif.c:17
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:314
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:1108
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
struct _LUID_AND_ATTRIBUTES LUID_AND_ATTRIBUTES
NTSTATUS NTAPI NtFilterToken(_In_ HANDLE ExistingTokenHandle, _In_ ULONG Flags, _In_opt_ PTOKEN_GROUPS SidsToDisable, _In_opt_ PTOKEN_PRIVILEGES PrivilegesToDelete, _In_opt_ PTOKEN_GROUPS RestrictedSids, _Out_ PHANDLE NewTokenHandle)
Creates an access token in a restricted form from the original existing token, that is,...
Definition: tokenlif.c:2071
KPROCESSOR_MODE NTAPI ExGetPreviousMode(VOID)
Definition: sysinfo.c:3063
_IRQL_requires_same_ typedef _In_ ULONG _In_ UCHAR Level
Definition: wmitypes.h:55
#define TOKEN_CREATE_METHOD
Definition: se.h:70
#define _When_(expr, annos)
Definition: ms_sal.h:254
NTSTATUS SepCreateTokenLock(_Inout_ PTOKEN Token)
Creates a lock for the token.
Definition: token.c:45
if(dx==0 &&dy==0)
Definition: linetemp.h:174
TOpcodeData Groups[17][8]
VOID SepRemoveUserGroupToken(_Inout_ PTOKEN Token, _In_ ULONG Index)
Removes a group from the token.
Definition: token.c:618
VOID NTAPI SepReleaseSid(_In_ PSID CapturedSid, _In_ KPROCESSOR_MODE AccessMode, _In_ BOOLEAN CaptureIfKernel)
Releases a captured SID.
Definition: sid.c:400
_SEH2_TRY
Definition: create.c:4226
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define SE_PRIVILEGE_ENABLED
Definition: setypes.h:63
NTSTATUS NTAPI ObReferenceObjectByHandle(IN HANDLE Handle, IN ACCESS_MASK DesiredAccess, IN POBJECT_TYPE ObjectType, IN KPROCESSOR_MODE AccessMode, OUT PVOID *Object, OUT POBJECT_HANDLE_INFORMATION HandleInformation OPTIONAL)
Definition: obref.c:494
_In_ ACCESS_MASK _In_opt_ POBJECT_ATTRIBUTES _In_ BOOLEAN _In_ TOKEN_TYPE _Out_ PHANDLE NewTokenHandle
Definition: sefuncs.h:401
ACCESS_MASK GrantedAccess
Definition: iotypes.h:181
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
#define FALSE
Definition: types.h:117
#define RtlEqualLuid(Luid1, Luid2)
Definition: rtlfuncs.h:301
enum _SECURITY_IMPERSONATION_LEVEL SECURITY_IMPERSONATION_LEVEL
VOID SepUpdatePrivilegeFlagsToken(_Inout_ PTOKEN Token)
Updates the token's flags based upon the privilege that the token has been granted....
Definition: token.c:554
NTSTATUS NTAPI SepCaptureAcl(_In_ PACL InputAcl, _In_ KPROCESSOR_MODE AccessMode, _In_ POOL_TYPE PoolType, _In_ BOOLEAN CaptureIfKernel, _Out_ PACL *CapturedAcl)
Captures an access control list from an already valid input ACL.
Definition: acl.c:352
#define PsGetCurrentProcess
Definition: psfuncs.h:17
NTSTATUS SepRmReferenceLogonSession(_Inout_ PLUID LogonLuid)
unsigned char BOOLEAN
#define STATUS_BAD_TOKEN_TYPE
Definition: ntstatus.h:404
POBJECT_TYPE SeTokenObjectType
Definition: token.c:17
#define SE_GROUP_ENABLED_BY_DEFAULT
Definition: setypes.h:91
#define _In_
Definition: ms_sal.h:308
_In_ ULONG _In_ ACCESS_MASK _In_ PSID Sid
Definition: rtlfuncs.h:1130
_In_ ACCESS_MASK _In_ ULONG _Out_ PHANDLE TokenHandle
Definition: psfuncs.h:715
PsGetCurrentThreadId
Definition: CrNtStubs.h:7
NTSYSAPI ULONG NTAPI RtlLengthSid(IN PSID Sid)
Definition: sid.c:150
void * PVOID
Definition: retypes.h:9
NTSTATUS NTAPI ObCreateObject(IN KPROCESSOR_MODE ProbeMode OPTIONAL, IN POBJECT_TYPE Type, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN KPROCESSOR_MODE AccessMode, IN OUT PVOID ParseContext OPTIONAL, IN ULONG ObjectSize, IN ULONG PagedPoolCharge OPTIONAL, IN ULONG NonPagedPoolCharge OPTIONAL, OUT PVOID *Object)
Definition: oblife.c:951
Status
Definition: gdiplustypes.h:24
_Out_writes_bytes_to_opt_ AbsoluteSecurityDescriptorSize PSECURITY_DESCRIPTOR _Inout_ PULONG _Out_writes_bytes_to_opt_ DaclSize PACL _Inout_ PULONG _Out_writes_bytes_to_opt_ SaclSize PACL _Inout_ PULONG _Out_writes_bytes_to_opt_ OwnerSize PSID _Inout_ PULONG _Out_writes_bytes_to_opt_ PrimaryGroupSize PSID PrimaryGroup
Definition: rtlfuncs.h:1585
#define SE_CHANGE_NOTIFY_PRIVILEGE
Definition: security.c:677
_In_ KPROCESSOR_MODE PreviousMode
Definition: sefuncs.h:103
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
#define __kernel_entry
Definition: specstrings.h:355
#define ASSERT(a)
Definition: mode.c:44
VOID NTAPI SeReleaseLuidAndAttributesArray(_In_ PLUID_AND_ATTRIBUTES Privilege, _In_ KPROCESSOR_MODE PreviousMode, _In_ BOOLEAN CaptureIfKernel)
Releases a LUID with attributes structure.
Definition: priv.c:554
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define SE_GROUP_ENABLED
Definition: setypes.h:92
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
struct _SID_AND_ATTRIBUTES SID_AND_ATTRIBUTES
_Out_ PBOOLEAN _Out_ PBOOLEAN _Out_ PSECURITY_IMPERSONATION_LEVEL ImpersonationLevel
Definition: psfuncs.h:154
#define ObDereferenceObject
Definition: obfuncs.h:203
PVOID HANDLE
Definition: typedefs.h:73
#define ProbeForWriteHandle(Ptr)
Definition: probe.h:43
_In_ ACCESS_MASK _In_opt_ POBJECT_TYPE _In_ KPROCESSOR_MODE _Out_ PVOID _Out_opt_ POBJECT_HANDLE_INFORMATION HandleInformation
Definition: obfuncs.h:40
#define SE_GROUP_MANDATORY
Definition: setypes.h:90
#define ProbeForReadLargeInteger(Ptr)
Definition: probe.h:75
CCHAR KPROCESSOR_MODE
Definition: ketypes.h:7
_In_ PSECURITY_SUBJECT_CONTEXT _In_ BOOLEAN _In_ ACCESS_MASK _In_ ACCESS_MASK _Outptr_opt_ PPRIVILEGE_SET * Privileges
Definition: sefuncs.h:13
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
#define TOKEN_DUPLICATE
Definition: setypes.h:922
PSID SeAliasAdminsSid
Definition: sid.c:41
VOID NTAPI ProbeForRead(IN CONST VOID *Address, IN SIZE_T Length, IN ULONG Alignment)
Definition: exintrin.c:102
VOID NTAPI SepReleaseSecurityQualityOfService(_In_opt_ PSECURITY_QUALITY_OF_SERVICE CapturedSecurityQualityOfService, _In_ KPROCESSOR_MODE AccessMode, _In_ BOOLEAN CaptureIfKernel)
Releases (frees) the captured SQOS data from an object in the memory pool.
Definition: sqos.c:225
#define SepReleaseTokenLock(Token)
Definition: se.h:286
NTSTATUS NTAPI SeCaptureSidAndAttributesArray(_In_ PSID_AND_ATTRIBUTES SrcSidAndAttributes, _In_ ULONG AttributeCount, _In_ KPROCESSOR_MODE PreviousMode, _In_opt_ PVOID AllocatedMem, _In_ ULONG AllocatedLength, _In_ POOL_TYPE PoolType, _In_ BOOLEAN CaptureIfKernel, _Out_ PSID_AND_ATTRIBUTES *CapturedSidAndAttributes, _Out_ PULONG ResultLength)
Captures a SID with attributes.
Definition: sid.c:696
PVOID *typedef PHANDLE
Definition: ntsecpkg.h:454
#define TAG_TOKEN_DYNAMIC
Definition: tag.h:155
_Must_inspect_result_ __kernel_entry NTSTATUS NTAPI NtDuplicateToken(_In_ HANDLE ExistingTokenHandle, _In_ ACCESS_MASK DesiredAccess, _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, _In_ BOOLEAN EffectiveOnly, _In_ TOKEN_TYPE TokenType, _Out_ PHANDLE NewTokenHandle)
Duplicates a token.
Definition: tokenlif.c:1865
#define SE_GROUP_USE_FOR_DENY_ONLY
Definition: setypes.h:94
__kernel_entry NTSTATUS NTAPI NtCreateToken(_Out_ PHANDLE TokenHandle, _In_ ACCESS_MASK DesiredAccess, _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, _In_ TOKEN_TYPE TokenType, _In_ PLUID AuthenticationId, _In_ PLARGE_INTEGER ExpirationTime, _In_ PTOKEN_USER TokenUser, _In_ PTOKEN_GROUPS TokenGroups, _In_ PTOKEN_PRIVILEGES TokenPrivileges, _In_opt_ PTOKEN_OWNER TokenOwner, _In_ PTOKEN_PRIMARY_GROUP TokenPrimaryGroup, _In_opt_ PTOKEN_DEFAULT_DACL TokenDefaultDacl, _In_ PTOKEN_SOURCE TokenSource)
Creates an access token.
Definition: tokenlif.c:1554
#define TOKEN_FILTER_METHOD
Definition: se.h:72
VOID SepRemovePrivilegeToken(_Inout_ PTOKEN Token, _In_ ULONG Index)
Removes a privilege from the token.
Definition: token.c:582
NTSYSAPI BOOLEAN WINAPI RtlCopySid(DWORD, PSID, PSID)
static const WCHAR Cleanup[]
Definition: register.c:80
#define _Must_inspect_result_
Definition: ms_sal.h:558
enum _TOKEN_TYPE TOKEN_TYPE
EPROCESS KiInitialProcess
Definition: krnlinit.c:45
NTSTATUS NTAPI SeFilterToken(_In_ PACCESS_TOKEN ExistingToken, _In_ ULONG Flags, _In_opt_ PTOKEN_GROUPS SidsToDisable, _In_opt_ PTOKEN_PRIVILEGES PrivilegesToDelete, _In_opt_ PTOKEN_GROUPS RestrictedSids, _Out_ PACCESS_TOKEN *FilteredToken)
Filters an access token from an existing token, making it more restricted than the previous one.
Definition: tokenlif.c:1434
_SEH2_END
Definition: create.c:4400
NTSTATUS NTAPI ObInsertObject(IN PVOID Object, IN PACCESS_STATE AccessState OPTIONAL, IN ACCESS_MASK DesiredAccess, IN ULONG ObjectPointerBias, OUT PVOID *NewObject OPTIONAL, OUT PHANDLE Handle)
Definition: obhandle.c:2935
#define TOKEN_HAS_ADMIN_GROUP
Definition: setypes.h:1178
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
NTSTATUS NTAPI SepCreateToken(_Out_ PHANDLE TokenHandle, _In_ KPROCESSOR_MODE PreviousMode, _In_ ACCESS_MASK DesiredAccess, _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, _In_ TOKEN_TYPE TokenType, _In_ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, _In_ PLUID AuthenticationId, _In_ PLARGE_INTEGER ExpirationTime, _In_ PSID_AND_ATTRIBUTES User, _In_ ULONG GroupCount, _In_ PSID_AND_ATTRIBUTES Groups, _In_ ULONG GroupsLength, _In_ ULONG PrivilegeCount, _In_ PLUID_AND_ATTRIBUTES Privileges, _In_opt_ PSID Owner, _In_ PSID PrimaryGroup, _In_opt_ PACL DefaultDacl, _In_ PTOKEN_SOURCE TokenSource, _In_ BOOLEAN SystemToken)
Internal function responsible for access token object creation in the kernel. A fully created token o...
Definition: tokenlif.c:97
VOID SepUpdateSinglePrivilegeFlagToken(_Inout_ PTOKEN Token, _In_ ULONG Index)
Updates the token's flags based upon the privilege that the token has been granted....
Definition: token.c:442
VOID NTAPI ExAllocateLocallyUniqueId(OUT LUID *LocallyUniqueId)
Definition: uuid.c:335
ULONG RtlLengthSidAndAttributes(_In_ ULONG Count, _In_ PSID_AND_ATTRIBUTES Src)
Computes the length size of a SID.
Definition: token.c:965
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
Definition: lsa.idl:65
#define min(a, b)
Definition: monoChain.cc:55
_Out_writes_bytes_to_opt_ AbsoluteSecurityDescriptorSize PSECURITY_DESCRIPTOR _Inout_ PULONG _Out_writes_bytes_to_opt_ DaclSize PACL _Inout_ PULONG _Out_writes_bytes_to_opt_ SaclSize PACL _Inout_ PULONG _Out_writes_bytes_to_opt_ OwnerSize PSID Owner
Definition: rtlfuncs.h:1583
HANDLE NTAPI PsGetCurrentProcessId(VOID)
Definition: process.c:1123
#define NULL
Definition: types.h:112
#define TOKEN_DUPLICATE_METHOD
Definition: se.h:71
#define DISABLE_MAX_PRIVILEGE
Definition: setypes.h:114
#define DPRINT1
Definition: precomp.h:8
BOOLEAN NTAPI SeSinglePrivilegeCheck(_In_ LUID PrivilegeValue, _In_ KPROCESSOR_MODE PreviousMode)
Checks if a single privilege is present in the context of the calling thread.
Definition: priv.c:744
#define SepAcquireTokenLockShared(Token)
Definition: se.h:280
NTSTATUS NTAPI SepDuplicateToken(_In_ PTOKEN Token, _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, _In_ BOOLEAN EffectiveOnly, _In_ TOKEN_TYPE TokenType, _In_ SECURITY_IMPERSONATION_LEVEL Level, _In_ KPROCESSOR_MODE PreviousMode, _Out_ PTOKEN *NewAccessToken)
Duplicates an access token, from an existing valid token.
Definition: tokenlif.c:471
unsigned int ULONG
Definition: retypes.h:1
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
#define ULONG_PTR
Definition: config.h:101
#define ALIGN_UP_BY(size, align)
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define SANDBOX_INERT
Definition: setypes.h:115
_Must_inspect_result_ _In_ WDFDEVICE _In_ DEVICE_REGISTRY_PROPERTY _In_ ULONG _Out_ PULONG ResultLength
Definition: wdfdevice.h:3776
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:40
#define STATUS_SUCCESS
Definition: shellext.h:65
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:165
#define _SEH2_YIELD(__stmt)
Definition: pseh2_64.h:168
#define DPRINT
Definition: sndvol32.h:71
NTSTATUS NTAPI SepCaptureSecurityQualityOfService(_In_opt_ POBJECT_ATTRIBUTES ObjectAttributes, _In_ KPROCESSOR_MODE AccessMode, _In_ POOL_TYPE PoolType, _In_ BOOLEAN CaptureIfKernel, _Out_ PSECURITY_QUALITY_OF_SERVICE *CapturedSecurityQualityOfService, _Out_ PBOOLEAN Present)
Captures the security quality of service data given the object attributes from an object.
Definition: sqos.c:52
_In_ ACCESS_MASK _In_opt_ POBJECT_ATTRIBUTES _In_ BOOLEAN EffectiveOnly
Definition: sefuncs.h:401
#define TOKEN_SESSION_NOT_REFERENCED
Definition: setypes.h:1180
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:1011
ULONG ACCESS_MASK
Definition: nt_native.h:40
NTSYSAPI BOOLEAN NTAPI RtlEqualSid(_In_ PSID Sid1, _In_ PSID Sid2)
_In_ ACCESS_MASK _In_opt_ POBJECT_ATTRIBUTES _In_ BOOLEAN _In_ TOKEN_TYPE TokenType
Definition: sefuncs.h:401
#define TOKEN_IS_RESTRICTED
Definition: setypes.h:1179
#define PAGED_CODE()
_Must_inspect_result_ _In_ WDFDMAENABLER _In_ _In_opt_ PWDF_OBJECT_ATTRIBUTES Attributes