ReactOS 0.4.15-dev-5893-g1bb4167
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
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 */
138 if (Groups[i].Attributes & SE_GROUP_MANDATORY)
139 {
140 /* Force them to be enabled */
141 Groups[i].Attributes |= (SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT);
142 }
143
144 /* Check of the group is an admin group */
145 if (RtlEqualSid(SeAliasAdminsSid, Groups[i].Sid))
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 */
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
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;
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;
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;
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 */
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
297 {
299 {
300 RtlCopyMemory(AccessToken->Privileges,
302 PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
303 }
305 {
307 }
308 _SEH2_END;
309 }
310 else
311 {
312 RtlCopyMemory(AccessToken->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 */
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 */
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,
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
428Quit:
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
470NTAPI
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
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;
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 */
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 */
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
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
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 */
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
783Quit:
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
853static
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,
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);
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;
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 */
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);
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
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
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 {
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 */
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
1384Quit:
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
1433NTAPI
1435 _In_ PACCESS_TOKEN ExistingToken,
1437 _In_opt_ PTOKEN_GROUPS SidsToDisable,
1438 _In_opt_ PTOKEN_PRIVILEGES PrivilegesToDelete,
1439 _In_opt_ PTOKEN_GROUPS RestrictedSids,
1440 _Out_ PACCESS_TOKEN *FilteredToken)
1441{
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
1553NTAPI
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;
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,
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,
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,
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,
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,
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,
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,
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
1811Cleanup:
1812
1813 /* Release what we captured */
1817 SepReleaseSid(CapturedOwnerSid, PreviousMode, FALSE);
1818 SepReleaseSid(CapturedPrimaryGroupSid, PreviousMode, FALSE);
1819 SepReleaseAcl(CapturedDefaultDacl, PreviousMode, FALSE);
1820
1821 return Status;
1822}
1823
1864NTAPI
1866 _In_ HANDLE ExistingTokenHandle,
1872{
1874 HANDLE hToken;
1875 PTOKEN Token;
1876 PTOKEN NewToken;
1877 PSECURITY_QUALITY_OF_SERVICE CapturedSecurityQualityOfService;
1878 BOOLEAN QoSPresent;
1881
1882 PAGED_CODE();
1883
1886 {
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
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,
1922 (PVOID*)&Token,
1924 if (!NT_SUCCESS(Status))
1925 {
1926 DPRINT1("Failed to reference token (Status 0x%lx)\n", Status);
1927 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
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,
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 &&
1957 Token->ImpersonationLevel < SecurityImpersonation)
1958 {
1960 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
1962 FALSE);
1964 }
1965
1969 TokenType,
1970 (QoSPresent ? CapturedSecurityQualityOfService->ImpersonationLevel : SecurityAnonymous),
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,
2001 FALSE);
2002
2003 return Status;
2004}
2005
2070NTAPI
2072 _In_ HANDLE ExistingTokenHandle,
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;
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,
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,
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,
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,
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,
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
2257Quit:
2258 /* Dereference the token */
2260
2261 /* Release all the captured data */
2262 if (CapturedSids != NULL)
2263 {
2264 SeReleaseSidAndAttributesArray(CapturedSids,
2266 TRUE);
2267 }
2268
2269 if (CapturedPrivileges != NULL)
2270 {
2271 SeReleaseLuidAndAttributesArray(CapturedPrivileges,
2273 TRUE);
2274 }
2275
2276 if (CapturedRestrictedSids != NULL)
2277 {
2278 SeReleaseSidAndAttributesArray(CapturedRestrictedSids,
2280 TRUE);
2281 }
2282
2283 return Status;
2284}
2285
2286/* EOF */
#define PAGED_CODE()
#define STATUS_PRIVILEGE_NOT_HELD
Definition: DriverTester.h:9
#define ALIGN_UP_BY(size, align)
unsigned char BOOLEAN
TOKEN_TYPE
Definition: asmpp.cpp:29
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:36
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
static const WCHAR Cleanup[]
Definition: register.c:80
#define ULONG_PTR
Definition: config.h:101
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
#define NonPagedPool
Definition: env_spec_w32.h:307
#define PagedPool
Definition: env_spec_w32.h:308
#define ExGetPreviousMode
Definition: ex.h:139
VOID NTAPI ProbeForRead(IN CONST VOID *Address, IN SIZE_T Length, IN ULONG Alignment)
Definition: exintrin.c:102
#define _SEH2_END
Definition: filesup.c:22
#define _SEH2_TRY
Definition: filesup.c:19
PsGetCurrentThreadId
Definition: CrNtStubs.h:8
Status
Definition: gdiplustypes.h:25
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
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
NTSYSAPI BOOLEAN WINAPI RtlCopySid(DWORD, PSID, PSID)
if(dx< 0)
Definition: linetemp.h:194
enum _SECURITY_IMPERSONATION_LEVEL SECURITY_IMPERSONATION_LEVEL
@ SecurityImpersonation
Definition: lsa.idl:57
@ SecurityAnonymous
Definition: lsa.idl:55
#define ASSERT(a)
Definition: mode.c:44
@ TokenImpersonation
Definition: imports.h:274
@ TokenPrimary
Definition: imports.h:273
#define SE_CHANGE_NOTIFY_PRIVILEGE
Definition: security.c:677
#define min(a, b)
Definition: monoChain.cc:55
#define _Must_inspect_result_
Definition: ms_sal.h:558
#define _Out_
Definition: ms_sal.h:345
#define _When_(expr, annos)
Definition: ms_sal.h:254
#define _In_
Definition: ms_sal.h:308
#define _In_opt_
Definition: ms_sal.h:309
#define KernelMode
Definition: asm.h:34
#define KeGetPreviousMode()
Definition: ketypes.h:1108
_In_ ACCESS_MASK _In_ ULONG _Out_ PHANDLE TokenHandle
Definition: psfuncs.h:718
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)
_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:1597
_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:1599
NTSYSAPI ULONG NTAPI RtlLengthSid(IN PSID Sid)
Definition: sid.c:150
_In_ ULONG _In_ ACCESS_MASK _In_ PSID Sid
Definition: rtlfuncs.h:1133
NTSYSAPI BOOLEAN NTAPI RtlEqualSid(_In_ PSID Sid1, _In_ PSID Sid2)
_In_ ACCESS_MASK _In_opt_ POBJECT_ATTRIBUTES _In_ BOOLEAN EffectiveOnly
Definition: sefuncs.h:403
_In_ ACCESS_MASK _In_opt_ POBJECT_ATTRIBUTES _In_ BOOLEAN _In_ TOKEN_TYPE _Out_ PHANDLE NewTokenHandle
Definition: sefuncs.h:405
_In_ ACCESS_MASK _In_opt_ POBJECT_ATTRIBUTES _In_ BOOLEAN _In_ TOKEN_TYPE TokenType
Definition: sefuncs.h:404
#define SE_GROUP_USE_FOR_DENY_ONLY
Definition: setypes.h:94
#define SE_GROUP_MANDATORY
Definition: setypes.h:90
#define SE_GROUP_ENABLED_BY_DEFAULT
Definition: setypes.h:91
#define DISABLE_MAX_PRIVILEGE
Definition: setypes.h:114
#define SANDBOX_INERT
Definition: setypes.h:115
#define SE_GROUP_ENABLED
Definition: setypes.h:92
ULONG ACCESS_MASK
Definition: nt_native.h:40
VOID NTAPI ExAllocateLocallyUniqueId(OUT LUID *LocallyUniqueId)
Definition: uuid.c:335
EPROCESS KiInitialProcess
Definition: krnlinit.c:45
VOID NTAPI SepReleaseSid(_In_ PSID CapturedSid, _In_ KPROCESSOR_MODE AccessMode, _In_ BOOLEAN CaptureIfKernel)
Releases a captured SID.
Definition: sid.c:400
NTSTATUS NTAPI SepRmInsertLogonSessionIntoToken(_Inout_ PTOKEN Token)
Inserts a logon session into an access token specified by the caller.
Definition: srm.c:368
VOID SepRemovePrivilegeToken(_Inout_ PTOKEN Token, _In_ ULONG Index)
Removes a privilege from the token.
Definition: token.c:582
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
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
const LUID SeCreateTokenPrivilege
Definition: priv.c:21
NTSTATUS SepCreateTokenLock(_Inout_ PTOKEN Token)
Creates a lock for the token.
Definition: token.c:45
#define TOKEN_CREATE_METHOD
Definition: se.h:70
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:994
#define SepAcquireTokenLockShared(Token)
Definition: se.h:280
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
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
PSID SeAliasAdminsSid
Definition: sid.c:41
ULONG RtlLengthSidAndAttributes(_In_ ULONG Count, _In_ PSID_AND_ATTRIBUTES Src)
Computes the length size of a SID.
Definition: token.c:965
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 SepRmReferenceLogonSession(_Inout_ PLUID LogonLuid)
VOID SepRemoveUserGroupToken(_Inout_ PTOKEN Token, _In_ ULONG Index)
Removes a group from the token.
Definition: token.c:618
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
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
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
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:711
#define SepReleaseTokenLock(Token)
Definition: se.h:286
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 TOKEN_FILTER_METHOD
Definition: se.h:72
#define TOKEN_DUPLICATE_METHOD
Definition: se.h:71
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)
HANDLE NTAPI PsGetCurrentProcessId(VOID)
Definition: process.c:1123
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
POBJECT_TYPE SeTokenObjectType
Definition: token.c:17
PVOID *typedef PHANDLE
Definition: ntsecpkg.h:455
#define STATUS_BAD_TOKEN_TYPE
Definition: ntstatus.h:404
#define STATUS_BAD_IMPERSONATION_LEVEL
Definition: ntstatus.h:401
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
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:1024
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
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:159
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:34
#define _SEH2_YIELD(__stmt)
Definition: pseh2_64.h:162
#define ProbeForWriteHandle(Ptr)
Definition: probe.h:43
#define ProbeForReadLargeInteger(Ptr)
Definition: probe.h:75
#define STATUS_SUCCESS
Definition: shellext.h:65
#define DPRINT
Definition: sndvol32.h:71
#define __kernel_entry
Definition: specstrings.h:355
DWORD LowPart
ACCESS_MASK GrantedAccess
Definition: iotypes.h:181
SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
Definition: lsa.idl:65
CCHAR SourceName[TOKEN_SOURCE_LENGTH]
Definition: imports.h:278
LUID SourceIdentifier
Definition: imports.h:279
LUID AuthenticationId
Definition: setypes.h:219
ULONG DynamicCharged
Definition: setypes.h:230
SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
Definition: setypes.h:240
LUID ModifiedId
Definition: setypes.h:224
ULONG DefaultOwnerIndex
Definition: setypes.h:232
LARGE_INTEGER ExpirationTime
Definition: setypes.h:221
PSID_AND_ATTRIBUTES RestrictedSids
Definition: setypes.h:234
ULONG VariablePart
Definition: setypes.h:253
ULONG SessionId
Definition: setypes.h:225
ULONG PrivilegeCount
Definition: setypes.h:228
PLUID_AND_ATTRIBUTES Privileges
Definition: setypes.h:236
PSID_AND_ATTRIBUTES UserAndGroups
Definition: setypes.h:233
TOKEN_TYPE TokenType
Definition: setypes.h:239
ULONG TokenFlags
Definition: setypes.h:241
LUID ParentTokenId
Definition: setypes.h:220
ULONG DynamicAvailable
Definition: setypes.h:231
ULONG VariableLength
Definition: setypes.h:229
PACL DefaultDacl
Definition: setypes.h:238
PSID PrimaryGroup
Definition: setypes.h:235
LUID OriginatingLogonSession
Definition: setypes.h:246
LUID TokenId
Definition: setypes.h:218
PULONG DynamicPart
Definition: setypes.h:237
ULONG UserAndGroupCount
Definition: setypes.h:226
TOKEN_SOURCE TokenSource
Definition: setypes.h:217
ULONG RestrictedSidCount
Definition: setypes.h:227
#define TAG_TOKEN_DYNAMIC
Definition: tag.h:158
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
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
__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 SE_TOKEN_DYNAMIC_SLIM
Definition: tokenlif.c:17
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
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
_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
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
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
#define NTAPI
Definition: typedefs.h:36
void * PVOID
Definition: typedefs.h:50
PVOID HANDLE
Definition: typedefs.h:73
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
uint32_t ULONG_PTR
Definition: typedefs.h:65
uint32_t ULONG
Definition: typedefs.h:59
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
_Must_inspect_result_ _In_ WDFDMAENABLER _In_ _In_opt_ PWDF_OBJECT_ATTRIBUTES Attributes
_Must_inspect_result_ _In_ WDFDEVICE _In_ DEVICE_REGISTRY_PROPERTY _In_ ULONG _Out_ PULONG ResultLength
Definition: wdfdevice.h:3776
_Must_inspect_result_ _In_ WDFDEVICE _In_ ULONG _In_ ACCESS_MASK DesiredAccess
Definition: wdfdevice.h:2658
_IRQL_requires_same_ typedef _In_ ULONG _In_ UCHAR Level
Definition: wmitypes.h:56
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
CCHAR KPROCESSOR_MODE
Definition: ketypes.h:7
_In_ ACCESS_MASK _In_opt_ POBJECT_TYPE _In_ KPROCESSOR_MODE _Out_ PVOID _Out_opt_ POBJECT_HANDLE_INFORMATION HandleInformation
Definition: obfuncs.h:44
#define ObDereferenceObject
Definition: obfuncs.h:203
#define PsGetCurrentProcess
Definition: psfuncs.h:17
_Out_ PBOOLEAN _Out_ PBOOLEAN _Out_ PSECURITY_IMPERSONATION_LEVEL ImpersonationLevel
Definition: psfuncs.h:156
#define RtlEqualLuid(Luid1, Luid2)
Definition: rtlfuncs.h:301
_In_ PSECURITY_SUBJECT_CONTEXT _In_ BOOLEAN _In_ ACCESS_MASK _In_ ACCESS_MASK _Outptr_opt_ PPRIVILEGE_SET * Privileges
Definition: sefuncs.h:17
_In_ KPROCESSOR_MODE PreviousMode
Definition: sefuncs.h:103
#define TOKEN_SESSION_NOT_REFERENCED
Definition: setypes.h:1180
#define TOKEN_DUPLICATE
Definition: setypes.h:922
struct _LUID_AND_ATTRIBUTES LUID_AND_ATTRIBUTES
@ TokenDefaultDacl
Definition: setypes.h:967
@ TokenSource
Definition: setypes.h:968
@ TokenGroups
Definition: setypes.h:963
@ TokenPrivileges
Definition: setypes.h:964
@ TokenUser
Definition: setypes.h:962
@ TokenPrimaryGroup
Definition: setypes.h:966
@ TokenOwner
Definition: setypes.h:965
struct _SID_AND_ATTRIBUTES SID_AND_ATTRIBUTES
#define TOKEN_SANDBOX_INERT
Definition: setypes.h:1181
#define SE_PRIVILEGE_ENABLED
Definition: setypes.h:63
#define TOKEN_IS_RESTRICTED
Definition: setypes.h:1179
#define TOKEN_HAS_ADMIN_GROUP
Definition: setypes.h:1178