ReactOS 0.4.16-dev-1946-g52006dd
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 /* Note: ObInsertObject dereferences AccessToken on failure */
421 return Status;
422 }
423 }
424 else
425 {
426 /* Return pointer instead of handle */
427 *TokenHandle = (HANDLE)AccessToken;
428 }
429
430Quit:
431 if (!NT_SUCCESS(Status))
432 {
433 /* Dereference the token, the delete procedure will clean it up */
434 ObDereferenceObject(AccessToken);
435 }
436
437 return Status;
438}
439
472NTAPI
480 _Out_ PTOKEN* NewAccessToken)
481{
483 PTOKEN AccessToken;
484 PVOID EndMem;
485 ULONG PrimaryGroupIndex;
486 ULONG VariableLength;
487 ULONG DynamicPartSize, TotalSize;
488 ULONG PrivilegesIndex, GroupsIndex;
489
490 PAGED_CODE();
491
492 /* Compute how much size we need to allocate for the token */
493 VariableLength = Token->VariableLength;
494 TotalSize = FIELD_OFFSET(TOKEN, VariablePart) + VariableLength;
495
496 /*
497 * Compute how much size we need to allocate
498 * the dynamic part of the newly duplicated
499 * token.
500 */
501 DynamicPartSize = Token->DefaultDacl ? Token->DefaultDacl->AclSize : 0;
502 DynamicPartSize += RtlLengthSid(Token->PrimaryGroup);
503
508 NULL,
509 TotalSize,
510 Token->DynamicCharged,
511 TotalSize,
512 (PVOID*)&AccessToken);
513 if (!NT_SUCCESS(Status))
514 {
515 DPRINT1("ObCreateObject() failed (Status 0x%lx)\n", Status);
516 return Status;
517 }
518
519 /* Zero out the buffer and initialize the token */
520 RtlZeroMemory(AccessToken, TotalSize);
521
522 ExAllocateLocallyUniqueId(&AccessToken->TokenId);
523
524 AccessToken->TokenType = TokenType;
525 AccessToken->ImpersonationLevel = Level;
526
527 /* Initialise the lock for the access token */
528 Status = SepCreateTokenLock(AccessToken);
529 if (!NT_SUCCESS(Status))
530 {
531 ObDereferenceObject(AccessToken);
532 return Status;
533 }
534
535 /* Copy the immutable fields */
536 AccessToken->TokenSource.SourceIdentifier = Token->TokenSource.SourceIdentifier;
538 Token->TokenSource.SourceName,
539 sizeof(Token->TokenSource.SourceName));
540
541 AccessToken->AuthenticationId = Token->AuthenticationId;
542 AccessToken->ParentTokenId = Token->ParentTokenId;
543 AccessToken->ExpirationTime = Token->ExpirationTime;
544 AccessToken->OriginatingLogonSession = Token->OriginatingLogonSession;
545 AccessToken->DynamicCharged = Token->DynamicCharged;
546
547 /* Lock the source token and copy the mutable fields */
549
550 AccessToken->SessionId = Token->SessionId;
551 AccessToken->ModifiedId = Token->ModifiedId;
552
553 AccessToken->TokenFlags = Token->TokenFlags & ~TOKEN_SESSION_NOT_REFERENCED;
554
555 /* Reference the logon session */
557 if (!NT_SUCCESS(Status))
558 {
559 /* No logon session could be found, bail out */
560 DPRINT1("SepRmReferenceLogonSession() failed (Status 0x%lx)\n", Status);
561 /* Set the flag for proper cleanup by the delete procedure */
563 goto Quit;
564 }
565
566 /* Insert the referenced logon session into the token */
568 if (!NT_SUCCESS(Status))
569 {
570 /* Failed to insert the logon session into the token, bail out */
571 DPRINT1("SepRmInsertLogonSessionIntoToken() failed (Status 0x%lx)\n", Status);
572 goto Quit;
573 }
574
575 /* Fill in token debug information */
576#if DBG
577 RtlCopyMemory(AccessToken->ImageFileName,
578 PsGetCurrentProcess()->ImageFileName,
579 min(sizeof(AccessToken->ImageFileName), sizeof(PsGetCurrentProcess()->ImageFileName)));
580
581 AccessToken->ProcessCid = PsGetCurrentProcessId();
582 AccessToken->ThreadCid = PsGetCurrentThreadId();
583 AccessToken->CreateMethod = TOKEN_DUPLICATE_METHOD;
584#endif
585
586 /* Assign the data that reside in the token's variable information area */
587 AccessToken->VariableLength = VariableLength;
588 EndMem = (PVOID)&AccessToken->VariablePart;
589
590 /* Copy the privileges */
591 AccessToken->PrivilegeCount = 0;
592 AccessToken->Privileges = NULL;
593 if (Token->Privileges && (Token->PrivilegeCount > 0))
594 {
595 ULONG PrivilegesLength = Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
596 PrivilegesLength = ALIGN_UP_BY(PrivilegesLength, sizeof(PVOID));
597
598 ASSERT(VariableLength >= PrivilegesLength);
599
600 AccessToken->PrivilegeCount = Token->PrivilegeCount;
601 AccessToken->Privileges = EndMem;
602 EndMem = (PVOID)((ULONG_PTR)EndMem + PrivilegesLength);
603 VariableLength -= PrivilegesLength;
604
605 RtlCopyMemory(AccessToken->Privileges,
606 Token->Privileges,
607 AccessToken->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
608 }
609
610 /* Copy the user and groups */
611 AccessToken->UserAndGroupCount = 0;
612 AccessToken->UserAndGroups = NULL;
613 if (Token->UserAndGroups && (Token->UserAndGroupCount > 0))
614 {
615 AccessToken->UserAndGroupCount = Token->UserAndGroupCount;
616 AccessToken->UserAndGroups = EndMem;
617 EndMem = &AccessToken->UserAndGroups[AccessToken->UserAndGroupCount];
618 VariableLength -= ((ULONG_PTR)EndMem - (ULONG_PTR)AccessToken->UserAndGroups);
619
621 Token->UserAndGroups,
622 VariableLength,
623 AccessToken->UserAndGroups,
624 EndMem,
625 &EndMem,
626 &VariableLength);
627 if (!NT_SUCCESS(Status))
628 {
629 DPRINT1("RtlCopySidAndAttributesArray(UserAndGroups) failed (Status 0x%lx)\n", Status);
630 goto Quit;
631 }
632 }
633
634 /* Find the token primary group */
636 Token->PrimaryGroup,
637 NULL,
638 &PrimaryGroupIndex,
639 NULL);
640 if (!NT_SUCCESS(Status))
641 {
642 DPRINT1("SepFindPrimaryGroupAndDefaultOwner failed (Status 0x%lx)\n", Status);
643 goto Quit;
644 }
645
646 /* Copy the restricted SIDs */
647 AccessToken->RestrictedSidCount = 0;
648 AccessToken->RestrictedSids = NULL;
649 if (Token->RestrictedSids && (Token->RestrictedSidCount > 0))
650 {
651 AccessToken->RestrictedSidCount = Token->RestrictedSidCount;
652 AccessToken->RestrictedSids = EndMem;
653 EndMem = &AccessToken->RestrictedSids[AccessToken->RestrictedSidCount];
654 VariableLength -= ((ULONG_PTR)EndMem - (ULONG_PTR)AccessToken->RestrictedSids);
655
657 Token->RestrictedSids,
658 VariableLength,
659 AccessToken->RestrictedSids,
660 EndMem,
661 &EndMem,
662 &VariableLength);
663 if (!NT_SUCCESS(Status))
664 {
665 DPRINT1("RtlCopySidAndAttributesArray(RestrictedSids) failed (Status 0x%lx)\n", Status);
666 goto Quit;
667 }
668 }
669
670 /* Now allocate the token's dynamic information area and set the data */
672 DynamicPartSize,
674 if (AccessToken->DynamicPart == NULL)
675 {
677 goto Quit;
678 }
679
680 /* Unused memory in the dynamic area */
681 AccessToken->DynamicAvailable = 0;
682
683 /*
684 * Assign the primary group to the token
685 * and put it in the dynamic part as well.
686 */
687 EndMem = (PVOID)AccessToken->DynamicPart;
688 AccessToken->PrimaryGroup = EndMem;
689 RtlCopySid(RtlLengthSid(AccessToken->UserAndGroups[PrimaryGroupIndex].Sid),
690 EndMem,
691 AccessToken->UserAndGroups[PrimaryGroupIndex].Sid);
692 AccessToken->DefaultOwnerIndex = Token->DefaultOwnerIndex;
693 EndMem = (PVOID)((ULONG_PTR)EndMem + RtlLengthSid(AccessToken->UserAndGroups[PrimaryGroupIndex].Sid));
694
695 /*
696 * The existing token has a default DACL only
697 * if it has an allocated dynamic part.
698 */
699 if (Token->DynamicPart && Token->DefaultDacl)
700 {
701 AccessToken->DefaultDacl = EndMem;
702
703 RtlCopyMemory(EndMem,
704 Token->DefaultDacl,
705 Token->DefaultDacl->AclSize);
706 }
707
708 /*
709 * Filter the token by removing the disabled privileges
710 * and groups if the caller wants to duplicate an access
711 * token as effective only.
712 */
713 if (EffectiveOnly)
714 {
715 /*
716 * Begin querying the groups and search for disabled ones. Do not touch the
717 * user which is at the first position because it cannot be disabled, no
718 * matter what attributes it has.
719 */
720 for (GroupsIndex = 1; GroupsIndex < AccessToken->UserAndGroupCount; GroupsIndex++)
721 {
722 /*
723 * A group is considered disabled if its attributes is either
724 * 0 or SE_GROUP_ENABLED is not included in the attributes flags list.
725 * That is because a certain user and/or group can have several attributes
726 * that bear no influence on whether a user/group is enabled or not
727 * (SE_GROUP_ENABLED_BY_DEFAULT for example which is a mere indicator
728 * that the group has just been enabled by default). A mandatory
729 * group (that is, the group has SE_GROUP_MANDATORY attribute)
730 * by standards it's always enabled and no one can disable it.
731 */
732 if (AccessToken->UserAndGroups[GroupsIndex].Attributes == 0 ||
733 (AccessToken->UserAndGroups[GroupsIndex].Attributes & SE_GROUP_ENABLED) == 0)
734 {
735 /*
736 * If this group is an administrators group
737 * and the token belongs to such group,
738 * we've to take away TOKEN_HAS_ADMIN_GROUP
739 * for the fact that's not enabled and as
740 * such the token no longer belongs to
741 * this group.
742 */
744 &AccessToken->UserAndGroups[GroupsIndex].Sid))
745 {
746 AccessToken->TokenFlags &= ~TOKEN_HAS_ADMIN_GROUP;
747 }
748
749 /*
750 * A group is not enabled, it's time to remove
751 * from the token and update the groups index
752 * accordingly and continue with the next group.
753 */
754 SepRemoveUserGroupToken(AccessToken, GroupsIndex);
755 GroupsIndex--;
756 }
757 }
758
759 /* Begin querying the privileges and search for disabled ones */
760 for (PrivilegesIndex = 0; PrivilegesIndex < AccessToken->PrivilegeCount; PrivilegesIndex++)
761 {
762 /*
763 * A privilege is considered disabled if its attributes is either
764 * 0 or SE_PRIVILEGE_ENABLED is not included in the attributes flags list.
765 * That is because a certain privilege can have several attributes
766 * that bear no influence on whether a privilege is enabled or not
767 * (SE_PRIVILEGE_ENABLED_BY_DEFAULT for example which is a mere indicator
768 * that the privilege has just been enabled by default).
769 */
770 if (AccessToken->Privileges[PrivilegesIndex].Attributes == 0 ||
771 (AccessToken->Privileges[PrivilegesIndex].Attributes & SE_PRIVILEGE_ENABLED) == 0)
772 {
773 /*
774 * A privilege is not enabled, therefor it's time
775 * to strip it from the token and continue with the next
776 * privilege. Of course we must also want to update the
777 * privileges index accordingly.
778 */
779 SepRemovePrivilegeToken(AccessToken, PrivilegesIndex);
780 PrivilegesIndex--;
781 }
782 }
783 }
784
785 /* Return the token to the caller */
786 *NewAccessToken = AccessToken;
788
789Quit:
790 if (!NT_SUCCESS(Status))
791 {
792 /* Dereference the token, the delete procedure will clean it up */
793 ObDereferenceObject(AccessToken);
794 }
795
796 /* Unlock the source token */
798
799 return Status;
800}
801
859static
863 _In_opt_ PLUID_AND_ATTRIBUTES PrivilegesToBeDeleted,
864 _In_opt_ PSID_AND_ATTRIBUTES SidsToBeDisabled,
865 _In_opt_ PSID_AND_ATTRIBUTES RestrictedSidsIntoToken,
866 _When_(PrivilegesToBeDeleted != NULL, _In_) ULONG PrivilegesCount,
867 _When_(SidsToBeDisabled != NULL, _In_) ULONG RegularGroupsSidCount,
868 _When_(RestrictedSidsIntoToken != NULL, _In_) ULONG RestrictedSidsCount,
869 _In_ ULONG PrivilegeFlags,
871 _Out_ PTOKEN *FilteredToken)
872{
874 PTOKEN AccessToken;
875 PVOID EndMem;
876 ULONG DynamicPartSize;
877 ULONG RestrictedSidsLength;
878 ULONG PrivilegesLength;
879 ULONG PrimaryGroupIndex;
880 ULONG RestrictedSidsInList;
881 ULONG RestrictedSidsInToken;
882 ULONG VariableLength, TotalSize;
883 ULONG PrivsInToken, PrivsInList;
884 ULONG GroupsInToken, GroupsInList;
885 BOOLEAN WantPrivilegesDisabled;
886 BOOLEAN FoundPrivilege;
887 BOOLEAN FoundGroup;
888
889 PAGED_CODE();
890
891 /* Ensure that the source token is valid, and lock it */
892 ASSERT(Token);
894
895 /* Assume the caller doesn't want privileges disabled */
896 WantPrivilegesDisabled = FALSE;
897
898 /* Assume we haven't found anything */
899 FoundPrivilege = FALSE;
900 FoundGroup = FALSE;
901
902 /*
903 * Take the size that we need for filtered token
904 * allocation based upon the existing access token
905 * we've been given.
906 */
907 VariableLength = Token->VariableLength;
908
909 if (RestrictedSidsIntoToken != NULL)
910 {
911 /*
912 * If the caller provided a list of restricted SIDs
913 * to be added onto the filtered access token then
914 * we must compute the size which is the total space
915 * of the current token and the length of the restricted
916 * SIDs for the filtered token.
917 */
918 RestrictedSidsLength = RestrictedSidsCount * sizeof(SID_AND_ATTRIBUTES);
919 RestrictedSidsLength += RtlLengthSidAndAttributes(RestrictedSidsCount, RestrictedSidsIntoToken);
920 RestrictedSidsLength = ALIGN_UP_BY(RestrictedSidsLength, sizeof(PVOID));
921
922 /*
923 * The variable length of the token is not just
924 * the actual space length of the existing token
925 * but also the sum of the restricted SIDs length.
926 */
927 VariableLength += RestrictedSidsLength;
928 TotalSize = FIELD_OFFSET(TOKEN, VariablePart) + VariableLength + RestrictedSidsLength;
929 }
930 else
931 {
932 /* Otherwise the size is of the actual current token */
933 TotalSize = FIELD_OFFSET(TOKEN, VariablePart) + VariableLength;
934 }
935
936 /*
937 * Compute how much size we need to allocate
938 * the dynamic part of the newly duplicated
939 * token.
940 */
941 DynamicPartSize = Token->DefaultDacl ? Token->DefaultDacl->AclSize : 0;
942 DynamicPartSize += RtlLengthSid(Token->PrimaryGroup);
943
944 /* Set up a filtered token object */
947 NULL,
949 NULL,
950 TotalSize,
951 Token->DynamicCharged,
952 TotalSize,
953 (PVOID*)&AccessToken);
954 if (!NT_SUCCESS(Status))
955 {
956 DPRINT1("SepPerformTokenFiltering(): Failed to create the filtered token object (Status 0x%lx)\n", Status);
957
958 /* Unlock the source token and bail out */
960 return Status;
961 }
962
963 /* Initialize the token and begin filling stuff to it */
964 RtlZeroMemory(AccessToken, TotalSize);
965
966 /* Set up a lock for the new token */
967 Status = SepCreateTokenLock(AccessToken);
968 if (!NT_SUCCESS(Status))
969 goto Quit;
970
971 /* Allocate new IDs for the token */
972 ExAllocateLocallyUniqueId(&AccessToken->TokenId);
974
975 /* Copy the type and impersonation level from the token */
976 AccessToken->TokenType = Token->TokenType;
977 AccessToken->ImpersonationLevel = Token->ImpersonationLevel;
978
979 /* Copy the immutable fields */
980 AccessToken->TokenSource.SourceIdentifier = Token->TokenSource.SourceIdentifier;
982 Token->TokenSource.SourceName,
983 sizeof(Token->TokenSource.SourceName));
984
985 AccessToken->AuthenticationId = Token->AuthenticationId;
986 AccessToken->ParentTokenId = Token->TokenId;
987 AccessToken->OriginatingLogonSession = Token->OriginatingLogonSession;
988 AccessToken->DynamicCharged = Token->DynamicCharged;
989
990 AccessToken->ExpirationTime = Token->ExpirationTime;
991
992 /* Copy the mutable fields */
993 AccessToken->SessionId = Token->SessionId;
994 AccessToken->TokenFlags = Token->TokenFlags & ~TOKEN_SESSION_NOT_REFERENCED;
995
996 /* Reference the logon session */
998 if (!NT_SUCCESS(Status))
999 {
1000 /* We failed, bail out*/
1001 DPRINT1("SepPerformTokenFiltering(): Failed to reference the logon session (Status 0x%lx)\n", Status);
1003 goto Quit;
1004 }
1005
1006 /* Insert the referenced logon session into the token */
1008 if (!NT_SUCCESS(Status))
1009 {
1010 /* Failed to insert the logon session into the token, bail out */
1011 DPRINT1("SepPerformTokenFiltering(): Failed to insert the logon session into token (Status 0x%lx)\n", Status);
1012 goto Quit;
1013 }
1014
1015 /* Fill in token debug information */
1016#if DBG
1017 RtlCopyMemory(AccessToken->ImageFileName,
1018 PsGetCurrentProcess()->ImageFileName,
1019 min(sizeof(AccessToken->ImageFileName), sizeof(PsGetCurrentProcess()->ImageFileName)));
1020
1021 AccessToken->ProcessCid = PsGetCurrentProcessId();
1022 AccessToken->ThreadCid = PsGetCurrentThreadId();
1023 AccessToken->CreateMethod = TOKEN_FILTER_METHOD;
1024#endif
1025
1026 /* Assign the data that reside in the token's variable information area */
1027 AccessToken->VariableLength = VariableLength;
1028 EndMem = (PVOID)&AccessToken->VariablePart;
1029
1030 /* Copy the privileges from the existing token */
1031 AccessToken->PrivilegeCount = 0;
1032 AccessToken->Privileges = NULL;
1033 if (Token->Privileges && (Token->PrivilegeCount > 0))
1034 {
1035 PrivilegesLength = Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
1036 PrivilegesLength = ALIGN_UP_BY(PrivilegesLength, sizeof(PVOID));
1037
1038 /*
1039 * Ensure that the token can actually hold all
1040 * the privileges from the existing token.
1041 * Otherwise something's seriously wrong and
1042 * we've to guard ourselves.
1043 */
1044 ASSERT(VariableLength >= PrivilegesLength);
1045
1046 AccessToken->PrivilegeCount = Token->PrivilegeCount;
1047 AccessToken->Privileges = EndMem;
1048 EndMem = (PVOID)((ULONG_PTR)EndMem + PrivilegesLength);
1049 VariableLength -= PrivilegesLength;
1050
1051 RtlCopyMemory(AccessToken->Privileges,
1052 Token->Privileges,
1053 AccessToken->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
1054 }
1055
1056 /* Copy the user and groups */
1057 AccessToken->UserAndGroupCount = 0;
1058 AccessToken->UserAndGroups = NULL;
1059 if (Token->UserAndGroups && (Token->UserAndGroupCount > 0))
1060 {
1061 AccessToken->UserAndGroupCount = Token->UserAndGroupCount;
1062 AccessToken->UserAndGroups = EndMem;
1063 EndMem = &AccessToken->UserAndGroups[AccessToken->UserAndGroupCount];
1064 VariableLength -= ((ULONG_PTR)EndMem - (ULONG_PTR)AccessToken->UserAndGroups);
1065
1067 Token->UserAndGroups,
1068 VariableLength,
1069 AccessToken->UserAndGroups,
1070 EndMem,
1071 &EndMem,
1072 &VariableLength);
1073 if (!NT_SUCCESS(Status))
1074 {
1075 DPRINT1("SepPerformTokenFiltering(): Failed to copy the groups into token (Status 0x%lx)\n", Status);
1076 goto Quit;
1077 }
1078 }
1079
1080 /* Copy the restricted SIDs */
1081 AccessToken->RestrictedSidCount = 0;
1082 AccessToken->RestrictedSids = NULL;
1083 if (Token->RestrictedSids && (Token->RestrictedSidCount > 0))
1084 {
1085 AccessToken->RestrictedSidCount = Token->RestrictedSidCount;
1086 AccessToken->RestrictedSids = EndMem;
1087 EndMem = &AccessToken->RestrictedSids[AccessToken->RestrictedSidCount];
1088 VariableLength -= ((ULONG_PTR)EndMem - (ULONG_PTR)AccessToken->RestrictedSids);
1089
1091 Token->RestrictedSids,
1092 VariableLength,
1093 AccessToken->RestrictedSids,
1094 EndMem,
1095 &EndMem,
1096 &VariableLength);
1097 if (!NT_SUCCESS(Status))
1098 {
1099 DPRINT1("SepPerformTokenFiltering(): Failed to copy the restricted SIDs into token (Status 0x%lx)\n", Status);
1100 goto Quit;
1101 }
1102 }
1103
1104 /*
1105 * Insert the restricted SIDs into the token on
1106 * the request by the caller.
1107 */
1108 if (RestrictedSidsIntoToken != NULL)
1109 {
1110 for (RestrictedSidsInList = 0; RestrictedSidsInList < RestrictedSidsCount; RestrictedSidsInList++)
1111 {
1112 /* Did the caller assign attributes to the restricted SIDs? */
1113 if (RestrictedSidsIntoToken[RestrictedSidsInList].Attributes != 0)
1114 {
1115 /* There mustn't be any attributes, bail out */
1116 DPRINT1("SepPerformTokenFiltering(): There mustn't be any attributes to restricted SIDs!\n");
1118 goto Quit;
1119 }
1120 }
1121
1122 /*
1123 * Ensure that the token can hold the restricted SIDs
1124 * (the variable length is calculated at the beginning
1125 * of the routine call).
1126 */
1127 ASSERT(VariableLength >= RestrictedSidsLength);
1128
1129 /*
1130 * Now let's begin inserting the restricted SIDs into the filtered
1131 * access token from the list the caller gave us.
1132 */
1133 AccessToken->RestrictedSidCount = RestrictedSidsCount;
1134 AccessToken->RestrictedSids = EndMem;
1135 EndMem = (PVOID)((ULONG_PTR)EndMem + RestrictedSidsLength);
1136 VariableLength -= RestrictedSidsLength;
1137
1138 RtlCopyMemory(AccessToken->RestrictedSids,
1139 RestrictedSidsIntoToken,
1140 AccessToken->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES));
1141
1142 /*
1143 * As we've copied the restricted SIDs into
1144 * the token, we must assign them the following
1145 * combination of attributes SE_GROUP_ENABLED,
1146 * SE_GROUP_ENABLED_BY_DEFAULT and SE_GROUP_MANDATORY.
1147 * With such attributes we estabilish that restricting
1148 * SIDs into the token are enabled for access checks.
1149 */
1150 for (RestrictedSidsInToken = 0; RestrictedSidsInToken < AccessToken->RestrictedSidCount; RestrictedSidsInToken++)
1151 {
1153 }
1154
1155 /*
1156 * As we added restricted SIDs into the token, mark
1157 * it as restricted.
1158 */
1159 AccessToken->TokenFlags |= TOKEN_IS_RESTRICTED;
1160 }
1161
1162 /* Search for the primary group */
1164 Token->PrimaryGroup,
1165 NULL,
1166 &PrimaryGroupIndex,
1167 NULL);
1168 if (!NT_SUCCESS(Status))
1169 {
1170 DPRINT1("SepPerformTokenFiltering(): Failed searching for the primary group (Status 0x%lx)\n", Status);
1171 goto Quit;
1172 }
1173
1174 /* Now allocate the token's dynamic information area and set the data */
1176 DynamicPartSize,
1178 if (AccessToken->DynamicPart == NULL)
1179 {
1181 goto Quit;
1182 }
1183
1184 /* Unused memory in the dynamic area */
1185 AccessToken->DynamicAvailable = 0;
1186
1187 /*
1188 * Assign the primary group to the token
1189 * and put it in the dynamic part as well.
1190 */
1191 EndMem = (PVOID)AccessToken->DynamicPart;
1192 AccessToken->PrimaryGroup = EndMem;
1193 RtlCopySid(RtlLengthSid(AccessToken->UserAndGroups[PrimaryGroupIndex].Sid),
1194 EndMem,
1195 AccessToken->UserAndGroups[PrimaryGroupIndex].Sid);
1196 AccessToken->DefaultOwnerIndex = Token->DefaultOwnerIndex;
1197 EndMem = (PVOID)((ULONG_PTR)EndMem + RtlLengthSid(AccessToken->UserAndGroups[PrimaryGroupIndex].Sid));
1198
1199 /*
1200 * The existing token has a default DACL only
1201 * if it has an allocated dynamic part.
1202 */
1203 if (Token->DynamicPart && Token->DefaultDacl)
1204 {
1205 AccessToken->DefaultDacl = EndMem;
1206
1207 RtlCopyMemory(EndMem,
1208 Token->DefaultDacl,
1209 Token->DefaultDacl->AclSize);
1210 }
1211
1212 /*
1213 * Now figure out what does the caller
1214 * want with the privileges.
1215 */
1216 if (PrivilegeFlags & DISABLE_MAX_PRIVILEGE)
1217 {
1218 /*
1219 * The caller wants them disabled, cache this request
1220 * for later operations.
1221 */
1222 WantPrivilegesDisabled = TRUE;
1223 }
1224
1225 if (PrivilegeFlags & SANDBOX_INERT)
1226 {
1227 /* The caller wants an inert token, store the TOKEN_SANDBOX_INERT flag now */
1228 AccessToken->TokenFlags |= TOKEN_SANDBOX_INERT;
1229 }
1230
1231 /*
1232 * Now it's time to filter the token's privileges.
1233 * Loop all the privileges in the token.
1234 */
1235 for (PrivsInToken = 0; PrivsInToken < AccessToken->PrivilegeCount; PrivsInToken++)
1236 {
1237 if (WantPrivilegesDisabled)
1238 {
1239 /*
1240 * We got the acknowledgement that the caller wants
1241 * to disable all the privileges so let's just do it.
1242 * However, as per the general documentation is stated
1243 * that only SE_CHANGE_NOTIFY_PRIVILEGE must be kept
1244 * therefore in that case we must skip this privilege.
1245 */
1246 if (AccessToken->Privileges[PrivsInToken].Luid.LowPart == SE_CHANGE_NOTIFY_PRIVILEGE)
1247 {
1248 continue;
1249 }
1250 else
1251 {
1252 /*
1253 * The act of disabling privileges actually means
1254 * "deleting" them from the access token entirely.
1255 * First we must disable them so that we can update
1256 * token flags accordingly.
1257 */
1258 AccessToken->Privileges[PrivsInToken].Attributes &= ~SE_PRIVILEGE_ENABLED;
1259 SepUpdateSinglePrivilegeFlagToken(AccessToken, PrivsInToken);
1260
1261 /* Remove the privileges now */
1262 SepRemovePrivilegeToken(AccessToken, PrivsInToken);
1263 PrivsInToken--;
1264 }
1265 }
1266 else
1267 {
1268 if (PrivilegesToBeDeleted != NULL)
1269 {
1270 /* Loop the privileges we've got to delete */
1271 for (PrivsInList = 0; PrivsInList < PrivilegesCount; PrivsInList++)
1272 {
1273 /* Does this privilege exist in the token? */
1274 if (RtlEqualLuid(&AccessToken->Privileges[PrivsInToken].Luid,
1275 &PrivilegesToBeDeleted[PrivsInList].Luid))
1276 {
1277 /* Mark that we found it */
1278 FoundPrivilege = TRUE;
1279 break;
1280 }
1281 }
1282
1283 /* Did we find the privilege? */
1284 if (PrivsInList == PrivilegesCount)
1285 {
1286 /* We didn't, continue with next one */
1287 continue;
1288 }
1289 }
1290 }
1291
1292 /*
1293 * If we have found the target privilege in the token
1294 * based on the privileges list given by the caller
1295 * then begin deleting it.
1296 */
1297 if (FoundPrivilege)
1298 {
1299 /* Disable the privilege and update the flags */
1300 AccessToken->Privileges[PrivsInToken].Attributes &= ~SE_PRIVILEGE_ENABLED;
1301 SepUpdateSinglePrivilegeFlagToken(AccessToken, PrivsInToken);
1302
1303 /* Delete the privilege */
1304 SepRemovePrivilegeToken(AccessToken, PrivsInToken);
1305
1306 /*
1307 * Adjust the index and reset the FoundPrivilege indicator
1308 * so that we can continue with the next privilege to delete.
1309 */
1310 PrivsInToken--;
1311 FoundPrivilege = FALSE;
1312 continue;
1313 }
1314 }
1315
1316 /*
1317 * Loop the group SIDs that we want to disable as
1318 * per on the request by the caller.
1319 */
1320 if (SidsToBeDisabled != NULL)
1321 {
1322 for (GroupsInToken = 0; GroupsInToken < AccessToken->UserAndGroupCount; GroupsInToken++)
1323 {
1324 for (GroupsInList = 0; GroupsInList < RegularGroupsSidCount; GroupsInList++)
1325 {
1326 /* Does this group SID exist in the token? */
1327 if (RtlEqualSid(&AccessToken->UserAndGroups[GroupsInToken].Sid,
1328 &SidsToBeDisabled[GroupsInList].Sid))
1329 {
1330 /* Mark that we found it */
1331 FoundGroup = TRUE;
1332 break;
1333 }
1334 }
1335
1336 /* Did we find the group? */
1337 if (GroupsInList == RegularGroupsSidCount)
1338 {
1339 /* We didn't, continue with next one */
1340 continue;
1341 }
1342
1343 /* If we have found the group, disable it */
1344 if (FoundGroup)
1345 {
1346 /*
1347 * If the acess token belongs to the administrators
1348 * group and this is the target group, we must take
1349 * away TOKEN_HAS_ADMIN_GROUP flag from the token.
1350 */
1352 &AccessToken->UserAndGroups[GroupsInToken].Sid))
1353 {
1354 AccessToken->TokenFlags &= ~TOKEN_HAS_ADMIN_GROUP;
1355 }
1356
1357 /*
1358 * If the target group that we have found it is the
1359 * owner then from now on it no longer is but the user.
1360 * Therefore assign the default owner index as the user.
1361 */
1362 if (AccessToken->DefaultOwnerIndex == GroupsInToken)
1363 {
1364 AccessToken->DefaultOwnerIndex = 0;
1365 }
1366
1367 /*
1368 * The principle of disabling a group SID is by
1369 * taking away SE_GROUP_ENABLED_BY_DEFAULT and
1370 * SE_GROUP_ENABLED attributes and assign
1371 * SE_GROUP_USE_FOR_DENY_ONLY. This renders
1372 * SID a "Deny only" SID.
1373 */
1374 AccessToken->UserAndGroups[GroupsInToken].Attributes &= ~(SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT);
1375 AccessToken->UserAndGroups[GroupsInToken].Attributes |= SE_GROUP_USE_FOR_DENY_ONLY;
1376
1377 /* Adjust the index and continue with the next group */
1378 GroupsInToken--;
1379 FoundGroup = FALSE;
1380 continue;
1381 }
1382 }
1383 }
1384
1385 /* We've finally filtered the token, return it to the caller */
1386 *FilteredToken = AccessToken;
1388 DPRINT("SepPerformTokenFiltering(): The token has been filtered!\n");
1389
1390Quit:
1391 if (!NT_SUCCESS(Status))
1392 {
1393 /* Dereference the created token */
1394 ObDereferenceObject(AccessToken);
1395 }
1396
1397 /* Unlock the source token */
1399
1400 return Status;
1401}
1402
1403/* PUBLIC FUNCTIONS ***********************************************************/
1404
1439NTAPI
1441 _In_ PACCESS_TOKEN ExistingToken,
1443 _In_opt_ PTOKEN_GROUPS SidsToDisable,
1444 _In_opt_ PTOKEN_PRIVILEGES PrivilegesToDelete,
1445 _In_opt_ PTOKEN_GROUPS RestrictedSids,
1446 _Out_ PACCESS_TOKEN *FilteredToken)
1447{
1449 PTOKEN AccessToken;
1450 ULONG PrivilegesCount = 0;
1451 ULONG SidsCount = 0;
1452 ULONG RestrictedSidsCount = 0;
1453
1454 PAGED_CODE();
1455
1456 /* Begin copying the counters */
1457 if (SidsToDisable != NULL)
1458 {
1459 SidsCount = SidsToDisable->GroupCount;
1460 }
1461
1462 if (PrivilegesToDelete != NULL)
1463 {
1464 PrivilegesCount = PrivilegesToDelete->PrivilegeCount;
1465 }
1466
1467 if (RestrictedSids != NULL)
1468 {
1469 RestrictedSidsCount = RestrictedSids->GroupCount;
1470 }
1471
1472 /* Call the internal API */
1473 Status = SepPerformTokenFiltering(ExistingToken,
1474 PrivilegesToDelete->Privileges,
1475 SidsToDisable->Groups,
1476 RestrictedSids->Groups,
1477 PrivilegesCount,
1478 SidsCount,
1479 RestrictedSidsCount,
1480 Flags,
1481 KernelMode,
1482 &AccessToken);
1483 if (!NT_SUCCESS(Status))
1484 {
1485 DPRINT1("SeFilterToken(): Failed to filter the token (Status 0x%lx)\n", Status);
1486 return Status;
1487 }
1488
1489 /* Insert the filtered token */
1490 Status = ObInsertObject(AccessToken,
1491 NULL,
1492 0,
1493 0,
1494 NULL,
1495 NULL);
1496 if (!NT_SUCCESS(Status))
1497 {
1498 DPRINT1("SeFilterToken(): Failed to insert the filtered token (Status 0x%lx)\n", Status);
1499 return Status;
1500 }
1501
1502 /* Return it to the caller */
1503 *FilteredToken = AccessToken;
1504 return Status;
1505}
1506
1507/* SYSTEM CALLS ***************************************************************/
1508
1559NTAPI
1565 _In_ PLUID AuthenticationId,
1566 _In_ PLARGE_INTEGER ExpirationTime,
1574{
1575 HANDLE hToken;
1577 ULONG PrivilegeCount, GroupCount;
1578 PSID OwnerSid, PrimaryGroupSid;
1579 PACL DefaultDacl;
1580 LARGE_INTEGER LocalExpirationTime = {{0, 0}};
1581 LUID LocalAuthenticationId;
1582 TOKEN_SOURCE LocalTokenSource;
1583 SECURITY_QUALITY_OF_SERVICE LocalSecurityQos;
1584 PLUID_AND_ATTRIBUTES CapturedPrivileges = NULL;
1585 PSID_AND_ATTRIBUTES CapturedUser = NULL;
1586 PSID_AND_ATTRIBUTES CapturedGroups = NULL;
1587 PSID CapturedOwnerSid = NULL;
1588 PSID CapturedPrimaryGroupSid = NULL;
1589 PACL CapturedDefaultDacl = NULL;
1590 ULONG PrivilegesLength, UserLength, GroupsLength;
1592
1593 PAGED_CODE();
1594
1596
1597 if (PreviousMode != KernelMode)
1598 {
1599 _SEH2_TRY
1600 {
1602
1603 if (ObjectAttributes != NULL)
1604 {
1606 sizeof(OBJECT_ATTRIBUTES),
1607 sizeof(ULONG));
1608 LocalSecurityQos = *(SECURITY_QUALITY_OF_SERVICE*)ObjectAttributes->SecurityQualityOfService;
1609 }
1610
1611 ProbeForRead(AuthenticationId,
1612 sizeof(LUID),
1613 sizeof(ULONG));
1614 LocalAuthenticationId = *AuthenticationId;
1615
1616 LocalExpirationTime = ProbeForReadLargeInteger(ExpirationTime);
1617
1619 sizeof(TOKEN_USER),
1620 sizeof(ULONG));
1621
1623 sizeof(TOKEN_GROUPS),
1624 sizeof(ULONG));
1625 GroupCount = TokenGroups->GroupCount;
1626
1628 sizeof(TOKEN_PRIVILEGES),
1629 sizeof(ULONG));
1630 PrivilegeCount = TokenPrivileges->PrivilegeCount;
1631
1632 if (TokenOwner != NULL)
1633 {
1635 sizeof(TOKEN_OWNER),
1636 sizeof(ULONG));
1637 OwnerSid = TokenOwner->Owner;
1638 }
1639 else
1640 {
1641 OwnerSid = NULL;
1642 }
1643
1645 sizeof(TOKEN_PRIMARY_GROUP),
1646 sizeof(ULONG));
1647 PrimaryGroupSid = TokenPrimaryGroup->PrimaryGroup;
1648
1649 if (TokenDefaultDacl != NULL)
1650 {
1652 sizeof(TOKEN_DEFAULT_DACL),
1653 sizeof(ULONG));
1654 DefaultDacl = TokenDefaultDacl->DefaultDacl;
1655 }
1656 else
1657 {
1658 DefaultDacl = NULL;
1659 }
1660
1662 sizeof(TOKEN_SOURCE),
1663 sizeof(ULONG));
1664 LocalTokenSource = *TokenSource;
1665 }
1667 {
1668 /* Return the exception code */
1670 }
1671 _SEH2_END;
1672 }
1673 else
1674 {
1675 if (ObjectAttributes != NULL)
1676 LocalSecurityQos = *(SECURITY_QUALITY_OF_SERVICE*)ObjectAttributes->SecurityQualityOfService;
1677 LocalAuthenticationId = *AuthenticationId;
1678 LocalExpirationTime = *ExpirationTime;
1679 GroupCount = TokenGroups->GroupCount;
1680 PrivilegeCount = TokenPrivileges->PrivilegeCount;
1681 OwnerSid = TokenOwner ? TokenOwner->Owner : NULL;
1682 PrimaryGroupSid = TokenPrimaryGroup->PrimaryGroup;
1683 DefaultDacl = TokenDefaultDacl ? TokenDefaultDacl->DefaultDacl : NULL;
1684 LocalTokenSource = *TokenSource;
1685 }
1686
1687 /* Check token type */
1688 if ((TokenType < TokenPrimary) ||
1690 {
1691 return STATUS_BAD_TOKEN_TYPE;
1692 }
1693
1694 /* Check for token creation privilege */
1696 {
1698 }
1699
1700 /* Capture the user SID and attributes */
1702 1,
1704 NULL,
1705 0,
1706 PagedPool,
1707 FALSE,
1708 &CapturedUser,
1709 &UserLength);
1710 if (!NT_SUCCESS(Status))
1711 {
1712 goto Cleanup;
1713 }
1714
1715 /* Capture the groups SID and attributes array */
1717 GroupCount,
1719 NULL,
1720 0,
1721 PagedPool,
1722 FALSE,
1723 &CapturedGroups,
1724 &GroupsLength);
1725 if (!NT_SUCCESS(Status))
1726 {
1727 goto Cleanup;
1728 }
1729
1730 /* Capture privileges */
1732 PrivilegeCount,
1734 NULL,
1735 0,
1736 PagedPool,
1737 FALSE,
1738 &CapturedPrivileges,
1739 &PrivilegesLength);
1740 if (!NT_SUCCESS(Status))
1741 {
1742 goto Cleanup;
1743 }
1744
1745 /* Capture the token owner SID */
1746 if (TokenOwner != NULL)
1747 {
1748 Status = SepCaptureSid(OwnerSid,
1750 PagedPool,
1751 FALSE,
1752 &CapturedOwnerSid);
1753 if (!NT_SUCCESS(Status))
1754 {
1755 goto Cleanup;
1756 }
1757 }
1758
1759 /* Capture the token primary group SID */
1760 Status = SepCaptureSid(PrimaryGroupSid,
1762 PagedPool,
1763 FALSE,
1764 &CapturedPrimaryGroupSid);
1765 if (!NT_SUCCESS(Status))
1766 {
1767 goto Cleanup;
1768 }
1769
1770 /* Capture DefaultDacl */
1771 if (DefaultDacl != NULL)
1772 {
1773 Status = SepCaptureAcl(DefaultDacl,
1776 FALSE,
1777 &CapturedDefaultDacl);
1778 if (!NT_SUCCESS(Status))
1779 {
1780 goto Cleanup;
1781 }
1782 }
1783
1784 /* Call the internal function */
1785 Status = SepCreateToken(&hToken,
1789 TokenType,
1790 LocalSecurityQos.ImpersonationLevel,
1791 &LocalAuthenticationId,
1792 &LocalExpirationTime,
1793 CapturedUser,
1794 GroupCount,
1795 CapturedGroups,
1796 GroupsLength,
1797 PrivilegeCount,
1798 CapturedPrivileges,
1799 CapturedOwnerSid,
1800 CapturedPrimaryGroupSid,
1801 CapturedDefaultDacl,
1802 &LocalTokenSource,
1803 FALSE);
1804 if (NT_SUCCESS(Status))
1805 {
1806 _SEH2_TRY
1807 {
1808 *TokenHandle = hToken;
1809 }
1811 {
1813 }
1814 _SEH2_END;
1815 }
1816
1817Cleanup:
1818
1819 /* Release what we captured */
1823 SepReleaseSid(CapturedOwnerSid, PreviousMode, FALSE);
1824 SepReleaseSid(CapturedPrimaryGroupSid, PreviousMode, FALSE);
1825 SepReleaseAcl(CapturedDefaultDacl, PreviousMode, FALSE);
1826
1827 return Status;
1828}
1829
1870NTAPI
1872 _In_ HANDLE ExistingTokenHandle,
1878{
1880 HANDLE hToken;
1881 PTOKEN Token;
1882 PTOKEN NewToken;
1883 PSECURITY_QUALITY_OF_SERVICE CapturedSecurityQualityOfService;
1884 BOOLEAN QoSPresent;
1887
1888 PAGED_CODE();
1889
1892 {
1894 }
1895
1897
1898 if (PreviousMode != KernelMode)
1899 {
1900 _SEH2_TRY
1901 {
1903 }
1905 {
1906 /* Return the exception code */
1908 }
1909 _SEH2_END;
1910 }
1911
1914 PagedPool,
1915 FALSE,
1916 &CapturedSecurityQualityOfService,
1917 &QoSPresent);
1918 if (!NT_SUCCESS(Status))
1919 {
1920 DPRINT1("NtDuplicateToken() failed to capture QoS! Status: 0x%x\n", Status);
1921 return Status;
1922 }
1923
1924 Status = ObReferenceObjectByHandle(ExistingTokenHandle,
1928 (PVOID*)&Token,
1930 if (!NT_SUCCESS(Status))
1931 {
1932 DPRINT1("Failed to reference token (Status 0x%lx)\n", Status);
1933 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
1935 FALSE);
1936 return Status;
1937 }
1938
1939 /*
1940 * Fail, if the original token is an impersonation token and the caller
1941 * tries to raise the impersonation level of the new token above the
1942 * impersonation level of the original token.
1943 */
1944 if (Token->TokenType == TokenImpersonation)
1945 {
1946 if (QoSPresent &&
1947 CapturedSecurityQualityOfService->ImpersonationLevel >Token->ImpersonationLevel)
1948 {
1950 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
1952 FALSE);
1954 }
1955 }
1956
1957 /*
1958 * Fail, if a primary token is to be created from an impersonation token
1959 * and and the impersonation level of the impersonation token is below SecurityImpersonation.
1960 */
1961 if (Token->TokenType == TokenImpersonation &&
1963 Token->ImpersonationLevel < SecurityImpersonation)
1964 {
1966 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
1968 FALSE);
1970 }
1971
1975 TokenType,
1976 (QoSPresent ? CapturedSecurityQualityOfService->ImpersonationLevel : SecurityAnonymous),
1978 &NewToken);
1979
1981
1982 if (NT_SUCCESS(Status))
1983 {
1984 Status = ObInsertObject(NewToken,
1985 NULL,
1986 (DesiredAccess ? DesiredAccess : HandleInformation.GrantedAccess),
1987 0,
1988 NULL,
1989 &hToken);
1990 if (NT_SUCCESS(Status))
1991 {
1992 _SEH2_TRY
1993 {
1994 *NewTokenHandle = hToken;
1995 }
1997 {
1999 }
2000 _SEH2_END;
2001 }
2002 }
2003
2004 /* Free the captured structure */
2005 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService,
2007 FALSE);
2008
2009 return Status;
2010}
2011
2076NTAPI
2078 _In_ HANDLE ExistingTokenHandle,
2080 _In_opt_ PTOKEN_GROUPS SidsToDisable,
2081 _In_opt_ PTOKEN_PRIVILEGES PrivilegesToDelete,
2082 _In_opt_ PTOKEN_GROUPS RestrictedSids,
2084{
2085 PTOKEN Token, FilteredToken;
2086 HANDLE FilteredTokenHandle;
2089 OBJECT_HANDLE_INFORMATION HandleInfo;
2091 ULONG CapturedSidsCount = 0;
2092 ULONG CapturedPrivilegesCount = 0;
2093 ULONG CapturedRestrictedSidsCount = 0;
2094 ULONG ProbeSize = 0;
2095 PSID_AND_ATTRIBUTES CapturedSids = NULL;
2096 PSID_AND_ATTRIBUTES CapturedRestrictedSids = NULL;
2097 PLUID_AND_ATTRIBUTES CapturedPrivileges = NULL;
2098
2099 PAGED_CODE();
2100
2102
2103 _SEH2_TRY
2104 {
2105 /* Probe SidsToDisable */
2106 if (SidsToDisable != NULL)
2107 {
2108 /* Probe the header */
2109 ProbeForRead(SidsToDisable, sizeof(*SidsToDisable), sizeof(ULONG));
2110
2111 CapturedSidsCount = SidsToDisable->GroupCount;
2112 ProbeSize = FIELD_OFFSET(TOKEN_GROUPS, Groups[CapturedSidsCount]);
2113
2114 ProbeForRead(SidsToDisable, ProbeSize, sizeof(ULONG));
2115 }
2116
2117 /* Probe PrivilegesToDelete */
2118 if (PrivilegesToDelete != NULL)
2119 {
2120 /* Probe the header */
2121 ProbeForRead(PrivilegesToDelete, sizeof(*PrivilegesToDelete), sizeof(ULONG));
2122
2123 CapturedPrivilegesCount = PrivilegesToDelete->PrivilegeCount;
2124 ProbeSize = FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges[CapturedPrivilegesCount]);
2125
2126 ProbeForRead(PrivilegesToDelete, ProbeSize, sizeof(ULONG));
2127 }
2128
2129 /* Probe RestrictedSids */
2130 if (RestrictedSids != NULL)
2131 {
2132 /* Probe the header */
2133 ProbeForRead(RestrictedSids, sizeof(*RestrictedSids), sizeof(ULONG));
2134
2135 CapturedRestrictedSidsCount = RestrictedSids->GroupCount;
2136 ProbeSize = FIELD_OFFSET(TOKEN_GROUPS, Groups[CapturedRestrictedSidsCount]);
2137
2138 ProbeForRead(RestrictedSids, ProbeSize, sizeof(ULONG));
2139 }
2140
2141 /* Probe the handle */
2143 }
2145 {
2146 /* Return the exception code */
2148 }
2149 _SEH2_END;
2150
2151 /* Reference the token */
2152 Status = ObReferenceObjectByHandle(ExistingTokenHandle,
2156 (PVOID*)&Token,
2157 &HandleInfo);
2158 if (!NT_SUCCESS(Status))
2159 {
2160 DPRINT1("NtFilterToken(): Failed to reference the token (Status 0x%lx)\n", Status);
2161 return Status;
2162 }
2163
2164 /* Capture the group SIDs */
2165 if (SidsToDisable != NULL)
2166 {
2167 Status = SeCaptureSidAndAttributesArray(SidsToDisable->Groups,
2168 CapturedSidsCount,
2170 NULL,
2171 0,
2172 PagedPool,
2173 TRUE,
2174 &CapturedSids,
2175 &ResultLength);
2176 if (!NT_SUCCESS(Status))
2177 {
2178 DPRINT1("NtFilterToken(): Failed to capture the SIDs (Status 0x%lx)\n", Status);
2179 goto Quit;
2180 }
2181 }
2182
2183 /* Capture the privileges */
2184 if (PrivilegesToDelete != NULL)
2185 {
2186 Status = SeCaptureLuidAndAttributesArray(PrivilegesToDelete->Privileges,
2187 CapturedPrivilegesCount,
2189 NULL,
2190 0,
2191 PagedPool,
2192 TRUE,
2193 &CapturedPrivileges,
2194 &ResultLength);
2195 if (!NT_SUCCESS(Status))
2196 {
2197 DPRINT1("NtFilterToken(): Failed to capture the privileges (Status 0x%lx)\n", Status);
2198 goto Quit;
2199 }
2200 }
2201
2202 /* Capture the restricted SIDs */
2203 if (RestrictedSids != NULL)
2204 {
2205 Status = SeCaptureSidAndAttributesArray(RestrictedSids->Groups,
2206 CapturedRestrictedSidsCount,
2208 NULL,
2209 0,
2210 PagedPool,
2211 TRUE,
2212 &CapturedRestrictedSids,
2213 &ResultLength);
2214 if (!NT_SUCCESS(Status))
2215 {
2216 DPRINT1("NtFilterToken(): Failed to capture the restricted SIDs (Status 0x%lx)\n", Status);
2217 goto Quit;
2218 }
2219 }
2220
2221 /* Call the internal API */
2223 CapturedPrivileges,
2224 CapturedSids,
2225 CapturedRestrictedSids,
2226 CapturedPrivilegesCount,
2227 CapturedSidsCount,
2228 CapturedRestrictedSidsCount,
2229 Flags,
2231 &FilteredToken);
2232 if (!NT_SUCCESS(Status))
2233 {
2234 DPRINT1("NtFilterToken(): Failed to filter the token (Status 0x%lx)\n", Status);
2235 goto Quit;
2236 }
2237
2238 /* Insert the filtered token and retrieve a handle to it */
2239 Status = ObInsertObject(FilteredToken,
2240 NULL,
2241 HandleInfo.GrantedAccess,
2242 0,
2243 NULL,
2244 &FilteredTokenHandle);
2245 if (!NT_SUCCESS(Status))
2246 {
2247 DPRINT1("NtFilterToken(): Failed to insert the filtered token (Status 0x%lx)\n", Status);
2248 /* Note: ObInsertObject dereferences FilteredToken on failure */
2249 goto Quit;
2250 }
2251
2252 /* And return it to the caller once we're done */
2253 _SEH2_TRY
2254 {
2255 *NewTokenHandle = FilteredTokenHandle;
2256 }
2258 {
2260 _SEH2_YIELD(goto Quit);
2261 }
2262 _SEH2_END;
2263
2264Quit:
2265 /* Dereference the token */
2267
2268 /* Release all the captured data */
2269 if (CapturedSids != NULL)
2270 {
2271 SeReleaseSidAndAttributesArray(CapturedSids,
2273 TRUE);
2274 }
2275
2276 if (CapturedPrivileges != NULL)
2277 {
2278 SeReleaseLuidAndAttributesArray(CapturedPrivileges,
2280 TRUE);
2281 }
2282
2283 if (CapturedRestrictedSids != NULL)
2284 {
2285 SeReleaseSidAndAttributesArray(CapturedRestrictedSids,
2287 TRUE);
2288 }
2289
2290 return Status;
2291}
2292
2293/* EOF */
#define PAGED_CODE()
#define STATUS_PRIVILEGE_NOT_HELD
Definition: DriverTester.h:9
#define ALIGN_UP_BY(size, align)
_In_ PVOID _In_ ULONG _Out_ PVOID _In_ ULONG _Inout_ PULONG _In_ KPROCESSOR_MODE PreviousMode
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:33
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:143
VOID NTAPI ProbeForRead(IN CONST VOID *Address, IN SIZE_T Length, IN ULONG Alignment)
Definition: exintrin.c:102
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:90
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 KeGetPreviousMode()
Definition: ketypes.h:1115
#define KernelMode
Definition: asm.h:38
_In_ ACCESS_MASK _In_ ULONG _Out_ PHANDLE TokenHandle
Definition: psfuncs.h:727
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:1629
_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:1631
NTSYSAPI ULONG NTAPI RtlLengthSid(IN PSID Sid)
Definition: sid.c:150
_In_ ULONG _In_ ACCESS_MASK _In_ PSID Sid
Definition: rtlfuncs.h:1165
NTSYSAPI BOOLEAN NTAPI RtlEqualSid(_In_ PSID Sid1, _In_ PSID Sid2)
_In_ ACCESS_MASK _In_opt_ POBJECT_ATTRIBUTES _In_ BOOLEAN EffectiveOnly
Definition: sefuncs.h:410
_In_ ACCESS_MASK _In_opt_ POBJECT_ATTRIBUTES _In_ BOOLEAN _In_ TOKEN_TYPE _Out_ PHANDLE NewTokenHandle
Definition: sefuncs.h:412
_In_ ACCESS_MASK _In_opt_ POBJECT_ATTRIBUTES _In_ BOOLEAN _In_ TOKEN_TYPE TokenType
Definition: sefuncs.h:411
#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
#define _Must_inspect_result_
Definition: no_sal2.h:62
#define _Out_
Definition: no_sal2.h:160
#define _In_
Definition: no_sal2.h:158
#define _In_opt_
Definition: no_sal2.h:212
#define _When_(c, a)
Definition: no_sal2.h:38
ULONG ACCESS_MASK
Definition: nt_native.h:40
VOID NTAPI ExAllocateLocallyUniqueId(OUT LUID *LocallyUniqueId)
Definition: uuid.c:335
EPROCESS KiInitialProcess
Definition: krnlinit.c:41
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:80
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:976
#define SepAcquireTokenLockShared(Token)
Definition: se.h:290
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:693
#define SepReleaseTokenLock(Token)
Definition: se.h:296
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:82
#define TOKEN_DUPLICATE_METHOD
Definition: se.h:81
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:498
#define STATUS_BAD_IMPERSONATION_LEVEL
Definition: ntstatus.h:495
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:1039
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:181
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:82
#define _SEH2_END
Definition: pseh2_64.h:171
#define _SEH2_TRY
Definition: pseh2_64.h:71
#define _SEH2_YIELD(__stmt)
Definition: pseh2_64.h:184
#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:73
#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:157
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:861
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:473
__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:1560
#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:2077
_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:1871
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:1440
#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:3782
_Must_inspect_result_ _In_ WDFDEVICE _In_ ULONG _In_ ACCESS_MASK DesiredAccess
Definition: wdfdevice.h:2664
_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:157
#define RtlEqualLuid(Luid1, Luid2)
Definition: rtlfuncs.h:304
_In_ PSECURITY_SUBJECT_CONTEXT _In_ BOOLEAN _In_ ACCESS_MASK _In_ ACCESS_MASK _Outptr_opt_ PPRIVILEGE_SET * Privileges
Definition: sefuncs.h:17
#define TOKEN_SESSION_NOT_REFERENCED
Definition: setypes.h:1196
#define TOKEN_DUPLICATE
Definition: setypes.h:938
struct _LUID_AND_ATTRIBUTES LUID_AND_ATTRIBUTES
@ TokenDefaultDacl
Definition: setypes.h:983
@ TokenSource
Definition: setypes.h:984
@ TokenGroups
Definition: setypes.h:979
@ TokenPrivileges
Definition: setypes.h:980
@ TokenUser
Definition: setypes.h:978
@ TokenPrimaryGroup
Definition: setypes.h:982
@ TokenOwner
Definition: setypes.h:981
struct _SID_AND_ATTRIBUTES SID_AND_ATTRIBUTES
#define TOKEN_SANDBOX_INERT
Definition: setypes.h:1197
#define SE_PRIVILEGE_ENABLED
Definition: setypes.h:63
#define TOKEN_IS_RESTRICTED
Definition: setypes.h:1195
#define TOKEN_HAS_ADMIN_GROUP
Definition: setypes.h:1194