2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/se/token.c
5 * PURPOSE: Security manager
7 * PROGRAMMERS: David Welch <welch@cwcom.net>
10 /* INCLUDES *******************************************************************/
16 #if defined (ALLOC_PRAGMA)
17 #pragma alloc_text(INIT, SepInitializeTokenImplementation)
22 typedef struct _TOKEN_AUDIT_POLICY_INFORMATION
30 } TOKEN_AUDIT_POLICY_INFORMATION
, *PTOKEN_AUDIT_POLICY_INFORMATION
;
32 /* GLOBALS ********************************************************************/
34 POBJECT_TYPE SeTokenObjectType
= NULL
;
35 ERESOURCE SepTokenLock
;
37 TOKEN_SOURCE SeSystemTokenSource
= {"*SYSTEM*", {0}};
38 LUID SeSystemAuthenticationId
= SYSTEM_LUID
;
39 LUID SeAnonymousAuthenticationId
= ANONYMOUS_LOGON_LUID
;
41 static GENERIC_MAPPING SepTokenMapping
= {
48 static const INFORMATION_CLASS_INFO SeTokenInformationClass
[] = {
50 /* Class 0 not used, blame M$! */
51 ICI_SQ_SAME( 0, 0, 0),
54 ICI_SQ_SAME( sizeof(TOKEN_USER
), sizeof(ULONG
), ICIF_QUERY
| ICIF_QUERY_SIZE_VARIABLE
| ICIF_SET_SIZE_VARIABLE
),
56 ICI_SQ_SAME( sizeof(TOKEN_GROUPS
), sizeof(ULONG
), ICIF_QUERY
| ICIF_QUERY_SIZE_VARIABLE
| ICIF_SET_SIZE_VARIABLE
),
58 ICI_SQ_SAME( sizeof(TOKEN_PRIVILEGES
), sizeof(ULONG
), ICIF_QUERY
| ICIF_QUERY_SIZE_VARIABLE
| ICIF_SET_SIZE_VARIABLE
),
60 ICI_SQ_SAME( sizeof(TOKEN_OWNER
), sizeof(ULONG
), ICIF_QUERY
| ICIF_QUERY_SIZE_VARIABLE
| ICIF_SET
| ICIF_SET_SIZE_VARIABLE
),
61 /* TokenPrimaryGroup */
62 ICI_SQ_SAME( sizeof(TOKEN_PRIMARY_GROUP
), sizeof(ULONG
), ICIF_QUERY
| ICIF_QUERY_SIZE_VARIABLE
| ICIF_SET
| ICIF_SET_SIZE_VARIABLE
),
63 /* TokenDefaultDacl */
64 ICI_SQ_SAME( sizeof(TOKEN_DEFAULT_DACL
), sizeof(ULONG
), ICIF_QUERY
| ICIF_QUERY_SIZE_VARIABLE
| ICIF_SET
| ICIF_SET_SIZE_VARIABLE
),
66 ICI_SQ_SAME( sizeof(TOKEN_SOURCE
), sizeof(ULONG
), ICIF_QUERY
| ICIF_QUERY_SIZE_VARIABLE
| ICIF_SET_SIZE_VARIABLE
),
68 ICI_SQ_SAME( sizeof(TOKEN_TYPE
), sizeof(ULONG
), ICIF_QUERY
| ICIF_QUERY_SIZE_VARIABLE
),
69 /* TokenImpersonationLevel */
70 ICI_SQ_SAME( sizeof(SECURITY_IMPERSONATION_LEVEL
), sizeof(ULONG
), ICIF_QUERY
| ICIF_QUERY_SIZE_VARIABLE
),
72 ICI_SQ_SAME( sizeof(TOKEN_STATISTICS
), sizeof(ULONG
), ICIF_QUERY
| ICIF_QUERY_SIZE_VARIABLE
| ICIF_SET_SIZE_VARIABLE
),
73 /* TokenRestrictedSids */
74 ICI_SQ_SAME( sizeof(TOKEN_GROUPS
), sizeof(ULONG
), ICIF_QUERY
| ICIF_QUERY_SIZE_VARIABLE
),
76 ICI_SQ_SAME( sizeof(ULONG
), sizeof(ULONG
), ICIF_QUERY
| ICIF_SET
),
77 /* TokenGroupsAndPrivileges */
78 ICI_SQ_SAME( sizeof(TOKEN_GROUPS_AND_PRIVILEGES
), sizeof(ULONG
), ICIF_QUERY
| ICIF_QUERY_SIZE_VARIABLE
),
79 /* TokenSessionReference */
80 ICI_SQ_SAME( sizeof(ULONG
), sizeof(ULONG
), ICIF_SET
| ICIF_QUERY_SIZE_VARIABLE
),
81 /* TokenSandBoxInert */
82 ICI_SQ_SAME( sizeof(ULONG
), sizeof(ULONG
), ICIF_QUERY
| ICIF_QUERY_SIZE_VARIABLE
),
83 /* TokenAuditPolicy */
84 ICI_SQ_SAME( /* FIXME */0, sizeof(ULONG
), ICIF_QUERY
| ICIF_SET
| ICIF_QUERY_SIZE_VARIABLE
),
86 ICI_SQ_SAME( sizeof(TOKEN_ORIGIN
), sizeof(ULONG
), ICIF_QUERY
| ICIF_SET
| ICIF_QUERY_SIZE_VARIABLE
),
89 /* FUNCTIONS *****************************************************************/
92 SepCompareTokens(IN PTOKEN FirstToken
,
93 IN PTOKEN SecondToken
,
96 BOOLEAN Restricted
, IsEqual
= FALSE
;
98 ASSERT(FirstToken
!= SecondToken
);
100 /* FIXME: Check if every SID that is present in either token is also present in the other one */
102 Restricted
= SeTokenIsRestricted(FirstToken
);
103 if (Restricted
== SeTokenIsRestricted(SecondToken
))
107 /* FIXME: Check if every SID that is restricted in either token is also restricted in the other one */
110 /* FIXME: Check if every privilege that is present in either token is also present in the other one */
114 return STATUS_SUCCESS
;
119 SepUpdateSinglePrivilegeFlagToken(
120 _Inout_ PTOKEN Token
,
124 NT_ASSERT(Index
< Token
->PrivilegeCount
);
126 /* The high part of all values we are interested in is 0 */
127 if (Token
->Privileges
[Index
].Luid
.HighPart
!= 0)
132 /* Check for certain privileges to update flags */
133 if (Token
->Privileges
[Index
].Luid
.LowPart
== SE_CHANGE_NOTIFY_PRIVILEGE
)
135 TokenFlag
= TOKEN_HAS_TRAVERSE_PRIVILEGE
;
137 else if (Token
->Privileges
[Index
].Luid
.LowPart
== SE_BACKUP_PRIVILEGE
)
139 TokenFlag
= TOKEN_HAS_BACKUP_PRIVILEGE
;
141 else if (Token
->Privileges
[Index
].Luid
.LowPart
== SE_RESTORE_PRIVILEGE
)
143 TokenFlag
= TOKEN_HAS_RESTORE_PRIVILEGE
;
145 else if (Token
->Privileges
[Index
].Luid
.LowPart
== SE_IMPERSONATE_PRIVILEGE
)
147 TokenFlag
= TOKEN_HAS_IMPERSONATE_PRIVILEGE
;
155 /* Check if the specified privilege is enabled */
156 if (Token
->Privileges
[Index
].Attributes
& SE_PRIVILEGE_ENABLED
)
158 /* It is enabled, so set the flag */
159 Token
->TokenFlags
|= TokenFlag
;
163 /* Is is disabled, so remove the flag */
164 Token
->TokenFlags
&= ~TokenFlag
;
170 SepUpdatePrivilegeFlagsToken(
171 _Inout_ PTOKEN Token
)
175 /* Loop all privileges */
176 for (i
= 0; i
< Token
->PrivilegeCount
; i
++)
178 /* Updates the flags dor this privilege */
179 SepUpdateSinglePrivilegeFlagToken(Token
, i
);
185 SepRemovePrivilegeToken(
186 _Inout_ PTOKEN Token
,
190 NT_ASSERT(Index
< Token
->PrivilegeCount
);
192 /* Calculate the number of trailing privileges */
193 MoveCount
= Token
->PrivilegeCount
- Index
- 1;
196 /* Move them one location ahead */
197 RtlMoveMemory(&Token
->Privileges
[Index
],
198 &Token
->Privileges
[Index
+ 1],
199 MoveCount
* sizeof(LUID_AND_ATTRIBUTES
));
202 /* Update privilege count */
203 Token
->PrivilegeCount
--;
208 SepFreeProxyData(PVOID ProxyData
)
215 SepCopyProxyData(PVOID
* Dest
,
219 return STATUS_NOT_IMPLEMENTED
;
224 SeExchangePrimaryToken(PEPROCESS Process
,
225 PACCESS_TOKEN NewTokenP
,
226 PACCESS_TOKEN
* OldTokenP
)
229 PTOKEN NewToken
= (PTOKEN
)NewTokenP
;
233 if (NewToken
->TokenType
!= TokenPrimary
) return(STATUS_BAD_TOKEN_TYPE
);
234 if (NewToken
->TokenInUse
) return(STATUS_TOKEN_ALREADY_IN_USE
);
236 /* Mark new token in use */
237 NewToken
->TokenInUse
= 1;
239 /* Reference the New Token */
240 ObReferenceObject(NewToken
);
242 /* Replace the old with the new */
243 OldToken
= ObFastReplaceObject(&Process
->Token
, NewToken
);
245 /* Mark the Old Token as free */
246 OldToken
->TokenInUse
= 0;
248 *OldTokenP
= (PACCESS_TOKEN
)OldToken
;
249 return STATUS_SUCCESS
;
254 SeDeassignPrimaryToken(PEPROCESS Process
)
258 /* Remove the Token */
259 OldToken
= ObFastReplaceObject(&Process
->Token
, NULL
);
261 /* Mark the Old Token as free */
262 OldToken
->TokenInUse
= 0;
266 RtlLengthSidAndAttributes(ULONG Count
,
267 PSID_AND_ATTRIBUTES Src
)
274 uLength
= Count
* sizeof(SID_AND_ATTRIBUTES
);
275 for (i
= 0; i
< Count
; i
++)
276 uLength
+= RtlLengthSid(Src
[i
].Sid
);
284 SepFindPrimaryGroupAndDefaultOwner(PTOKEN Token
,
290 Token
->PrimaryGroup
= 0;
294 Token
->DefaultOwnerIndex
= Token
->UserAndGroupCount
;
297 /* Validate and set the primary group and user pointers */
298 for (i
= 0; i
< Token
->UserAndGroupCount
; i
++)
301 RtlEqualSid(Token
->UserAndGroups
[i
].Sid
, DefaultOwner
))
303 Token
->DefaultOwnerIndex
= i
;
306 if (RtlEqualSid(Token
->UserAndGroups
[i
].Sid
, PrimaryGroup
))
308 Token
->PrimaryGroup
= Token
->UserAndGroups
[i
].Sid
;
312 if (Token
->DefaultOwnerIndex
== Token
->UserAndGroupCount
)
314 return(STATUS_INVALID_OWNER
);
317 if (Token
->PrimaryGroup
== 0)
319 return(STATUS_INVALID_PRIMARY_GROUP
);
322 return STATUS_SUCCESS
;
328 SepDuplicateToken(PTOKEN Token
,
329 POBJECT_ATTRIBUTES ObjectAttributes
,
330 BOOLEAN EffectiveOnly
,
331 TOKEN_TYPE TokenType
,
332 SECURITY_IMPERSONATION_LEVEL Level
,
333 KPROCESSOR_MODE PreviousMode
,
334 PTOKEN
* NewAccessToken
)
339 PTOKEN AccessToken
= NULL
;
344 Status
= ObCreateObject(PreviousMode
,
352 (PVOID
*)&AccessToken
);
353 if (!NT_SUCCESS(Status
))
355 DPRINT1("ObCreateObject() failed (Status %lx)\n", Status
);
359 /* Zero out the buffer */
360 RtlZeroMemory(AccessToken
, sizeof(TOKEN
));
362 Status
= ZwAllocateLocallyUniqueId(&AccessToken
->TokenId
);
363 if (!NT_SUCCESS(Status
))
365 ObDereferenceObject(AccessToken
);
369 Status
= ZwAllocateLocallyUniqueId(&AccessToken
->ModifiedId
);
370 if (!NT_SUCCESS(Status
))
372 ObDereferenceObject(AccessToken
);
376 AccessToken
->TokenLock
= &SepTokenLock
;
378 AccessToken
->TokenType
= TokenType
;
379 AccessToken
->ImpersonationLevel
= Level
;
380 RtlCopyLuid(&AccessToken
->AuthenticationId
, &Token
->AuthenticationId
);
382 AccessToken
->TokenSource
.SourceIdentifier
.LowPart
= Token
->TokenSource
.SourceIdentifier
.LowPart
;
383 AccessToken
->TokenSource
.SourceIdentifier
.HighPart
= Token
->TokenSource
.SourceIdentifier
.HighPart
;
384 memcpy(AccessToken
->TokenSource
.SourceName
,
385 Token
->TokenSource
.SourceName
,
386 sizeof(Token
->TokenSource
.SourceName
));
387 AccessToken
->ExpirationTime
.QuadPart
= Token
->ExpirationTime
.QuadPart
;
388 AccessToken
->UserAndGroupCount
= Token
->UserAndGroupCount
;
389 AccessToken
->DefaultOwnerIndex
= Token
->DefaultOwnerIndex
;
391 uLength
= sizeof(SID_AND_ATTRIBUTES
) * AccessToken
->UserAndGroupCount
;
392 for (i
= 0; i
< Token
->UserAndGroupCount
; i
++)
393 uLength
+= RtlLengthSid(Token
->UserAndGroups
[i
].Sid
);
395 AccessToken
->UserAndGroups
= ExAllocatePoolWithTag(PagedPool
,
398 if (AccessToken
->UserAndGroups
== NULL
)
400 Status
= STATUS_INSUFFICIENT_RESOURCES
;
404 EndMem
= &AccessToken
->UserAndGroups
[AccessToken
->UserAndGroupCount
];
406 Status
= RtlCopySidAndAttributesArray(AccessToken
->UserAndGroupCount
,
407 Token
->UserAndGroups
,
409 AccessToken
->UserAndGroups
,
413 if (!NT_SUCCESS(Status
))
416 Status
= SepFindPrimaryGroupAndDefaultOwner(AccessToken
,
419 if (!NT_SUCCESS(Status
))
422 AccessToken
->PrivilegeCount
= Token
->PrivilegeCount
;
424 uLength
= AccessToken
->PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
);
425 AccessToken
->Privileges
= ExAllocatePoolWithTag(PagedPool
,
427 TAG_TOKEN_PRIVILAGES
);
428 if (AccessToken
->Privileges
== NULL
)
430 Status
= STATUS_INSUFFICIENT_RESOURCES
;
434 for (i
= 0; i
< AccessToken
->PrivilegeCount
; i
++)
436 RtlCopyLuid(&AccessToken
->Privileges
[i
].Luid
,
437 &Token
->Privileges
[i
].Luid
);
438 AccessToken
->Privileges
[i
].Attributes
=
439 Token
->Privileges
[i
].Attributes
;
442 if (Token
->DefaultDacl
)
444 AccessToken
->DefaultDacl
= ExAllocatePoolWithTag(PagedPool
,
445 Token
->DefaultDacl
->AclSize
,
447 if (AccessToken
->DefaultDacl
== NULL
)
449 Status
= STATUS_INSUFFICIENT_RESOURCES
;
453 memcpy(AccessToken
->DefaultDacl
,
455 Token
->DefaultDacl
->AclSize
);
458 *NewAccessToken
= AccessToken
;
461 if (!NT_SUCCESS(Status
))
465 if (AccessToken
->UserAndGroups
)
466 ExFreePoolWithTag(AccessToken
->UserAndGroups
, TAG_TOKEN_USERS
);
468 if (AccessToken
->Privileges
)
469 ExFreePoolWithTag(AccessToken
->Privileges
, TAG_TOKEN_PRIVILAGES
);
471 if (AccessToken
->DefaultDacl
)
472 ExFreePoolWithTag(AccessToken
->DefaultDacl
, TAG_TOKEN_ACL
);
474 ObDereferenceObject(AccessToken
);
483 SeSubProcessToken(IN PTOKEN ParentToken
,
489 OBJECT_ATTRIBUTES ObjectAttributes
;
492 /* Initialize the attributes and duplicate it */
493 InitializeObjectAttributes(&ObjectAttributes
, NULL
, 0, NULL
, NULL
);
494 Status
= SepDuplicateToken(ParentToken
,
498 ParentToken
->ImpersonationLevel
,
501 if (NT_SUCCESS(Status
))
504 Status
= ObInsertObject(NewToken
,
510 if (NT_SUCCESS(Status
))
512 /* Set the session ID */
513 NewToken
->SessionId
= SessionId
;
514 NewToken
->TokenInUse
= InUse
;
516 /* Return the token */
527 SeIsTokenChild(IN PTOKEN Token
,
528 OUT PBOOLEAN IsChild
)
531 LUID ProcessLuid
, CallerLuid
;
536 /* Reference the process token */
537 ProcessToken
= PsReferencePrimaryToken(PsGetCurrentProcess());
540 ProcessLuid
= ProcessToken
->TokenId
;
542 /* Dereference the token */
543 ObFastDereferenceObject(&PsGetCurrentProcess()->Token
, ProcessToken
);
546 CallerLuid
= Token
->TokenId
;
548 /* Compare the LUIDs */
549 if (RtlEqualLuid(&CallerLuid
, &ProcessLuid
)) *IsChild
= TRUE
;
552 return STATUS_SUCCESS
;
557 SeCopyClientToken(IN PACCESS_TOKEN Token
,
558 IN SECURITY_IMPERSONATION_LEVEL Level
,
559 IN KPROCESSOR_MODE PreviousMode
,
560 OUT PACCESS_TOKEN
* NewToken
)
563 OBJECT_ATTRIBUTES ObjectAttributes
;
567 InitializeObjectAttributes(&ObjectAttributes
,
572 Status
= SepDuplicateToken(Token
,
585 SepDeleteToken(PVOID ObjectBody
)
587 PTOKEN AccessToken
= (PTOKEN
)ObjectBody
;
589 if (AccessToken
->UserAndGroups
)
590 ExFreePoolWithTag(AccessToken
->UserAndGroups
, TAG_TOKEN_USERS
);
592 if (AccessToken
->Privileges
)
593 ExFreePoolWithTag(AccessToken
->Privileges
, TAG_TOKEN_PRIVILAGES
);
595 if (AccessToken
->DefaultDacl
)
596 ExFreePoolWithTag(AccessToken
->DefaultDacl
, TAG_TOKEN_ACL
);
603 SepInitializeTokenImplementation(VOID
)
606 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
608 ExInitializeResource(&SepTokenLock
);
610 DPRINT("Creating Token Object Type\n");
612 /* Initialize the Token type */
613 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
614 RtlInitUnicodeString(&Name
, L
"Token");
615 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
616 ObjectTypeInitializer
.InvalidAttributes
= OBJ_OPENLINK
;
617 ObjectTypeInitializer
.SecurityRequired
= TRUE
;
618 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(TOKEN
);
619 ObjectTypeInitializer
.GenericMapping
= SepTokenMapping
;
620 ObjectTypeInitializer
.PoolType
= PagedPool
;
621 ObjectTypeInitializer
.ValidAccessMask
= TOKEN_ALL_ACCESS
;
622 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
623 ObjectTypeInitializer
.DeleteProcedure
= SepDeleteToken
;
624 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &SeTokenObjectType
);
629 SeAssignPrimaryToken(IN PEPROCESS Process
,
635 ASSERT(Token
->TokenType
== TokenPrimary
);
636 ASSERT(!Token
->TokenInUse
);
638 /* Clean any previous token */
639 if (Process
->Token
.Object
) SeDeassignPrimaryToken(Process
);
641 /* Set the new token */
642 ObReferenceObject(Token
);
643 Token
->TokenInUse
= TRUE
;
644 ObInitializeFastReference(&Process
->Token
, Token
);
650 SepCreateToken(OUT PHANDLE TokenHandle
,
651 IN KPROCESSOR_MODE PreviousMode
,
652 IN ACCESS_MASK DesiredAccess
,
653 IN POBJECT_ATTRIBUTES ObjectAttributes
,
654 IN TOKEN_TYPE TokenType
,
655 IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
,
656 IN PLUID AuthenticationId
,
657 IN PLARGE_INTEGER ExpirationTime
,
658 IN PSID_AND_ATTRIBUTES User
,
660 IN PSID_AND_ATTRIBUTES Groups
,
661 IN ULONG GroupLength
,
662 IN ULONG PrivilegeCount
,
663 IN PLUID_AND_ATTRIBUTES Privileges
,
665 IN PSID PrimaryGroup
,
667 IN PTOKEN_SOURCE TokenSource
,
668 IN BOOLEAN SystemToken
)
677 ULONG TokenFlags
= 0;
679 /* Loop all groups */
680 for (i
= 0; i
< GroupCount
; i
++)
682 /* Check for mandatory groups */
683 if (Groups
[i
].Attributes
& SE_GROUP_MANDATORY
)
685 /* Force them to be enabled */
686 Groups
[i
].Attributes
|= (SE_GROUP_ENABLED
| SE_GROUP_ENABLED_BY_DEFAULT
);
689 /* Check of the group is an admin group */
690 if (RtlEqualSid(SeAliasAdminsSid
, Groups
[i
].Sid
))
692 /* Remember this so we can optimize queries later */
693 TokenFlags
|= TOKEN_HAS_ADMIN_GROUP
;
697 Status
= ZwAllocateLocallyUniqueId(&TokenId
);
698 if (!NT_SUCCESS(Status
))
701 Status
= ZwAllocateLocallyUniqueId(&ModifiedId
);
702 if (!NT_SUCCESS(Status
))
705 Status
= ObCreateObject(PreviousMode
,
713 (PVOID
*)&AccessToken
);
714 if (!NT_SUCCESS(Status
))
716 DPRINT1("ObCreateObject() failed (Status %lx)\n", Status
);
720 /* Zero out the buffer */
721 RtlZeroMemory(AccessToken
, sizeof(TOKEN
));
723 AccessToken
->TokenLock
= &SepTokenLock
;
725 RtlCopyLuid(&AccessToken
->TokenSource
.SourceIdentifier
,
726 &TokenSource
->SourceIdentifier
);
727 memcpy(AccessToken
->TokenSource
.SourceName
,
728 TokenSource
->SourceName
,
729 sizeof(TokenSource
->SourceName
));
731 RtlCopyLuid(&AccessToken
->TokenId
, &TokenId
);
732 RtlCopyLuid(&AccessToken
->AuthenticationId
, AuthenticationId
);
733 AccessToken
->ExpirationTime
= *ExpirationTime
;
734 RtlCopyLuid(&AccessToken
->ModifiedId
, &ModifiedId
);
736 AccessToken
->UserAndGroupCount
= GroupCount
+ 1;
737 AccessToken
->PrivilegeCount
= PrivilegeCount
;
739 AccessToken
->TokenFlags
= TokenFlags
;
740 AccessToken
->TokenType
= TokenType
;
741 AccessToken
->ImpersonationLevel
= ImpersonationLevel
;
744 * Normally we would just point these members into the variable information
745 * area; however, our ObCreateObject() call can't allocate a variable information
746 * area, so we allocate them seperately and provide a destroy function.
749 uLength
= sizeof(SID_AND_ATTRIBUTES
) * AccessToken
->UserAndGroupCount
;
750 uLength
+= RtlLengthSid(User
->Sid
);
751 for (i
= 0; i
< GroupCount
; i
++)
752 uLength
+= RtlLengthSid(Groups
[i
].Sid
);
754 // FIXME: should use the object itself
755 AccessToken
->UserAndGroups
= ExAllocatePoolWithTag(PagedPool
,
758 if (AccessToken
->UserAndGroups
== NULL
)
760 Status
= STATUS_INSUFFICIENT_RESOURCES
;
764 EndMem
= &AccessToken
->UserAndGroups
[AccessToken
->UserAndGroupCount
];
766 Status
= RtlCopySidAndAttributesArray(1,
769 AccessToken
->UserAndGroups
,
773 if (!NT_SUCCESS(Status
))
776 Status
= RtlCopySidAndAttributesArray(GroupCount
,
779 &AccessToken
->UserAndGroups
[1],
783 if (!NT_SUCCESS(Status
))
786 Status
= SepFindPrimaryGroupAndDefaultOwner(AccessToken
,
789 if (!NT_SUCCESS(Status
))
792 // FIXME: should use the object itself
793 uLength
= PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
);
794 if (uLength
== 0) uLength
= sizeof(PVOID
);
795 AccessToken
->Privileges
= ExAllocatePoolWithTag(PagedPool
,
797 TAG_TOKEN_PRIVILAGES
);
798 if (AccessToken
->Privileges
== NULL
)
800 Status
= STATUS_INSUFFICIENT_RESOURCES
;
804 if (PreviousMode
!= KernelMode
)
808 RtlCopyMemory(AccessToken
->Privileges
,
810 PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
));
812 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
814 Status
= _SEH2_GetExceptionCode();
820 RtlCopyMemory(AccessToken
->Privileges
,
822 PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
));
825 if (!NT_SUCCESS(Status
))
828 /* Update privilege flags */
829 SepUpdatePrivilegeFlagsToken(AccessToken
);
831 if (DefaultDacl
!= NULL
)
833 // FIXME: should use the object itself
834 AccessToken
->DefaultDacl
= ExAllocatePoolWithTag(PagedPool
,
835 DefaultDacl
->AclSize
,
837 if (AccessToken
->DefaultDacl
== NULL
)
839 Status
= STATUS_INSUFFICIENT_RESOURCES
;
843 RtlCopyMemory(AccessToken
->DefaultDacl
,
845 DefaultDacl
->AclSize
);
849 AccessToken
->DefaultDacl
= NULL
;
854 Status
= ObInsertObject((PVOID
)AccessToken
,
860 if (!NT_SUCCESS(Status
))
862 DPRINT1("ObInsertObject() failed (Status %lx)\n", Status
);
867 /* Return pointer instead of handle */
868 *TokenHandle
= (HANDLE
)AccessToken
;
872 if (!NT_SUCCESS(Status
))
876 /* Dereference the token, the delete procedure will clean up */
877 ObDereferenceObject(AccessToken
);
886 SepCreateSystemProcessToken(VOID
)
888 LUID_AND_ATTRIBUTES Privileges
[25];
889 ULONG GroupAttributes
, OwnerAttributes
;
890 SID_AND_ATTRIBUTES Groups
[32];
891 LARGE_INTEGER Expiration
;
892 SID_AND_ATTRIBUTES UserSid
;
895 OBJECT_ATTRIBUTES ObjectAttributes
;
901 /* Don't ever expire */
902 Expiration
.QuadPart
= -1;
904 /* All groups mandatory and enabled */
905 GroupAttributes
= SE_GROUP_ENABLED
| SE_GROUP_MANDATORY
| SE_GROUP_ENABLED_BY_DEFAULT
;
906 OwnerAttributes
= SE_GROUP_ENABLED
| SE_GROUP_OWNER
| SE_GROUP_ENABLED_BY_DEFAULT
;
909 UserSid
.Sid
= SeLocalSystemSid
;
910 UserSid
.Attributes
= 0;
912 /* Primary group is local system */
913 PrimaryGroup
= SeLocalSystemSid
;
915 /* Owner is admins */
916 Owner
= SeAliasAdminsSid
;
918 /* Groups are admins, world, and authenticated users */
919 Groups
[0].Sid
= SeAliasAdminsSid
;
920 Groups
[0].Attributes
= OwnerAttributes
;
921 Groups
[1].Sid
= SeWorldSid
;
922 Groups
[1].Attributes
= GroupAttributes
;
923 Groups
[2].Sid
= SeAuthenticatedUserSid
;
924 Groups
[2].Attributes
= OwnerAttributes
;
925 GroupLength
= sizeof(SID_AND_ATTRIBUTES
) +
926 SeLengthSid(Groups
[0].Sid
) +
927 SeLengthSid(Groups
[1].Sid
) +
928 SeLengthSid(Groups
[2].Sid
);
929 ASSERT(GroupLength
<= sizeof(Groups
));
931 /* Setup the privileges */
933 Privileges
[i
].Attributes
= SE_PRIVILEGE_ENABLED_BY_DEFAULT
| SE_PRIVILEGE_ENABLED
;
934 Privileges
[i
++].Luid
= SeTcbPrivilege
;
936 Privileges
[i
].Attributes
= 0;
937 Privileges
[i
++].Luid
= SeCreateTokenPrivilege
;
939 Privileges
[i
].Attributes
= 0;
940 Privileges
[i
++].Luid
= SeTakeOwnershipPrivilege
;
942 Privileges
[i
].Attributes
= SE_PRIVILEGE_ENABLED_BY_DEFAULT
| SE_PRIVILEGE_ENABLED
;
943 Privileges
[i
++].Luid
= SeCreatePagefilePrivilege
;
945 Privileges
[i
].Attributes
= SE_PRIVILEGE_ENABLED_BY_DEFAULT
| SE_PRIVILEGE_ENABLED
;
946 Privileges
[i
++].Luid
= SeLockMemoryPrivilege
;
948 Privileges
[i
].Attributes
= 0;
949 Privileges
[i
++].Luid
= SeAssignPrimaryTokenPrivilege
;
951 Privileges
[i
].Attributes
= 0;
952 Privileges
[i
++].Luid
= SeIncreaseQuotaPrivilege
;
954 Privileges
[i
].Attributes
= SE_PRIVILEGE_ENABLED_BY_DEFAULT
| SE_PRIVILEGE_ENABLED
;
955 Privileges
[i
++].Luid
= SeIncreaseBasePriorityPrivilege
;
957 Privileges
[i
].Attributes
= SE_PRIVILEGE_ENABLED_BY_DEFAULT
| SE_PRIVILEGE_ENABLED
;
958 Privileges
[i
++].Luid
= SeCreatePermanentPrivilege
;
960 Privileges
[i
].Attributes
= SE_PRIVILEGE_ENABLED_BY_DEFAULT
| SE_PRIVILEGE_ENABLED
;
961 Privileges
[i
++].Luid
= SeDebugPrivilege
;
963 Privileges
[i
].Attributes
= SE_PRIVILEGE_ENABLED_BY_DEFAULT
| SE_PRIVILEGE_ENABLED
;
964 Privileges
[i
++].Luid
= SeAuditPrivilege
;
966 Privileges
[i
].Attributes
= 0;
967 Privileges
[i
++].Luid
= SeSecurityPrivilege
;
969 Privileges
[i
].Attributes
= 0;
970 Privileges
[i
++].Luid
= SeSystemEnvironmentPrivilege
;
972 Privileges
[i
].Attributes
= SE_PRIVILEGE_ENABLED_BY_DEFAULT
| SE_PRIVILEGE_ENABLED
;
973 Privileges
[i
++].Luid
= SeChangeNotifyPrivilege
;
975 Privileges
[i
].Attributes
= 0;
976 Privileges
[i
++].Luid
= SeBackupPrivilege
;
978 Privileges
[i
].Attributes
= 0;
979 Privileges
[i
++].Luid
= SeRestorePrivilege
;
981 Privileges
[i
].Attributes
= 0;
982 Privileges
[i
++].Luid
= SeShutdownPrivilege
;
984 Privileges
[i
].Attributes
= 0;
985 Privileges
[i
++].Luid
= SeLoadDriverPrivilege
;
987 Privileges
[i
].Attributes
= SE_PRIVILEGE_ENABLED_BY_DEFAULT
| SE_PRIVILEGE_ENABLED
;
988 Privileges
[i
++].Luid
= SeProfileSingleProcessPrivilege
;
990 Privileges
[i
].Attributes
= 0;
991 Privileges
[i
++].Luid
= SeSystemtimePrivilege
;
994 /* Setup the object attributes */
995 InitializeObjectAttributes(&ObjectAttributes
, NULL
, 0, NULL
, NULL
);
996 ASSERT(SeSystemDefaultDacl
!= NULL
);
998 /* Create the token */
999 Status
= SepCreateToken((PHANDLE
)&Token
,
1005 &SeSystemAuthenticationId
,
1015 SeSystemDefaultDacl
,
1016 &SeSystemTokenSource
,
1018 ASSERT(Status
== STATUS_SUCCESS
);
1020 /* Return the token */
1024 /* PUBLIC FUNCTIONS ***********************************************************/
1031 SeFilterToken(IN PACCESS_TOKEN ExistingToken
,
1033 IN PTOKEN_GROUPS SidsToDisable OPTIONAL
,
1034 IN PTOKEN_PRIVILEGES PrivilegesToDelete OPTIONAL
,
1035 IN PTOKEN_GROUPS RestrictedSids OPTIONAL
,
1036 OUT PACCESS_TOKEN
* FilteredToken
)
1039 return STATUS_NOT_IMPLEMENTED
;
1047 SeQueryInformationToken(IN PACCESS_TOKEN Token
,
1048 IN TOKEN_INFORMATION_CLASS TokenInformationClass
,
1049 OUT PVOID
*TokenInformation
)
1052 return STATUS_NOT_IMPLEMENTED
;
1060 SeQuerySessionIdToken(IN PACCESS_TOKEN Token
,
1061 IN PULONG pSessionId
)
1063 *pSessionId
= ((PTOKEN
)Token
)->SessionId
;
1064 return STATUS_SUCCESS
;
1072 SeQueryAuthenticationIdToken(IN PACCESS_TOKEN Token
,
1077 *LogonId
= ((PTOKEN
)Token
)->AuthenticationId
;
1079 return STATUS_SUCCESS
;
1086 SECURITY_IMPERSONATION_LEVEL
1088 SeTokenImpersonationLevel(IN PACCESS_TOKEN Token
)
1092 return ((PTOKEN
)Token
)->ImpersonationLevel
;
1100 SeTokenType(IN PACCESS_TOKEN Token
)
1104 return ((PTOKEN
)Token
)->TokenType
;
1113 SeTokenIsAdmin(IN PACCESS_TOKEN Token
)
1117 return (((PTOKEN
)Token
)->TokenFlags
& TOKEN_WRITE_RESTRICTED
) != 0;
1125 SeTokenIsRestricted(IN PACCESS_TOKEN Token
)
1129 return (((PTOKEN
)Token
)->TokenFlags
& TOKEN_IS_RESTRICTED
) != 0;
1137 SeTokenIsWriteRestricted(IN PACCESS_TOKEN Token
)
1141 return (((PTOKEN
)Token
)->TokenFlags
& TOKEN_HAS_RESTORE_PRIVILEGE
) != 0;
1144 /* SYSTEM CALLS ***************************************************************/
1150 NtQueryInformationToken(IN HANDLE TokenHandle
,
1151 IN TOKEN_INFORMATION_CLASS TokenInformationClass
,
1152 OUT PVOID TokenInformation
,
1153 IN ULONG TokenInformationLength
,
1154 OUT PULONG ReturnLength
)
1162 ULONG RequiredLength
;
1163 KPROCESSOR_MODE PreviousMode
;
1168 PreviousMode
= ExGetPreviousMode();
1170 /* Check buffers and class validity */
1171 Status
= DefaultQueryInfoBufferCheck(TokenInformationClass
,
1172 SeTokenInformationClass
,
1173 sizeof(SeTokenInformationClass
) / sizeof(SeTokenInformationClass
[0]),
1175 TokenInformationLength
,
1179 if (!NT_SUCCESS(Status
))
1181 DPRINT("NtQueryInformationToken() failed, Status: 0x%x\n", Status
);
1185 Status
= ObReferenceObjectByHandle(TokenHandle
,
1186 (TokenInformationClass
== TokenSource
) ? TOKEN_QUERY_SOURCE
: TOKEN_QUERY
,
1191 if (NT_SUCCESS(Status
))
1193 switch (TokenInformationClass
)
1197 PTOKEN_USER tu
= (PTOKEN_USER
)TokenInformation
;
1199 DPRINT("NtQueryInformationToken(TokenUser)\n");
1200 RequiredLength
= sizeof(TOKEN_USER
) +
1201 RtlLengthSid(Token
->UserAndGroups
[0].Sid
);
1205 if (TokenInformationLength
>= RequiredLength
)
1207 Status
= RtlCopySidAndAttributesArray(1,
1208 &Token
->UserAndGroups
[0],
1209 RequiredLength
- sizeof(TOKEN_USER
),
1217 Status
= STATUS_BUFFER_TOO_SMALL
;
1220 if (ReturnLength
!= NULL
)
1222 *ReturnLength
= RequiredLength
;
1225 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1227 Status
= _SEH2_GetExceptionCode();
1236 PTOKEN_GROUPS tg
= (PTOKEN_GROUPS
)TokenInformation
;
1238 DPRINT("NtQueryInformationToken(TokenGroups)\n");
1239 RequiredLength
= sizeof(tg
->GroupCount
) +
1240 RtlLengthSidAndAttributes(Token
->UserAndGroupCount
- 1, &Token
->UserAndGroups
[1]);
1244 if (TokenInformationLength
>= RequiredLength
)
1246 ULONG SidLen
= RequiredLength
- sizeof(tg
->GroupCount
) -
1247 ((Token
->UserAndGroupCount
- 1) * sizeof(SID_AND_ATTRIBUTES
));
1248 PSID_AND_ATTRIBUTES Sid
= (PSID_AND_ATTRIBUTES
)((ULONG_PTR
)TokenInformation
+ sizeof(tg
->GroupCount
) +
1249 ((Token
->UserAndGroupCount
- 1) * sizeof(SID_AND_ATTRIBUTES
)));
1251 tg
->GroupCount
= Token
->UserAndGroupCount
- 1;
1252 Status
= RtlCopySidAndAttributesArray(Token
->UserAndGroupCount
- 1,
1253 &Token
->UserAndGroups
[1],
1262 Status
= STATUS_BUFFER_TOO_SMALL
;
1265 if (ReturnLength
!= NULL
)
1267 *ReturnLength
= RequiredLength
;
1270 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1272 Status
= _SEH2_GetExceptionCode();
1279 case TokenPrivileges
:
1281 PTOKEN_PRIVILEGES tp
= (PTOKEN_PRIVILEGES
)TokenInformation
;
1283 DPRINT("NtQueryInformationToken(TokenPrivileges)\n");
1284 RequiredLength
= sizeof(tp
->PrivilegeCount
) +
1285 (Token
->PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
));
1289 if (TokenInformationLength
>= RequiredLength
)
1291 tp
->PrivilegeCount
= Token
->PrivilegeCount
;
1292 RtlCopyLuidAndAttributesArray(Token
->PrivilegeCount
,
1294 &tp
->Privileges
[0]);
1298 Status
= STATUS_BUFFER_TOO_SMALL
;
1301 if (ReturnLength
!= NULL
)
1303 *ReturnLength
= RequiredLength
;
1306 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1308 Status
= _SEH2_GetExceptionCode();
1318 PTOKEN_OWNER to
= (PTOKEN_OWNER
)TokenInformation
;
1320 DPRINT("NtQueryInformationToken(TokenOwner)\n");
1321 SidLen
= RtlLengthSid(Token
->UserAndGroups
[Token
->DefaultOwnerIndex
].Sid
);
1322 RequiredLength
= sizeof(TOKEN_OWNER
) + SidLen
;
1326 if (TokenInformationLength
>= RequiredLength
)
1328 to
->Owner
= (PSID
)(to
+ 1);
1329 Status
= RtlCopySid(SidLen
,
1331 Token
->UserAndGroups
[Token
->DefaultOwnerIndex
].Sid
);
1335 Status
= STATUS_BUFFER_TOO_SMALL
;
1338 if (ReturnLength
!= NULL
)
1340 *ReturnLength
= RequiredLength
;
1343 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1345 Status
= _SEH2_GetExceptionCode();
1352 case TokenPrimaryGroup
:
1355 PTOKEN_PRIMARY_GROUP tpg
= (PTOKEN_PRIMARY_GROUP
)TokenInformation
;
1357 DPRINT("NtQueryInformationToken(TokenPrimaryGroup)\n");
1358 SidLen
= RtlLengthSid(Token
->PrimaryGroup
);
1359 RequiredLength
= sizeof(TOKEN_PRIMARY_GROUP
) + SidLen
;
1363 if (TokenInformationLength
>= RequiredLength
)
1365 tpg
->PrimaryGroup
= (PSID
)(tpg
+ 1);
1366 Status
= RtlCopySid(SidLen
,
1368 Token
->PrimaryGroup
);
1372 Status
= STATUS_BUFFER_TOO_SMALL
;
1375 if (ReturnLength
!= NULL
)
1377 *ReturnLength
= RequiredLength
;
1380 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1382 Status
= _SEH2_GetExceptionCode();
1389 case TokenDefaultDacl
:
1391 PTOKEN_DEFAULT_DACL tdd
= (PTOKEN_DEFAULT_DACL
)TokenInformation
;
1393 DPRINT("NtQueryInformationToken(TokenDefaultDacl)\n");
1394 RequiredLength
= sizeof(TOKEN_DEFAULT_DACL
);
1396 if (Token
->DefaultDacl
!= NULL
)
1398 RequiredLength
+= Token
->DefaultDacl
->AclSize
;
1403 if (TokenInformationLength
>= RequiredLength
)
1405 if (Token
->DefaultDacl
!= NULL
)
1407 tdd
->DefaultDacl
= (PACL
)(tdd
+ 1);
1408 RtlCopyMemory(tdd
->DefaultDacl
,
1410 Token
->DefaultDacl
->AclSize
);
1414 tdd
->DefaultDacl
= NULL
;
1419 Status
= STATUS_BUFFER_TOO_SMALL
;
1422 if (ReturnLength
!= NULL
)
1424 *ReturnLength
= RequiredLength
;
1427 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1429 Status
= _SEH2_GetExceptionCode();
1438 PTOKEN_SOURCE ts
= (PTOKEN_SOURCE
)TokenInformation
;
1440 DPRINT("NtQueryInformationToken(TokenSource)\n");
1441 RequiredLength
= sizeof(TOKEN_SOURCE
);
1445 if (TokenInformationLength
>= RequiredLength
)
1447 *ts
= Token
->TokenSource
;
1451 Status
= STATUS_BUFFER_TOO_SMALL
;
1454 if (ReturnLength
!= NULL
)
1456 *ReturnLength
= RequiredLength
;
1459 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1461 Status
= _SEH2_GetExceptionCode();
1470 PTOKEN_TYPE tt
= (PTOKEN_TYPE
)TokenInformation
;
1472 DPRINT("NtQueryInformationToken(TokenType)\n");
1473 RequiredLength
= sizeof(TOKEN_TYPE
);
1477 if (TokenInformationLength
>= RequiredLength
)
1479 *tt
= Token
->TokenType
;
1483 Status
= STATUS_BUFFER_TOO_SMALL
;
1486 if (ReturnLength
!= NULL
)
1488 *ReturnLength
= RequiredLength
;
1491 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1493 Status
= _SEH2_GetExceptionCode();
1500 case TokenImpersonationLevel
:
1502 PSECURITY_IMPERSONATION_LEVEL sil
= (PSECURITY_IMPERSONATION_LEVEL
)TokenInformation
;
1504 DPRINT("NtQueryInformationToken(TokenImpersonationLevel)\n");
1506 /* Fail if the token is not an impersonation token */
1507 if (Token
->TokenType
!= TokenImpersonation
)
1509 Status
= STATUS_INVALID_INFO_CLASS
;
1513 RequiredLength
= sizeof(SECURITY_IMPERSONATION_LEVEL
);
1517 if (TokenInformationLength
>= RequiredLength
)
1519 *sil
= Token
->ImpersonationLevel
;
1523 Status
= STATUS_BUFFER_TOO_SMALL
;
1526 if (ReturnLength
!= NULL
)
1528 *ReturnLength
= RequiredLength
;
1531 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1533 Status
= _SEH2_GetExceptionCode();
1540 case TokenStatistics
:
1542 PTOKEN_STATISTICS ts
= (PTOKEN_STATISTICS
)TokenInformation
;
1544 DPRINT("NtQueryInformationToken(TokenStatistics)\n");
1545 RequiredLength
= sizeof(TOKEN_STATISTICS
);
1549 if (TokenInformationLength
>= RequiredLength
)
1551 ts
->TokenId
= Token
->TokenId
;
1552 ts
->AuthenticationId
= Token
->AuthenticationId
;
1553 ts
->ExpirationTime
= Token
->ExpirationTime
;
1554 ts
->TokenType
= Token
->TokenType
;
1555 ts
->ImpersonationLevel
= Token
->ImpersonationLevel
;
1556 ts
->DynamicCharged
= Token
->DynamicCharged
;
1557 ts
->DynamicAvailable
= Token
->DynamicAvailable
;
1558 ts
->GroupCount
= Token
->UserAndGroupCount
- 1;
1559 ts
->PrivilegeCount
= Token
->PrivilegeCount
;
1560 ts
->ModifiedId
= Token
->ModifiedId
;
1564 Status
= STATUS_BUFFER_TOO_SMALL
;
1567 if (ReturnLength
!= NULL
)
1569 *ReturnLength
= RequiredLength
;
1572 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1574 Status
= _SEH2_GetExceptionCode();
1583 PTOKEN_ORIGIN to
= (PTOKEN_ORIGIN
)TokenInformation
;
1585 DPRINT("NtQueryInformationToken(TokenOrigin)\n");
1586 RequiredLength
= sizeof(TOKEN_ORIGIN
);
1590 if (TokenInformationLength
>= RequiredLength
)
1592 RtlCopyLuid(&to
->OriginatingLogonSession
,
1593 &Token
->AuthenticationId
);
1597 Status
= STATUS_BUFFER_TOO_SMALL
;
1600 if (ReturnLength
!= NULL
)
1602 *ReturnLength
= RequiredLength
;
1605 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1607 Status
= _SEH2_GetExceptionCode();
1614 case TokenGroupsAndPrivileges
:
1615 DPRINT1("NtQueryInformationToken(TokenGroupsAndPrivileges) not implemented\n");
1616 Status
= STATUS_NOT_IMPLEMENTED
;
1619 case TokenRestrictedSids
:
1621 PTOKEN_GROUPS tg
= (PTOKEN_GROUPS
)TokenInformation
;
1623 DPRINT("NtQueryInformationToken(TokenRestrictedSids)\n");
1624 RequiredLength
= sizeof(tg
->GroupCount
) +
1625 RtlLengthSidAndAttributes(Token
->RestrictedSidCount
, Token
->RestrictedSids
);
1629 if (TokenInformationLength
>= RequiredLength
)
1631 ULONG SidLen
= RequiredLength
- sizeof(tg
->GroupCount
) -
1632 (Token
->RestrictedSidCount
* sizeof(SID_AND_ATTRIBUTES
));
1633 PSID_AND_ATTRIBUTES Sid
= (PSID_AND_ATTRIBUTES
)((ULONG_PTR
)TokenInformation
+ sizeof(tg
->GroupCount
) +
1634 (Token
->RestrictedSidCount
* sizeof(SID_AND_ATTRIBUTES
)));
1636 tg
->GroupCount
= Token
->RestrictedSidCount
;
1637 Status
= RtlCopySidAndAttributesArray(Token
->RestrictedSidCount
,
1638 Token
->RestrictedSids
,
1647 Status
= STATUS_BUFFER_TOO_SMALL
;
1650 if (ReturnLength
!= NULL
)
1652 *ReturnLength
= RequiredLength
;
1655 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1657 Status
= _SEH2_GetExceptionCode();
1664 case TokenSandBoxInert
:
1665 DPRINT1("NtQueryInformationToken(TokenSandboxInert) not implemented\n");
1666 Status
= STATUS_NOT_IMPLEMENTED
;
1669 case TokenSessionId
:
1671 ULONG SessionId
= 0;
1673 DPRINT("NtQueryInformationToken(TokenSessionId)\n");
1675 Status
= SeQuerySessionIdToken(Token
,
1678 if (NT_SUCCESS(Status
))
1682 /* buffer size was already verified, no need to check here again */
1683 *(PULONG
)TokenInformation
= SessionId
;
1685 if (ReturnLength
!= NULL
)
1687 *ReturnLength
= sizeof(ULONG
);
1690 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1692 Status
= _SEH2_GetExceptionCode();
1701 DPRINT1("NtQueryInformationToken(%d) invalid information class\n", TokenInformationClass
);
1702 Status
= STATUS_INVALID_INFO_CLASS
;
1706 ObDereferenceObject(Token
);
1714 * NtSetTokenInformation: Partly implemented.
1716 * TokenOrigin, TokenDefaultDacl
1720 NtSetInformationToken(IN HANDLE TokenHandle
,
1721 IN TOKEN_INFORMATION_CLASS TokenInformationClass
,
1722 OUT PVOID TokenInformation
,
1723 IN ULONG TokenInformationLength
)
1726 KPROCESSOR_MODE PreviousMode
;
1727 ULONG NeededAccess
= TOKEN_ADJUST_DEFAULT
;
1732 PreviousMode
= ExGetPreviousMode();
1734 Status
= DefaultSetInfoBufferCheck(TokenInformationClass
,
1735 SeTokenInformationClass
,
1736 sizeof(SeTokenInformationClass
) / sizeof(SeTokenInformationClass
[0]),
1738 TokenInformationLength
,
1740 if (!NT_SUCCESS(Status
))
1742 /* Invalid buffers */
1743 DPRINT("NtSetInformationToken() failed, Status: 0x%x\n", Status
);
1747 if (TokenInformationClass
== TokenSessionId
)
1749 NeededAccess
|= TOKEN_ADJUST_SESSIONID
;
1752 Status
= ObReferenceObjectByHandle(TokenHandle
,
1758 if (NT_SUCCESS(Status
))
1760 switch (TokenInformationClass
)
1764 if (TokenInformationLength
>= sizeof(TOKEN_OWNER
))
1766 PTOKEN_OWNER to
= (PTOKEN_OWNER
)TokenInformation
;
1767 PSID InputSid
= NULL
, CapturedSid
;
1771 InputSid
= to
->Owner
;
1773 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1775 Status
= _SEH2_GetExceptionCode();
1780 Status
= SepCaptureSid(InputSid
,
1785 if (NT_SUCCESS(Status
))
1787 RtlCopySid(RtlLengthSid(CapturedSid
),
1788 Token
->UserAndGroups
[Token
->DefaultOwnerIndex
].Sid
,
1790 SepReleaseSid(CapturedSid
,
1797 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1802 case TokenPrimaryGroup
:
1804 if (TokenInformationLength
>= sizeof(TOKEN_PRIMARY_GROUP
))
1806 PTOKEN_PRIMARY_GROUP tpg
= (PTOKEN_PRIMARY_GROUP
)TokenInformation
;
1807 PSID InputSid
= NULL
, CapturedSid
;
1811 InputSid
= tpg
->PrimaryGroup
;
1813 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1815 Status
= _SEH2_GetExceptionCode();
1820 Status
= SepCaptureSid(InputSid
,
1825 if (NT_SUCCESS(Status
))
1827 RtlCopySid(RtlLengthSid(CapturedSid
),
1828 Token
->PrimaryGroup
,
1830 SepReleaseSid(CapturedSid
,
1837 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1842 case TokenDefaultDacl
:
1844 if (TokenInformationLength
>= sizeof(TOKEN_DEFAULT_DACL
))
1846 PTOKEN_DEFAULT_DACL tdd
= (PTOKEN_DEFAULT_DACL
)TokenInformation
;
1847 PACL InputAcl
= NULL
;
1851 InputAcl
= tdd
->DefaultDacl
;
1853 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1855 Status
= _SEH2_GetExceptionCode();
1860 if (InputAcl
!= NULL
)
1864 /* Capture and copy the dacl */
1865 Status
= SepCaptureAcl(InputAcl
,
1870 if (NT_SUCCESS(Status
))
1872 /* Free the previous dacl if present */
1873 if(Token
->DefaultDacl
!= NULL
)
1875 ExFreePoolWithTag(Token
->DefaultDacl
, TAG_TOKEN_ACL
);
1878 /* Set the new dacl */
1879 Token
->DefaultDacl
= CapturedAcl
;
1884 /* Clear and free the default dacl if present */
1885 if (Token
->DefaultDacl
!= NULL
)
1887 ExFreePoolWithTag(Token
->DefaultDacl
, TAG_TOKEN_ACL
);
1888 Token
->DefaultDacl
= NULL
;
1894 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1899 case TokenSessionId
:
1901 ULONG SessionId
= 0;
1905 /* Buffer size was already verified, no need to check here again */
1906 SessionId
= *(PULONG
)TokenInformation
;
1908 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1910 Status
= _SEH2_GetExceptionCode();
1915 if (!SeSinglePrivilegeCheck(SeTcbPrivilege
,
1918 Status
= STATUS_PRIVILEGE_NOT_HELD
;
1922 Token
->SessionId
= SessionId
;
1926 case TokenSessionReference
:
1928 ULONG SessionReference
;
1932 /* Buffer size was already verified, no need to check here again */
1933 SessionReference
= *(PULONG
)TokenInformation
;
1935 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1937 Status
= _SEH2_GetExceptionCode();
1942 if (!SeSinglePrivilegeCheck(SeTcbPrivilege
, PreviousMode
))
1944 Status
= STATUS_PRIVILEGE_NOT_HELD
;
1948 /* Check if it is 0 */
1949 if (SessionReference
== 0)
1951 /* Atomically set the flag in the token */
1952 RtlInterlockedSetBits(&Token
->TokenFlags
,
1953 TOKEN_SESSION_NOT_REFERENCED
);
1961 case TokenAuditPolicy
:
1963 PTOKEN_AUDIT_POLICY_INFORMATION PolicyInformation
=
1964 (PTOKEN_AUDIT_POLICY_INFORMATION
)TokenInformation
;
1965 SEP_AUDIT_POLICY AuditPolicy
;
1970 ProbeForRead(PolicyInformation
,
1971 FIELD_OFFSET(TOKEN_AUDIT_POLICY_INFORMATION
,
1972 Policies
[PolicyInformation
->PolicyCount
]),
1975 /* Loop all policies in the structure */
1976 for (i
= 0; i
< PolicyInformation
->PolicyCount
; i
++)
1978 /* Set the corresponding bits in the packed structure */
1979 switch (PolicyInformation
->Policies
[i
].Category
)
1981 case AuditCategorySystem
:
1982 AuditPolicy
.PolicyElements
.System
= PolicyInformation
->Policies
[i
].Value
;
1985 case AuditCategoryLogon
:
1986 AuditPolicy
.PolicyElements
.Logon
= PolicyInformation
->Policies
[i
].Value
;
1989 case AuditCategoryObjectAccess
:
1990 AuditPolicy
.PolicyElements
.ObjectAccess
= PolicyInformation
->Policies
[i
].Value
;
1993 case AuditCategoryPrivilegeUse
:
1994 AuditPolicy
.PolicyElements
.PrivilegeUse
= PolicyInformation
->Policies
[i
].Value
;
1997 case AuditCategoryDetailedTracking
:
1998 AuditPolicy
.PolicyElements
.DetailedTracking
= PolicyInformation
->Policies
[i
].Value
;
2001 case AuditCategoryPolicyChange
:
2002 AuditPolicy
.PolicyElements
.PolicyChange
= PolicyInformation
->Policies
[i
].Value
;
2005 case AuditCategoryAccountManagement
:
2006 AuditPolicy
.PolicyElements
.AccountManagement
= PolicyInformation
->Policies
[i
].Value
;
2009 case AuditCategoryDirectoryServiceAccess
:
2010 AuditPolicy
.PolicyElements
.DirectoryServiceAccess
= PolicyInformation
->Policies
[i
].Value
;
2013 case AuditCategoryAccountLogon
:
2014 AuditPolicy
.PolicyElements
.AccountLogon
= PolicyInformation
->Policies
[i
].Value
;
2019 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2021 Status
= _SEH2_GetExceptionCode();
2026 if (!SeSinglePrivilegeCheck(SeTcbPrivilege
,
2029 Status
= STATUS_PRIVILEGE_NOT_HELD
;
2033 /* Lock the token */
2034 SepAcquireTokenLockExclusive(Token
);
2036 /* Set the new audit policy */
2037 Token
->AuditPolicy
= AuditPolicy
;
2039 /* Unlock the token */
2040 SepReleaseTokenLock(Token
);
2047 TOKEN_ORIGIN TokenOrigin
;
2051 /* Copy the token origin */
2052 TokenOrigin
= *(PTOKEN_ORIGIN
)TokenInformation
;
2054 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2056 Status
= _SEH2_GetExceptionCode();
2061 /* Check for TCB privilege */
2062 if (!SeSinglePrivilegeCheck(SeTcbPrivilege
, PreviousMode
))
2064 Status
= STATUS_PRIVILEGE_NOT_HELD
;
2068 /* Lock the token */
2069 SepAcquireTokenLockExclusive(Token
);
2071 /* Check if there is no token origin set yet */
2072 if ((Token
->OriginatingLogonSession
.LowPart
== 0) &&
2073 (Token
->OriginatingLogonSession
.HighPart
== 0))
2075 /* Set the token origin */
2076 Token
->OriginatingLogonSession
=
2077 TokenOrigin
.OriginatingLogonSession
;
2080 /* Unlock the token */
2081 SepReleaseTokenLock(Token
);
2088 DPRINT1("Invalid TokenInformationClass: 0x%lx\n",
2089 TokenInformationClass
);
2090 Status
= STATUS_INVALID_INFO_CLASS
;
2095 ObDereferenceObject(Token
);
2098 if (!NT_SUCCESS(Status
))
2100 DPRINT1("NtSetInformationToken failed with Status 0x%lx\n", Status
);
2110 * NOTE: Some sources claim 4th param is ImpersonationLevel, but on W2K
2111 * this is certainly NOT true, thou i can't say for sure that EffectiveOnly
2112 * is correct either. -Gunnar
2113 * This is true. EffectiveOnly overrides SQOS.EffectiveOnly. - IAI
2116 NtDuplicateToken(IN HANDLE ExistingTokenHandle
,
2117 IN ACCESS_MASK DesiredAccess
,
2118 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
2119 IN BOOLEAN EffectiveOnly
,
2120 IN TOKEN_TYPE TokenType
,
2121 OUT PHANDLE NewTokenHandle
)
2123 KPROCESSOR_MODE PreviousMode
;
2127 PSECURITY_QUALITY_OF_SERVICE CapturedSecurityQualityOfService
;
2129 OBJECT_HANDLE_INFORMATION HandleInformation
;
2134 if (TokenType
!= TokenImpersonation
&&
2135 TokenType
!= TokenPrimary
)
2136 return STATUS_INVALID_PARAMETER
;
2138 PreviousMode
= KeGetPreviousMode();
2140 if (PreviousMode
!= KernelMode
)
2144 ProbeForWriteHandle(NewTokenHandle
);
2146 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2148 /* Return the exception code */
2149 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2154 Status
= SepCaptureSecurityQualityOfService(ObjectAttributes
,
2158 &CapturedSecurityQualityOfService
,
2160 if (!NT_SUCCESS(Status
))
2162 DPRINT1("NtDuplicateToken() failed to capture QoS! Status: 0x%x\n", Status
);
2166 Status
= ObReferenceObjectByHandle(ExistingTokenHandle
,
2171 &HandleInformation
);
2172 if (!NT_SUCCESS(Status
))
2174 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService
,
2181 * Fail, if the original token is an impersonation token and the caller
2182 * tries to raise the impersonation level of the new token above the
2183 * impersonation level of the original token.
2185 if (Token
->TokenType
== TokenImpersonation
)
2188 CapturedSecurityQualityOfService
->ImpersonationLevel
>Token
->ImpersonationLevel
)
2190 ObDereferenceObject(Token
);
2191 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService
,
2194 return STATUS_BAD_IMPERSONATION_LEVEL
;
2199 * Fail, if a primary token is to be created from an impersonation token
2200 * and and the impersonation level of the impersonation token is below SecurityImpersonation.
2202 if (Token
->TokenType
== TokenImpersonation
&&
2203 TokenType
== TokenPrimary
&&
2204 Token
->ImpersonationLevel
< SecurityImpersonation
)
2206 ObDereferenceObject(Token
);
2207 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService
,
2210 return STATUS_BAD_IMPERSONATION_LEVEL
;
2213 Status
= SepDuplicateToken(Token
,
2217 (QoSPresent
? CapturedSecurityQualityOfService
->ImpersonationLevel
: SecurityAnonymous
),
2221 ObDereferenceObject(Token
);
2223 if (NT_SUCCESS(Status
))
2225 Status
= ObInsertObject((PVOID
)NewToken
,
2227 (DesiredAccess
? DesiredAccess
: HandleInformation
.GrantedAccess
),
2231 if (NT_SUCCESS(Status
))
2235 *NewTokenHandle
= hToken
;
2237 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2239 Status
= _SEH2_GetExceptionCode();
2245 /* Free the captured structure */
2246 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService
,
2254 NtAdjustGroupsToken(IN HANDLE TokenHandle
,
2255 IN BOOLEAN ResetToDefault
,
2256 IN PTOKEN_GROUPS NewState
,
2257 IN ULONG BufferLength
,
2258 OUT PTOKEN_GROUPS PreviousState OPTIONAL
,
2259 OUT PULONG ReturnLength
)
2262 return(STATUS_NOT_IMPLEMENTED
);
2268 SepAdjustPrivileges(
2269 _Inout_ PTOKEN Token
,
2270 _In_ BOOLEAN DisableAllPrivileges
,
2271 _In_opt_ PLUID_AND_ATTRIBUTES NewState
,
2272 _In_ ULONG NewStateCount
,
2273 _Out_opt_ PTOKEN_PRIVILEGES PreviousState
,
2274 _In_ BOOLEAN ApplyChanges
,
2275 _Out_ PULONG ChangedPrivileges
)
2277 ULONG i
, j
, PrivilegeCount
, ChangeCount
, NewAttributes
;
2279 /* Count the found privileges and those that need to be changed */
2283 /* Loop all privileges in the token */
2284 for (i
= 0; i
< Token
->PrivilegeCount
; i
++)
2286 /* Shall all of them be disabled? */
2287 if (DisableAllPrivileges
)
2289 /* The new attributes are the old ones, but disabled */
2290 NewAttributes
= Token
->Privileges
[i
].Attributes
& ~SE_PRIVILEGE_ENABLED
;
2294 /* Otherwise loop all provided privileges */
2295 for (j
= 0; j
< NewStateCount
; j
++)
2297 /* Check if this is the LUID we are looking for */
2298 if (RtlEqualLuid(&Token
->Privileges
[i
].Luid
, &NewState
[j
].Luid
))
2300 DPRINT("Found privilege\n");
2302 /* Copy SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_REMOVED */
2303 NewAttributes
= NewState
[j
].Attributes
;
2304 NewAttributes
&= (SE_PRIVILEGE_ENABLED
| SE_PRIVILEGE_REMOVED
);
2305 NewAttributes
|= Token
->Privileges
[i
].Attributes
& ~SE_PRIVILEGE_ENABLED
;
2312 /* Check if we didn't find the privilege */
2313 if (j
== NewStateCount
)
2315 /* Continue with the token's next privilege */
2320 /* We found a privilege, count it */
2323 /* Does the privilege need to be changed? */
2324 if (Token
->Privileges
[i
].Attributes
!= NewAttributes
)
2326 /* Does the caller want the old privileges? */
2327 if (PreviousState
!= NULL
)
2329 /* Copy the old privilege */
2330 PreviousState
->Privileges
[ChangeCount
] = Token
->Privileges
[i
];
2333 /* Does the caller want to apply the changes? */
2336 /* Shall we remove the privilege? */
2337 if (NewAttributes
& SE_PRIVILEGE_REMOVED
)
2339 /* Set the token as disabled and update flags for it */
2340 Token
->Privileges
[i
].Attributes
&= ~SE_PRIVILEGE_ENABLED
;
2341 SepUpdateSinglePrivilegeFlagToken(Token
, i
);
2343 /* Remove the privilege */
2344 SepRemovePrivilegeToken(Token
, i
);
2346 /* Fix the running index */
2349 /* Continue with next */
2353 /* Set the new attributes and update flags */
2354 Token
->Privileges
[i
].Attributes
= NewAttributes
;
2355 SepUpdateSinglePrivilegeFlagToken(Token
, i
);
2358 /* Increment the change count */
2363 /* Set the number of saved privileges */
2364 if (PreviousState
!= NULL
)
2365 PreviousState
->PrivilegeCount
= ChangeCount
;
2367 /* Return the number of changed privileges */
2368 *ChangedPrivileges
= ChangeCount
;
2370 /* Check if we missed some */
2371 if (!DisableAllPrivileges
&& (PrivilegeCount
< NewStateCount
))
2373 return STATUS_NOT_ALL_ASSIGNED
;
2376 return STATUS_SUCCESS
;
2383 _Must_inspect_result_
2387 NtAdjustPrivilegesToken(
2388 _In_ HANDLE TokenHandle
,
2389 _In_ BOOLEAN DisableAllPrivileges
,
2390 _In_opt_ PTOKEN_PRIVILEGES NewState
,
2391 _In_ ULONG BufferLength
,
2392 _Out_writes_bytes_to_opt_(BufferLength
,*ReturnLength
)
2393 PTOKEN_PRIVILEGES PreviousState
,
2394 _When_(PreviousState
!=NULL
, _Out_
) PULONG ReturnLength
)
2396 PLUID_AND_ATTRIBUTES CapturedPrivileges
= NULL
;
2397 KPROCESSOR_MODE PreviousMode
;
2398 ULONG CapturedCount
= 0;
2399 ULONG CapturedLength
= 0;
2400 ULONG NewStateSize
= 0;
2402 ULONG RequiredLength
;
2407 DPRINT("NtAdjustPrivilegesToken() called\n");
2409 /* Fail, if we do not disable all privileges but NewState is NULL */
2410 if (DisableAllPrivileges
== FALSE
&& NewState
== NULL
)
2411 return STATUS_INVALID_PARAMETER
;
2413 PreviousMode
= KeGetPreviousMode ();
2414 if (PreviousMode
!= KernelMode
)
2418 /* Probe NewState */
2419 if (DisableAllPrivileges
== FALSE
)
2421 /* First probe the header */
2422 ProbeForRead(NewState
, sizeof(TOKEN_PRIVILEGES
), sizeof(ULONG
));
2424 CapturedCount
= NewState
->PrivilegeCount
;
2425 NewStateSize
= FIELD_OFFSET(TOKEN_PRIVILEGES
, Privileges
[CapturedCount
]);
2427 ProbeForRead(NewState
, NewStateSize
, sizeof(ULONG
));
2430 /* Probe PreviousState and ReturnLength */
2431 if (PreviousState
!= NULL
)
2433 ProbeForWrite(PreviousState
, BufferLength
, sizeof(ULONG
));
2434 ProbeForWrite(ReturnLength
, sizeof(ULONG
), sizeof(ULONG
));
2437 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2439 /* Return the exception code */
2440 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2446 /* This is kernel mode, we trust the caller */
2447 if (DisableAllPrivileges
== FALSE
)
2448 CapturedCount
= NewState
->PrivilegeCount
;
2451 /* Do we need to capture the new state? */
2452 if (DisableAllPrivileges
== FALSE
)
2456 /* Capture the new state array of privileges */
2457 Status
= SeCaptureLuidAndAttributesArray(NewState
->Privileges
,
2464 &CapturedPrivileges
,
2467 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2469 /* Return the exception code */
2470 Status
= _SEH2_GetExceptionCode();
2474 if (!NT_SUCCESS(Status
))
2478 /* Reference the token */
2479 Status
= ObReferenceObjectByHandle(TokenHandle
,
2480 TOKEN_ADJUST_PRIVILEGES
| (PreviousState
!= NULL
? TOKEN_QUERY
: 0),
2485 if (!NT_SUCCESS(Status
))
2487 DPRINT1("Failed to reference token (Status %lx)\n", Status
);
2489 /* Release the captured privileges */
2490 if (CapturedPrivileges
!= NULL
)
2491 SeReleaseLuidAndAttributesArray(CapturedPrivileges
,
2498 /* Lock the token */
2499 ExEnterCriticalRegionAndAcquireResourceExclusive(Token
->TokenLock
);
2501 /* Count the privileges that need to be changed, do not apply them yet */
2502 Status
= SepAdjustPrivileges(Token
,
2503 DisableAllPrivileges
,
2510 /* Check if the caller asked for the previous state */
2511 if (PreviousState
!= NULL
)
2513 /* Calculate the required length */
2514 RequiredLength
= FIELD_OFFSET(TOKEN_PRIVILEGES
, Privileges
[ChangeCount
]);
2516 /* Try to return the required buffer length */
2519 *ReturnLength
= RequiredLength
;
2521 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2523 /* Do cleanup and return the exception code */
2524 Status
= _SEH2_GetExceptionCode();
2529 /* Fail, if the buffer length is smaller than the required length */
2530 if (BufferLength
< RequiredLength
)
2532 Status
= STATUS_BUFFER_TOO_SMALL
;
2537 /* Now enter SEH, since we might return the old privileges */
2540 /* This time apply the changes */
2541 Status
= SepAdjustPrivileges(Token
,
2542 DisableAllPrivileges
,
2549 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2551 /* Do cleanup and return the exception code */
2552 Status
= _SEH2_GetExceptionCode();
2558 /* Unlock and dereference the token */
2559 ExReleaseResourceAndLeaveCriticalRegion(Token
->TokenLock
);
2560 ObDereferenceObject(Token
);
2562 /* Release the captured privileges */
2563 if (CapturedPrivileges
!= NULL
)
2564 SeReleaseLuidAndAttributesArray(CapturedPrivileges
,
2568 DPRINT ("NtAdjustPrivilegesToken() done\n");
2575 _Out_ PHANDLE TokenHandle
,
2576 _In_ ACCESS_MASK DesiredAccess
,
2577 _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes
,
2578 _In_ TOKEN_TYPE TokenType
,
2579 _In_ PLUID AuthenticationId
,
2580 _In_ PLARGE_INTEGER ExpirationTime
,
2581 _In_ PTOKEN_USER TokenUser
,
2582 _In_ PTOKEN_GROUPS TokenGroups
,
2583 _In_ PTOKEN_PRIVILEGES TokenPrivileges
,
2584 _In_opt_ PTOKEN_OWNER TokenOwner
,
2585 _In_ PTOKEN_PRIMARY_GROUP TokenPrimaryGroup
,
2586 _In_opt_ PTOKEN_DEFAULT_DACL TokenDefaultDacl
,
2587 _In_ PTOKEN_SOURCE TokenSource
)
2590 KPROCESSOR_MODE PreviousMode
;
2591 ULONG PrivilegeCount
, GroupCount
;
2592 PSID OwnerSid
, PrimaryGroupSid
;
2594 LARGE_INTEGER LocalExpirationTime
= {{0, 0}};
2595 LUID LocalAuthenticationId
;
2596 TOKEN_SOURCE LocalTokenSource
;
2597 SECURITY_QUALITY_OF_SERVICE LocalSecurityQos
;
2598 PLUID_AND_ATTRIBUTES CapturedPrivileges
= NULL
;
2599 PSID_AND_ATTRIBUTES CapturedUser
= NULL
;
2600 PSID_AND_ATTRIBUTES CapturedGroups
= NULL
;
2601 PSID CapturedOwnerSid
= NULL
;
2602 PSID CapturedPrimaryGroupSid
= NULL
;
2603 PACL CapturedDefaultDacl
= NULL
;
2604 ULONG PrivilegesLength
, UserLength
, GroupsLength
;
2609 PreviousMode
= ExGetPreviousMode();
2611 if (PreviousMode
!= KernelMode
)
2615 ProbeForWriteHandle(TokenHandle
);
2617 if (ObjectAttributes
!= NULL
)
2619 ProbeForRead(ObjectAttributes
,
2620 sizeof(OBJECT_ATTRIBUTES
),
2622 LocalSecurityQos
= *(SECURITY_QUALITY_OF_SERVICE
*)ObjectAttributes
->SecurityQualityOfService
;
2625 ProbeForRead(AuthenticationId
,
2628 LocalAuthenticationId
= *AuthenticationId
;
2630 LocalExpirationTime
= ProbeForReadLargeInteger(ExpirationTime
);
2632 ProbeForRead(TokenUser
,
2636 ProbeForRead(TokenGroups
,
2637 sizeof(TOKEN_GROUPS
),
2639 GroupCount
= TokenGroups
->GroupCount
;
2641 ProbeForRead(TokenPrivileges
,
2642 sizeof(TOKEN_PRIVILEGES
),
2644 PrivilegeCount
= TokenPrivileges
->PrivilegeCount
;
2646 if (TokenOwner
!= NULL
)
2648 ProbeForRead(TokenOwner
,
2649 sizeof(TOKEN_OWNER
),
2651 OwnerSid
= TokenOwner
->Owner
;
2658 ProbeForRead(TokenPrimaryGroup
,
2659 sizeof(TOKEN_PRIMARY_GROUP
),
2661 PrimaryGroupSid
= TokenPrimaryGroup
->PrimaryGroup
;
2663 if (TokenDefaultDacl
!= NULL
)
2665 ProbeForRead(TokenDefaultDacl
,
2666 sizeof(TOKEN_DEFAULT_DACL
),
2668 DefaultDacl
= TokenDefaultDacl
->DefaultDacl
;
2675 ProbeForRead(TokenSource
,
2676 sizeof(TOKEN_SOURCE
),
2678 LocalTokenSource
= *TokenSource
;
2680 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2682 /* Return the exception code */
2683 return _SEH2_GetExceptionCode();
2689 if (ObjectAttributes
!= NULL
)
2690 LocalSecurityQos
= *(SECURITY_QUALITY_OF_SERVICE
*)ObjectAttributes
->SecurityQualityOfService
;
2691 LocalAuthenticationId
= *AuthenticationId
;
2692 LocalExpirationTime
= *ExpirationTime
;
2693 GroupCount
= TokenGroups
->GroupCount
;
2694 PrivilegeCount
= TokenPrivileges
->PrivilegeCount
;
2695 OwnerSid
= TokenOwner
? TokenOwner
->Owner
: NULL
;
2696 PrimaryGroupSid
= TokenPrimaryGroup
->PrimaryGroup
;
2697 DefaultDacl
= TokenDefaultDacl
? TokenDefaultDacl
->DefaultDacl
: NULL
;
2698 LocalTokenSource
= *TokenSource
;
2701 /* Check token type */
2702 if ((TokenType
< TokenPrimary
) ||
2703 (TokenType
> TokenImpersonation
))
2705 return STATUS_BAD_TOKEN_TYPE
;
2708 /* Capture the user SID and attributes */
2709 Status
= SeCaptureSidAndAttributesArray(&TokenUser
->User
,
2718 if (!NT_SUCCESS(Status
))
2723 /* Capture the groups SID and attributes array */
2724 Status
= SeCaptureSidAndAttributesArray(&TokenGroups
->Groups
[0],
2733 if (!NT_SUCCESS(Status
))
2738 /* Capture privileges */
2739 Status
= SeCaptureLuidAndAttributesArray(&TokenPrivileges
->Privileges
[0],
2746 &CapturedPrivileges
,
2748 if (!NT_SUCCESS(Status
))
2753 /* Capture the token owner SID */
2754 if (TokenOwner
!= NULL
)
2756 Status
= SepCaptureSid(OwnerSid
,
2761 if (!NT_SUCCESS(Status
))
2767 /* Capture the token primary group SID */
2768 Status
= SepCaptureSid(PrimaryGroupSid
,
2772 &CapturedPrimaryGroupSid
);
2773 if (!NT_SUCCESS(Status
))
2778 /* Capture DefaultDacl */
2779 if (DefaultDacl
!= NULL
)
2781 Status
= SepCaptureAcl(DefaultDacl
,
2785 &CapturedDefaultDacl
);
2788 /* Call the internal function */
2789 Status
= SepCreateToken(&hToken
,
2794 LocalSecurityQos
.ImpersonationLevel
,
2795 &LocalAuthenticationId
,
2796 &LocalExpirationTime
,
2800 0, // FIXME: Should capture
2804 CapturedPrimaryGroupSid
,
2805 CapturedDefaultDacl
,
2808 if (NT_SUCCESS(Status
))
2812 *TokenHandle
= hToken
;
2814 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2816 Status
= _SEH2_GetExceptionCode();
2823 /* Release what we captured */
2824 SeReleaseSidAndAttributesArray(CapturedUser
, PreviousMode
, FALSE
);
2825 SeReleaseSidAndAttributesArray(CapturedGroups
, PreviousMode
, FALSE
);
2826 SeReleaseLuidAndAttributesArray(CapturedPrivileges
, PreviousMode
, FALSE
);
2827 SepReleaseSid(CapturedOwnerSid
, PreviousMode
, FALSE
);
2828 SepReleaseSid(CapturedPrimaryGroupSid
, PreviousMode
, FALSE
);
2829 SepReleaseAcl(CapturedDefaultDacl
, PreviousMode
, FALSE
);
2839 NtOpenThreadTokenEx(IN HANDLE ThreadHandle
,
2840 IN ACCESS_MASK DesiredAccess
,
2841 IN BOOLEAN OpenAsSelf
,
2842 IN ULONG HandleAttributes
,
2843 OUT PHANDLE TokenHandle
)
2845 PETHREAD Thread
, NewThread
;
2847 PTOKEN Token
, NewToken
= NULL
, PrimaryToken
;
2848 BOOLEAN CopyOnOpen
, EffectiveOnly
;
2849 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
;
2850 SE_IMPERSONATION_STATE ImpersonationState
;
2851 OBJECT_ATTRIBUTES ObjectAttributes
;
2852 SECURITY_DESCRIPTOR SecurityDescriptor
;
2854 KPROCESSOR_MODE PreviousMode
;
2856 BOOLEAN RestoreImpersonation
= FALSE
;
2860 PreviousMode
= ExGetPreviousMode();
2862 if (PreviousMode
!= KernelMode
)
2866 ProbeForWriteHandle(TokenHandle
);
2868 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2870 /* Return the exception code */
2871 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2877 * At first open the thread token for information access and verify
2878 * that the token associated with thread is valid.
2881 Status
= ObReferenceObjectByHandle(ThreadHandle
, THREAD_QUERY_INFORMATION
,
2882 PsThreadType
, PreviousMode
, (PVOID
*)&Thread
,
2884 if (!NT_SUCCESS(Status
))
2889 Token
= PsReferenceImpersonationToken(Thread
, &CopyOnOpen
, &EffectiveOnly
,
2890 &ImpersonationLevel
);
2893 ObDereferenceObject(Thread
);
2894 return STATUS_NO_TOKEN
;
2897 if (ImpersonationLevel
== SecurityAnonymous
)
2899 PsDereferenceImpersonationToken(Token
);
2900 ObDereferenceObject(Thread
);
2901 return STATUS_CANT_OPEN_ANONYMOUS
;
2905 * Revert to self if OpenAsSelf is specified.
2910 RestoreImpersonation
= PsDisableImpersonation(PsGetCurrentThread(),
2911 &ImpersonationState
);
2916 Status
= ObReferenceObjectByHandle(ThreadHandle
, THREAD_ALL_ACCESS
,
2917 PsThreadType
, KernelMode
,
2918 (PVOID
*)&NewThread
, NULL
);
2919 if (NT_SUCCESS(Status
))
2921 PrimaryToken
= PsReferencePrimaryToken(NewThread
->ThreadsProcess
);
2923 Status
= SepCreateImpersonationTokenDacl(Token
, PrimaryToken
, &Dacl
);
2925 ObFastDereferenceObject(&NewThread
->ThreadsProcess
->Token
, PrimaryToken
);
2927 if (NT_SUCCESS(Status
))
2931 RtlCreateSecurityDescriptor(&SecurityDescriptor
,
2932 SECURITY_DESCRIPTOR_REVISION
);
2933 RtlSetDaclSecurityDescriptor(&SecurityDescriptor
, TRUE
, Dacl
,
2937 InitializeObjectAttributes(&ObjectAttributes
, NULL
, HandleAttributes
,
2938 NULL
, Dacl
? &SecurityDescriptor
: NULL
);
2941 Status
= SepDuplicateToken(Token
, &ObjectAttributes
, EffectiveOnly
,
2942 TokenImpersonation
, ImpersonationLevel
,
2943 KernelMode
, &NewToken
);
2944 if (NT_SUCCESS(Status
))
2946 ObReferenceObject(NewToken
);
2947 Status
= ObInsertObject(NewToken
, NULL
, DesiredAccess
, 0, NULL
,
2955 Status
= ObOpenObjectByPointer(Token
, HandleAttributes
,
2956 NULL
, DesiredAccess
, SeTokenObjectType
,
2957 PreviousMode
, &hToken
);
2960 if (Dacl
) ExFreePoolWithTag(Dacl
, TAG_TOKEN_ACL
);
2962 if (RestoreImpersonation
)
2964 PsRestoreImpersonation(PsGetCurrentThread(), &ImpersonationState
);
2967 ObDereferenceObject(Token
);
2969 if (NT_SUCCESS(Status
) && CopyOnOpen
)
2971 PsImpersonateClient(Thread
, NewToken
, FALSE
, EffectiveOnly
, ImpersonationLevel
);
2974 if (NewToken
) ObDereferenceObject(NewToken
);
2976 if (CopyOnOpen
&& NewThread
) ObDereferenceObject(NewThread
);
2978 if (NT_SUCCESS(Status
))
2982 *TokenHandle
= hToken
;
2984 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2986 Status
= _SEH2_GetExceptionCode();
2998 NtOpenThreadToken(IN HANDLE ThreadHandle
,
2999 IN ACCESS_MASK DesiredAccess
,
3000 IN BOOLEAN OpenAsSelf
,
3001 OUT PHANDLE TokenHandle
)
3003 return NtOpenThreadTokenEx(ThreadHandle
, DesiredAccess
, OpenAsSelf
, 0,
3014 NtCompareTokens(IN HANDLE FirstTokenHandle
,
3015 IN HANDLE SecondTokenHandle
,
3018 KPROCESSOR_MODE PreviousMode
;
3019 PTOKEN FirstToken
, SecondToken
;
3025 PreviousMode
= ExGetPreviousMode();
3027 if (PreviousMode
!= KernelMode
)
3031 ProbeForWriteBoolean(Equal
);
3033 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3035 /* Return the exception code */
3036 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3041 Status
= ObReferenceObjectByHandle(FirstTokenHandle
,
3045 (PVOID
*)&FirstToken
,
3047 if (!NT_SUCCESS(Status
))
3050 Status
= ObReferenceObjectByHandle(SecondTokenHandle
,
3054 (PVOID
*)&SecondToken
,
3056 if (!NT_SUCCESS(Status
))
3058 ObDereferenceObject(FirstToken
);
3062 if (FirstToken
!= SecondToken
)
3064 Status
= SepCompareTokens(FirstToken
,
3071 ObDereferenceObject(FirstToken
);
3072 ObDereferenceObject(SecondToken
);
3074 if (NT_SUCCESS(Status
))
3080 _SEH2_EXCEPT(ExSystemExceptionFilter())
3082 Status
= _SEH2_GetExceptionCode();
3092 NtFilterToken(IN HANDLE ExistingTokenHandle
,
3094 IN PTOKEN_GROUPS SidsToDisable OPTIONAL
,
3095 IN PTOKEN_PRIVILEGES PrivilegesToDelete OPTIONAL
,
3096 IN PTOKEN_GROUPS RestrictedSids OPTIONAL
,
3097 OUT PHANDLE NewTokenHandle
)
3100 return STATUS_NOT_IMPLEMENTED
;
3108 NtImpersonateAnonymousToken(IN HANDLE Thread
)
3111 return STATUS_NOT_IMPLEMENTED
;