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 */
111 DPRINT1("FIXME: Pretending tokens are equal!\n");
116 return STATUS_SUCCESS
;
121 SepUpdateSinglePrivilegeFlagToken(
122 _Inout_ PTOKEN Token
,
126 NT_ASSERT(Index
< Token
->PrivilegeCount
);
128 /* The high part of all values we are interested in is 0 */
129 if (Token
->Privileges
[Index
].Luid
.HighPart
!= 0)
134 /* Check for certain privileges to update flags */
135 if (Token
->Privileges
[Index
].Luid
.LowPart
== SE_CHANGE_NOTIFY_PRIVILEGE
)
137 TokenFlag
= TOKEN_HAS_TRAVERSE_PRIVILEGE
;
139 else if (Token
->Privileges
[Index
].Luid
.LowPart
== SE_BACKUP_PRIVILEGE
)
141 TokenFlag
= TOKEN_HAS_BACKUP_PRIVILEGE
;
143 else if (Token
->Privileges
[Index
].Luid
.LowPart
== SE_RESTORE_PRIVILEGE
)
145 TokenFlag
= TOKEN_HAS_RESTORE_PRIVILEGE
;
147 else if (Token
->Privileges
[Index
].Luid
.LowPart
== SE_IMPERSONATE_PRIVILEGE
)
149 TokenFlag
= TOKEN_HAS_IMPERSONATE_PRIVILEGE
;
157 /* Check if the specified privilege is enabled */
158 if (Token
->Privileges
[Index
].Attributes
& SE_PRIVILEGE_ENABLED
)
160 /* It is enabled, so set the flag */
161 Token
->TokenFlags
|= TokenFlag
;
165 /* Is is disabled, so remove the flag */
166 Token
->TokenFlags
&= ~TokenFlag
;
172 SepUpdatePrivilegeFlagsToken(
173 _Inout_ PTOKEN Token
)
177 /* Loop all privileges */
178 for (i
= 0; i
< Token
->PrivilegeCount
; i
++)
180 /* Updates the flags dor this privilege */
181 SepUpdateSinglePrivilegeFlagToken(Token
, i
);
187 SepRemovePrivilegeToken(
188 _Inout_ PTOKEN Token
,
192 NT_ASSERT(Index
< Token
->PrivilegeCount
);
194 /* Calculate the number of trailing privileges */
195 MoveCount
= Token
->PrivilegeCount
- Index
- 1;
198 /* Move them one location ahead */
199 RtlMoveMemory(&Token
->Privileges
[Index
],
200 &Token
->Privileges
[Index
+ 1],
201 MoveCount
* sizeof(LUID_AND_ATTRIBUTES
));
204 /* Update privilege count */
205 Token
->PrivilegeCount
--;
210 SepFreeProxyData(PVOID ProxyData
)
217 SepCopyProxyData(PVOID
* Dest
,
221 return STATUS_NOT_IMPLEMENTED
;
226 SeExchangePrimaryToken(PEPROCESS Process
,
227 PACCESS_TOKEN NewTokenP
,
228 PACCESS_TOKEN
* OldTokenP
)
231 PTOKEN NewToken
= (PTOKEN
)NewTokenP
;
235 if (NewToken
->TokenType
!= TokenPrimary
) return(STATUS_BAD_TOKEN_TYPE
);
236 if (NewToken
->TokenInUse
)
241 /* Maybe we're trying to set the same token */
242 OldToken
= PsReferencePrimaryToken(Process
);
243 if (OldToken
== NewToken
)
246 *OldTokenP
= OldToken
;
247 return STATUS_SUCCESS
;
250 Status
= SepCompareTokens(OldToken
, NewToken
, &IsEqual
);
251 if (!NT_SUCCESS(Status
))
254 PsDereferencePrimaryToken(OldToken
);
261 PsDereferencePrimaryToken(OldToken
);
262 return STATUS_TOKEN_ALREADY_IN_USE
;
264 /* Silently return STATUS_SUCCESS but do not set the new token,
265 * as it's already in use elsewhere. */
266 *OldTokenP
= OldToken
;
267 return STATUS_SUCCESS
;
270 /* Mark new token in use */
271 NewToken
->TokenInUse
= 1;
273 /* Reference the New Token */
274 ObReferenceObject(NewToken
);
276 /* Replace the old with the new */
277 OldToken
= ObFastReplaceObject(&Process
->Token
, NewToken
);
279 /* Mark the Old Token as free */
280 OldToken
->TokenInUse
= 0;
282 *OldTokenP
= (PACCESS_TOKEN
)OldToken
;
283 return STATUS_SUCCESS
;
288 SeDeassignPrimaryToken(PEPROCESS Process
)
292 /* Remove the Token */
293 OldToken
= ObFastReplaceObject(&Process
->Token
, NULL
);
295 /* Mark the Old Token as free */
296 OldToken
->TokenInUse
= 0;
300 RtlLengthSidAndAttributes(ULONG Count
,
301 PSID_AND_ATTRIBUTES Src
)
308 uLength
= Count
* sizeof(SID_AND_ATTRIBUTES
);
309 for (i
= 0; i
< Count
; i
++)
310 uLength
+= RtlLengthSid(Src
[i
].Sid
);
318 SepFindPrimaryGroupAndDefaultOwner(PTOKEN Token
,
324 Token
->PrimaryGroup
= 0;
328 Token
->DefaultOwnerIndex
= Token
->UserAndGroupCount
;
331 /* Validate and set the primary group and user pointers */
332 for (i
= 0; i
< Token
->UserAndGroupCount
; i
++)
335 RtlEqualSid(Token
->UserAndGroups
[i
].Sid
, DefaultOwner
))
337 Token
->DefaultOwnerIndex
= i
;
340 if (RtlEqualSid(Token
->UserAndGroups
[i
].Sid
, PrimaryGroup
))
342 Token
->PrimaryGroup
= Token
->UserAndGroups
[i
].Sid
;
346 if (Token
->DefaultOwnerIndex
== Token
->UserAndGroupCount
)
348 return(STATUS_INVALID_OWNER
);
351 if (Token
->PrimaryGroup
== 0)
353 return(STATUS_INVALID_PRIMARY_GROUP
);
356 return STATUS_SUCCESS
;
362 SepDuplicateToken(PTOKEN Token
,
363 POBJECT_ATTRIBUTES ObjectAttributes
,
364 BOOLEAN EffectiveOnly
,
365 TOKEN_TYPE TokenType
,
366 SECURITY_IMPERSONATION_LEVEL Level
,
367 KPROCESSOR_MODE PreviousMode
,
368 PTOKEN
* NewAccessToken
)
373 PTOKEN AccessToken
= NULL
;
378 Status
= ObCreateObject(PreviousMode
,
386 (PVOID
*)&AccessToken
);
387 if (!NT_SUCCESS(Status
))
389 DPRINT1("ObCreateObject() failed (Status %lx)\n", Status
);
393 /* Zero out the buffer */
394 RtlZeroMemory(AccessToken
, sizeof(TOKEN
));
396 Status
= ZwAllocateLocallyUniqueId(&AccessToken
->TokenId
);
397 if (!NT_SUCCESS(Status
))
399 ObDereferenceObject(AccessToken
);
403 Status
= ZwAllocateLocallyUniqueId(&AccessToken
->ModifiedId
);
404 if (!NT_SUCCESS(Status
))
406 ObDereferenceObject(AccessToken
);
410 AccessToken
->TokenLock
= &SepTokenLock
;
412 AccessToken
->TokenType
= TokenType
;
413 AccessToken
->ImpersonationLevel
= Level
;
414 RtlCopyLuid(&AccessToken
->AuthenticationId
, &Token
->AuthenticationId
);
416 AccessToken
->TokenSource
.SourceIdentifier
.LowPart
= Token
->TokenSource
.SourceIdentifier
.LowPart
;
417 AccessToken
->TokenSource
.SourceIdentifier
.HighPart
= Token
->TokenSource
.SourceIdentifier
.HighPart
;
418 memcpy(AccessToken
->TokenSource
.SourceName
,
419 Token
->TokenSource
.SourceName
,
420 sizeof(Token
->TokenSource
.SourceName
));
421 AccessToken
->ExpirationTime
.QuadPart
= Token
->ExpirationTime
.QuadPart
;
422 AccessToken
->UserAndGroupCount
= Token
->UserAndGroupCount
;
423 AccessToken
->DefaultOwnerIndex
= Token
->DefaultOwnerIndex
;
425 uLength
= sizeof(SID_AND_ATTRIBUTES
) * AccessToken
->UserAndGroupCount
;
426 for (i
= 0; i
< Token
->UserAndGroupCount
; i
++)
427 uLength
+= RtlLengthSid(Token
->UserAndGroups
[i
].Sid
);
429 AccessToken
->UserAndGroups
= ExAllocatePoolWithTag(PagedPool
,
432 if (AccessToken
->UserAndGroups
== NULL
)
434 Status
= STATUS_INSUFFICIENT_RESOURCES
;
438 EndMem
= &AccessToken
->UserAndGroups
[AccessToken
->UserAndGroupCount
];
440 Status
= RtlCopySidAndAttributesArray(AccessToken
->UserAndGroupCount
,
441 Token
->UserAndGroups
,
443 AccessToken
->UserAndGroups
,
447 if (!NT_SUCCESS(Status
))
450 Status
= SepFindPrimaryGroupAndDefaultOwner(AccessToken
,
453 if (!NT_SUCCESS(Status
))
456 AccessToken
->PrivilegeCount
= Token
->PrivilegeCount
;
458 uLength
= AccessToken
->PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
);
459 AccessToken
->Privileges
= ExAllocatePoolWithTag(PagedPool
,
461 TAG_TOKEN_PRIVILAGES
);
462 if (AccessToken
->Privileges
== NULL
)
464 Status
= STATUS_INSUFFICIENT_RESOURCES
;
468 for (i
= 0; i
< AccessToken
->PrivilegeCount
; i
++)
470 RtlCopyLuid(&AccessToken
->Privileges
[i
].Luid
,
471 &Token
->Privileges
[i
].Luid
);
472 AccessToken
->Privileges
[i
].Attributes
=
473 Token
->Privileges
[i
].Attributes
;
476 if (Token
->DefaultDacl
)
478 AccessToken
->DefaultDacl
= ExAllocatePoolWithTag(PagedPool
,
479 Token
->DefaultDacl
->AclSize
,
481 if (AccessToken
->DefaultDacl
== NULL
)
483 Status
= STATUS_INSUFFICIENT_RESOURCES
;
487 memcpy(AccessToken
->DefaultDacl
,
489 Token
->DefaultDacl
->AclSize
);
492 *NewAccessToken
= AccessToken
;
495 if (!NT_SUCCESS(Status
))
499 if (AccessToken
->UserAndGroups
)
500 ExFreePoolWithTag(AccessToken
->UserAndGroups
, TAG_TOKEN_USERS
);
502 if (AccessToken
->Privileges
)
503 ExFreePoolWithTag(AccessToken
->Privileges
, TAG_TOKEN_PRIVILAGES
);
505 if (AccessToken
->DefaultDacl
)
506 ExFreePoolWithTag(AccessToken
->DefaultDacl
, TAG_TOKEN_ACL
);
508 ObDereferenceObject(AccessToken
);
517 SeSubProcessToken(IN PTOKEN ParentToken
,
523 OBJECT_ATTRIBUTES ObjectAttributes
;
526 /* Initialize the attributes and duplicate it */
527 InitializeObjectAttributes(&ObjectAttributes
, NULL
, 0, NULL
, NULL
);
528 Status
= SepDuplicateToken(ParentToken
,
532 ParentToken
->ImpersonationLevel
,
535 if (NT_SUCCESS(Status
))
538 Status
= ObInsertObject(NewToken
,
544 if (NT_SUCCESS(Status
))
546 /* Set the session ID */
547 NewToken
->SessionId
= SessionId
;
548 NewToken
->TokenInUse
= InUse
;
550 /* Return the token */
561 SeIsTokenChild(IN PTOKEN Token
,
562 OUT PBOOLEAN IsChild
)
565 LUID ProcessLuid
, CallerLuid
;
570 /* Reference the process token */
571 ProcessToken
= PsReferencePrimaryToken(PsGetCurrentProcess());
574 ProcessLuid
= ProcessToken
->AuthenticationId
;
576 /* Dereference the token */
577 ObFastDereferenceObject(&PsGetCurrentProcess()->Token
, ProcessToken
);
580 CallerLuid
= Token
->AuthenticationId
;
582 /* Compare the LUIDs */
583 if (RtlEqualLuid(&CallerLuid
, &ProcessLuid
)) *IsChild
= TRUE
;
586 return STATUS_SUCCESS
;
591 SeCopyClientToken(IN PACCESS_TOKEN Token
,
592 IN SECURITY_IMPERSONATION_LEVEL Level
,
593 IN KPROCESSOR_MODE PreviousMode
,
594 OUT PACCESS_TOKEN
* NewToken
)
597 OBJECT_ATTRIBUTES ObjectAttributes
;
601 InitializeObjectAttributes(&ObjectAttributes
,
606 Status
= SepDuplicateToken(Token
,
619 SepDeleteToken(PVOID ObjectBody
)
621 PTOKEN AccessToken
= (PTOKEN
)ObjectBody
;
623 if (AccessToken
->UserAndGroups
)
624 ExFreePoolWithTag(AccessToken
->UserAndGroups
, TAG_TOKEN_USERS
);
626 if (AccessToken
->Privileges
)
627 ExFreePoolWithTag(AccessToken
->Privileges
, TAG_TOKEN_PRIVILAGES
);
629 if (AccessToken
->DefaultDacl
)
630 ExFreePoolWithTag(AccessToken
->DefaultDacl
, TAG_TOKEN_ACL
);
637 SepInitializeTokenImplementation(VOID
)
640 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
642 ExInitializeResource(&SepTokenLock
);
644 DPRINT("Creating Token Object Type\n");
646 /* Initialize the Token type */
647 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
648 RtlInitUnicodeString(&Name
, L
"Token");
649 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
650 ObjectTypeInitializer
.InvalidAttributes
= OBJ_OPENLINK
;
651 ObjectTypeInitializer
.SecurityRequired
= TRUE
;
652 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(TOKEN
);
653 ObjectTypeInitializer
.GenericMapping
= SepTokenMapping
;
654 ObjectTypeInitializer
.PoolType
= PagedPool
;
655 ObjectTypeInitializer
.ValidAccessMask
= TOKEN_ALL_ACCESS
;
656 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
657 ObjectTypeInitializer
.DeleteProcedure
= SepDeleteToken
;
658 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &SeTokenObjectType
);
663 SeAssignPrimaryToken(IN PEPROCESS Process
,
669 ASSERT(Token
->TokenType
== TokenPrimary
);
670 ASSERT(!Token
->TokenInUse
);
672 /* Clean any previous token */
673 if (Process
->Token
.Object
) SeDeassignPrimaryToken(Process
);
675 /* Set the new token */
676 ObReferenceObject(Token
);
677 Token
->TokenInUse
= TRUE
;
678 ObInitializeFastReference(&Process
->Token
, Token
);
684 SepCreateToken(OUT PHANDLE TokenHandle
,
685 IN KPROCESSOR_MODE PreviousMode
,
686 IN ACCESS_MASK DesiredAccess
,
687 IN POBJECT_ATTRIBUTES ObjectAttributes
,
688 IN TOKEN_TYPE TokenType
,
689 IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
,
690 IN PLUID AuthenticationId
,
691 IN PLARGE_INTEGER ExpirationTime
,
692 IN PSID_AND_ATTRIBUTES User
,
694 IN PSID_AND_ATTRIBUTES Groups
,
695 IN ULONG GroupLength
,
696 IN ULONG PrivilegeCount
,
697 IN PLUID_AND_ATTRIBUTES Privileges
,
699 IN PSID PrimaryGroup
,
701 IN PTOKEN_SOURCE TokenSource
,
702 IN BOOLEAN SystemToken
)
711 ULONG TokenFlags
= 0;
713 /* Loop all groups */
714 for (i
= 0; i
< GroupCount
; i
++)
716 /* Check for mandatory groups */
717 if (Groups
[i
].Attributes
& SE_GROUP_MANDATORY
)
719 /* Force them to be enabled */
720 Groups
[i
].Attributes
|= (SE_GROUP_ENABLED
| SE_GROUP_ENABLED_BY_DEFAULT
);
723 /* Check of the group is an admin group */
724 if (RtlEqualSid(SeAliasAdminsSid
, Groups
[i
].Sid
))
726 /* Remember this so we can optimize queries later */
727 TokenFlags
|= TOKEN_HAS_ADMIN_GROUP
;
731 Status
= ZwAllocateLocallyUniqueId(&TokenId
);
732 if (!NT_SUCCESS(Status
))
735 Status
= ZwAllocateLocallyUniqueId(&ModifiedId
);
736 if (!NT_SUCCESS(Status
))
739 Status
= ObCreateObject(PreviousMode
,
747 (PVOID
*)&AccessToken
);
748 if (!NT_SUCCESS(Status
))
750 DPRINT1("ObCreateObject() failed (Status %lx)\n", Status
);
754 /* Zero out the buffer */
755 RtlZeroMemory(AccessToken
, sizeof(TOKEN
));
757 AccessToken
->TokenLock
= &SepTokenLock
;
759 RtlCopyLuid(&AccessToken
->TokenSource
.SourceIdentifier
,
760 &TokenSource
->SourceIdentifier
);
761 memcpy(AccessToken
->TokenSource
.SourceName
,
762 TokenSource
->SourceName
,
763 sizeof(TokenSource
->SourceName
));
765 RtlCopyLuid(&AccessToken
->TokenId
, &TokenId
);
766 RtlCopyLuid(&AccessToken
->AuthenticationId
, AuthenticationId
);
767 AccessToken
->ExpirationTime
= *ExpirationTime
;
768 RtlCopyLuid(&AccessToken
->ModifiedId
, &ModifiedId
);
770 AccessToken
->UserAndGroupCount
= GroupCount
+ 1;
771 AccessToken
->PrivilegeCount
= PrivilegeCount
;
773 AccessToken
->TokenFlags
= TokenFlags
;
774 AccessToken
->TokenType
= TokenType
;
775 AccessToken
->ImpersonationLevel
= ImpersonationLevel
;
778 * Normally we would just point these members into the variable information
779 * area; however, our ObCreateObject() call can't allocate a variable information
780 * area, so we allocate them seperately and provide a destroy function.
783 uLength
= sizeof(SID_AND_ATTRIBUTES
) * AccessToken
->UserAndGroupCount
;
784 uLength
+= RtlLengthSid(User
->Sid
);
785 for (i
= 0; i
< GroupCount
; i
++)
786 uLength
+= RtlLengthSid(Groups
[i
].Sid
);
788 // FIXME: should use the object itself
789 AccessToken
->UserAndGroups
= ExAllocatePoolWithTag(PagedPool
,
792 if (AccessToken
->UserAndGroups
== NULL
)
794 Status
= STATUS_INSUFFICIENT_RESOURCES
;
798 EndMem
= &AccessToken
->UserAndGroups
[AccessToken
->UserAndGroupCount
];
800 Status
= RtlCopySidAndAttributesArray(1,
803 AccessToken
->UserAndGroups
,
807 if (!NT_SUCCESS(Status
))
810 Status
= RtlCopySidAndAttributesArray(GroupCount
,
813 &AccessToken
->UserAndGroups
[1],
817 if (!NT_SUCCESS(Status
))
820 Status
= SepFindPrimaryGroupAndDefaultOwner(AccessToken
,
823 if (!NT_SUCCESS(Status
))
826 // FIXME: should use the object itself
827 uLength
= PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
);
828 if (uLength
== 0) uLength
= sizeof(PVOID
);
829 AccessToken
->Privileges
= ExAllocatePoolWithTag(PagedPool
,
831 TAG_TOKEN_PRIVILAGES
);
832 if (AccessToken
->Privileges
== NULL
)
834 Status
= STATUS_INSUFFICIENT_RESOURCES
;
838 if (PreviousMode
!= KernelMode
)
842 RtlCopyMemory(AccessToken
->Privileges
,
844 PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
));
846 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
848 Status
= _SEH2_GetExceptionCode();
854 RtlCopyMemory(AccessToken
->Privileges
,
856 PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
));
859 if (!NT_SUCCESS(Status
))
862 /* Update privilege flags */
863 SepUpdatePrivilegeFlagsToken(AccessToken
);
865 if (DefaultDacl
!= NULL
)
867 // FIXME: should use the object itself
868 AccessToken
->DefaultDacl
= ExAllocatePoolWithTag(PagedPool
,
869 DefaultDacl
->AclSize
,
871 if (AccessToken
->DefaultDacl
== NULL
)
873 Status
= STATUS_INSUFFICIENT_RESOURCES
;
877 RtlCopyMemory(AccessToken
->DefaultDacl
,
879 DefaultDacl
->AclSize
);
883 AccessToken
->DefaultDacl
= NULL
;
888 Status
= ObInsertObject((PVOID
)AccessToken
,
894 if (!NT_SUCCESS(Status
))
896 DPRINT1("ObInsertObject() failed (Status %lx)\n", Status
);
901 /* Return pointer instead of handle */
902 *TokenHandle
= (HANDLE
)AccessToken
;
906 if (!NT_SUCCESS(Status
))
910 /* Dereference the token, the delete procedure will clean up */
911 ObDereferenceObject(AccessToken
);
920 SepCreateSystemProcessToken(VOID
)
922 LUID_AND_ATTRIBUTES Privileges
[25];
923 ULONG GroupAttributes
, OwnerAttributes
;
924 SID_AND_ATTRIBUTES Groups
[32];
925 LARGE_INTEGER Expiration
;
926 SID_AND_ATTRIBUTES UserSid
;
929 OBJECT_ATTRIBUTES ObjectAttributes
;
935 /* Don't ever expire */
936 Expiration
.QuadPart
= -1;
938 /* All groups mandatory and enabled */
939 GroupAttributes
= SE_GROUP_ENABLED
| SE_GROUP_MANDATORY
| SE_GROUP_ENABLED_BY_DEFAULT
;
940 OwnerAttributes
= SE_GROUP_ENABLED
| SE_GROUP_OWNER
| SE_GROUP_ENABLED_BY_DEFAULT
;
943 UserSid
.Sid
= SeLocalSystemSid
;
944 UserSid
.Attributes
= 0;
946 /* Primary group is local system */
947 PrimaryGroup
= SeLocalSystemSid
;
949 /* Owner is admins */
950 Owner
= SeAliasAdminsSid
;
952 /* Groups are admins, world, and authenticated users */
953 Groups
[0].Sid
= SeAliasAdminsSid
;
954 Groups
[0].Attributes
= OwnerAttributes
;
955 Groups
[1].Sid
= SeWorldSid
;
956 Groups
[1].Attributes
= GroupAttributes
;
957 Groups
[2].Sid
= SeAuthenticatedUserSid
;
958 Groups
[2].Attributes
= OwnerAttributes
;
959 GroupLength
= sizeof(SID_AND_ATTRIBUTES
) +
960 SeLengthSid(Groups
[0].Sid
) +
961 SeLengthSid(Groups
[1].Sid
) +
962 SeLengthSid(Groups
[2].Sid
);
963 ASSERT(GroupLength
<= sizeof(Groups
));
965 /* Setup the privileges */
967 Privileges
[i
].Attributes
= SE_PRIVILEGE_ENABLED_BY_DEFAULT
| SE_PRIVILEGE_ENABLED
;
968 Privileges
[i
++].Luid
= SeTcbPrivilege
;
970 Privileges
[i
].Attributes
= 0;
971 Privileges
[i
++].Luid
= SeCreateTokenPrivilege
;
973 Privileges
[i
].Attributes
= 0;
974 Privileges
[i
++].Luid
= SeTakeOwnershipPrivilege
;
976 Privileges
[i
].Attributes
= SE_PRIVILEGE_ENABLED_BY_DEFAULT
| SE_PRIVILEGE_ENABLED
;
977 Privileges
[i
++].Luid
= SeCreatePagefilePrivilege
;
979 Privileges
[i
].Attributes
= SE_PRIVILEGE_ENABLED_BY_DEFAULT
| SE_PRIVILEGE_ENABLED
;
980 Privileges
[i
++].Luid
= SeLockMemoryPrivilege
;
982 Privileges
[i
].Attributes
= 0;
983 Privileges
[i
++].Luid
= SeAssignPrimaryTokenPrivilege
;
985 Privileges
[i
].Attributes
= 0;
986 Privileges
[i
++].Luid
= SeIncreaseQuotaPrivilege
;
988 Privileges
[i
].Attributes
= SE_PRIVILEGE_ENABLED_BY_DEFAULT
| SE_PRIVILEGE_ENABLED
;
989 Privileges
[i
++].Luid
= SeIncreaseBasePriorityPrivilege
;
991 Privileges
[i
].Attributes
= SE_PRIVILEGE_ENABLED_BY_DEFAULT
| SE_PRIVILEGE_ENABLED
;
992 Privileges
[i
++].Luid
= SeCreatePermanentPrivilege
;
994 Privileges
[i
].Attributes
= SE_PRIVILEGE_ENABLED_BY_DEFAULT
| SE_PRIVILEGE_ENABLED
;
995 Privileges
[i
++].Luid
= SeDebugPrivilege
;
997 Privileges
[i
].Attributes
= SE_PRIVILEGE_ENABLED_BY_DEFAULT
| SE_PRIVILEGE_ENABLED
;
998 Privileges
[i
++].Luid
= SeAuditPrivilege
;
1000 Privileges
[i
].Attributes
= 0;
1001 Privileges
[i
++].Luid
= SeSecurityPrivilege
;
1003 Privileges
[i
].Attributes
= 0;
1004 Privileges
[i
++].Luid
= SeSystemEnvironmentPrivilege
;
1006 Privileges
[i
].Attributes
= SE_PRIVILEGE_ENABLED_BY_DEFAULT
| SE_PRIVILEGE_ENABLED
;
1007 Privileges
[i
++].Luid
= SeChangeNotifyPrivilege
;
1009 Privileges
[i
].Attributes
= 0;
1010 Privileges
[i
++].Luid
= SeBackupPrivilege
;
1012 Privileges
[i
].Attributes
= 0;
1013 Privileges
[i
++].Luid
= SeRestorePrivilege
;
1015 Privileges
[i
].Attributes
= 0;
1016 Privileges
[i
++].Luid
= SeShutdownPrivilege
;
1018 Privileges
[i
].Attributes
= 0;
1019 Privileges
[i
++].Luid
= SeLoadDriverPrivilege
;
1021 Privileges
[i
].Attributes
= SE_PRIVILEGE_ENABLED_BY_DEFAULT
| SE_PRIVILEGE_ENABLED
;
1022 Privileges
[i
++].Luid
= SeProfileSingleProcessPrivilege
;
1024 Privileges
[i
].Attributes
= 0;
1025 Privileges
[i
++].Luid
= SeSystemtimePrivilege
;
1028 /* Setup the object attributes */
1029 InitializeObjectAttributes(&ObjectAttributes
, NULL
, 0, NULL
, NULL
);
1030 ASSERT(SeSystemDefaultDacl
!= NULL
);
1032 /* Create the token */
1033 Status
= SepCreateToken((PHANDLE
)&Token
,
1039 &SeSystemAuthenticationId
,
1049 SeSystemDefaultDacl
,
1050 &SeSystemTokenSource
,
1052 ASSERT(Status
== STATUS_SUCCESS
);
1054 /* Return the token */
1058 /* PUBLIC FUNCTIONS ***********************************************************/
1065 SeFilterToken(IN PACCESS_TOKEN ExistingToken
,
1067 IN PTOKEN_GROUPS SidsToDisable OPTIONAL
,
1068 IN PTOKEN_PRIVILEGES PrivilegesToDelete OPTIONAL
,
1069 IN PTOKEN_GROUPS RestrictedSids OPTIONAL
,
1070 OUT PACCESS_TOKEN
* FilteredToken
)
1073 return STATUS_NOT_IMPLEMENTED
;
1081 SeQueryInformationToken(IN PACCESS_TOKEN Token
,
1082 IN TOKEN_INFORMATION_CLASS TokenInformationClass
,
1083 OUT PVOID
*TokenInformation
)
1086 return STATUS_NOT_IMPLEMENTED
;
1094 SeQuerySessionIdToken(IN PACCESS_TOKEN Token
,
1095 IN PULONG pSessionId
)
1097 *pSessionId
= ((PTOKEN
)Token
)->SessionId
;
1098 return STATUS_SUCCESS
;
1106 SeQueryAuthenticationIdToken(IN PACCESS_TOKEN Token
,
1111 *LogonId
= ((PTOKEN
)Token
)->AuthenticationId
;
1113 return STATUS_SUCCESS
;
1120 SECURITY_IMPERSONATION_LEVEL
1122 SeTokenImpersonationLevel(IN PACCESS_TOKEN Token
)
1126 return ((PTOKEN
)Token
)->ImpersonationLevel
;
1134 SeTokenType(IN PACCESS_TOKEN Token
)
1138 return ((PTOKEN
)Token
)->TokenType
;
1147 SeTokenIsAdmin(IN PACCESS_TOKEN Token
)
1151 return (((PTOKEN
)Token
)->TokenFlags
& TOKEN_WRITE_RESTRICTED
) != 0;
1159 SeTokenIsRestricted(IN PACCESS_TOKEN Token
)
1163 return (((PTOKEN
)Token
)->TokenFlags
& TOKEN_IS_RESTRICTED
) != 0;
1171 SeTokenIsWriteRestricted(IN PACCESS_TOKEN Token
)
1175 return (((PTOKEN
)Token
)->TokenFlags
& TOKEN_HAS_RESTORE_PRIVILEGE
) != 0;
1178 /* SYSTEM CALLS ***************************************************************/
1184 NtQueryInformationToken(IN HANDLE TokenHandle
,
1185 IN TOKEN_INFORMATION_CLASS TokenInformationClass
,
1186 OUT PVOID TokenInformation
,
1187 IN ULONG TokenInformationLength
,
1188 OUT PULONG ReturnLength
)
1196 ULONG RequiredLength
;
1197 KPROCESSOR_MODE PreviousMode
;
1202 PreviousMode
= ExGetPreviousMode();
1204 /* Check buffers and class validity */
1205 Status
= DefaultQueryInfoBufferCheck(TokenInformationClass
,
1206 SeTokenInformationClass
,
1207 sizeof(SeTokenInformationClass
) / sizeof(SeTokenInformationClass
[0]),
1209 TokenInformationLength
,
1213 if (!NT_SUCCESS(Status
))
1215 DPRINT("NtQueryInformationToken() failed, Status: 0x%x\n", Status
);
1219 Status
= ObReferenceObjectByHandle(TokenHandle
,
1220 (TokenInformationClass
== TokenSource
) ? TOKEN_QUERY_SOURCE
: TOKEN_QUERY
,
1225 if (NT_SUCCESS(Status
))
1227 switch (TokenInformationClass
)
1231 PTOKEN_USER tu
= (PTOKEN_USER
)TokenInformation
;
1233 DPRINT("NtQueryInformationToken(TokenUser)\n");
1234 RequiredLength
= sizeof(TOKEN_USER
) +
1235 RtlLengthSid(Token
->UserAndGroups
[0].Sid
);
1239 if (TokenInformationLength
>= RequiredLength
)
1241 Status
= RtlCopySidAndAttributesArray(1,
1242 &Token
->UserAndGroups
[0],
1243 RequiredLength
- sizeof(TOKEN_USER
),
1251 Status
= STATUS_BUFFER_TOO_SMALL
;
1254 if (ReturnLength
!= NULL
)
1256 *ReturnLength
= RequiredLength
;
1259 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1261 Status
= _SEH2_GetExceptionCode();
1270 PTOKEN_GROUPS tg
= (PTOKEN_GROUPS
)TokenInformation
;
1272 DPRINT("NtQueryInformationToken(TokenGroups)\n");
1273 RequiredLength
= sizeof(tg
->GroupCount
) +
1274 RtlLengthSidAndAttributes(Token
->UserAndGroupCount
- 1, &Token
->UserAndGroups
[1]);
1278 if (TokenInformationLength
>= RequiredLength
)
1280 ULONG SidLen
= RequiredLength
- sizeof(tg
->GroupCount
) -
1281 ((Token
->UserAndGroupCount
- 1) * sizeof(SID_AND_ATTRIBUTES
));
1282 PSID_AND_ATTRIBUTES Sid
= (PSID_AND_ATTRIBUTES
)((ULONG_PTR
)TokenInformation
+ sizeof(tg
->GroupCount
) +
1283 ((Token
->UserAndGroupCount
- 1) * sizeof(SID_AND_ATTRIBUTES
)));
1285 tg
->GroupCount
= Token
->UserAndGroupCount
- 1;
1286 Status
= RtlCopySidAndAttributesArray(Token
->UserAndGroupCount
- 1,
1287 &Token
->UserAndGroups
[1],
1296 Status
= STATUS_BUFFER_TOO_SMALL
;
1299 if (ReturnLength
!= NULL
)
1301 *ReturnLength
= RequiredLength
;
1304 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1306 Status
= _SEH2_GetExceptionCode();
1313 case TokenPrivileges
:
1315 PTOKEN_PRIVILEGES tp
= (PTOKEN_PRIVILEGES
)TokenInformation
;
1317 DPRINT("NtQueryInformationToken(TokenPrivileges)\n");
1318 RequiredLength
= sizeof(tp
->PrivilegeCount
) +
1319 (Token
->PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
));
1323 if (TokenInformationLength
>= RequiredLength
)
1325 tp
->PrivilegeCount
= Token
->PrivilegeCount
;
1326 RtlCopyLuidAndAttributesArray(Token
->PrivilegeCount
,
1328 &tp
->Privileges
[0]);
1332 Status
= STATUS_BUFFER_TOO_SMALL
;
1335 if (ReturnLength
!= NULL
)
1337 *ReturnLength
= RequiredLength
;
1340 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1342 Status
= _SEH2_GetExceptionCode();
1352 PTOKEN_OWNER to
= (PTOKEN_OWNER
)TokenInformation
;
1354 DPRINT("NtQueryInformationToken(TokenOwner)\n");
1355 SidLen
= RtlLengthSid(Token
->UserAndGroups
[Token
->DefaultOwnerIndex
].Sid
);
1356 RequiredLength
= sizeof(TOKEN_OWNER
) + SidLen
;
1360 if (TokenInformationLength
>= RequiredLength
)
1362 to
->Owner
= (PSID
)(to
+ 1);
1363 Status
= RtlCopySid(SidLen
,
1365 Token
->UserAndGroups
[Token
->DefaultOwnerIndex
].Sid
);
1369 Status
= STATUS_BUFFER_TOO_SMALL
;
1372 if (ReturnLength
!= NULL
)
1374 *ReturnLength
= RequiredLength
;
1377 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1379 Status
= _SEH2_GetExceptionCode();
1386 case TokenPrimaryGroup
:
1389 PTOKEN_PRIMARY_GROUP tpg
= (PTOKEN_PRIMARY_GROUP
)TokenInformation
;
1391 DPRINT("NtQueryInformationToken(TokenPrimaryGroup)\n");
1392 SidLen
= RtlLengthSid(Token
->PrimaryGroup
);
1393 RequiredLength
= sizeof(TOKEN_PRIMARY_GROUP
) + SidLen
;
1397 if (TokenInformationLength
>= RequiredLength
)
1399 tpg
->PrimaryGroup
= (PSID
)(tpg
+ 1);
1400 Status
= RtlCopySid(SidLen
,
1402 Token
->PrimaryGroup
);
1406 Status
= STATUS_BUFFER_TOO_SMALL
;
1409 if (ReturnLength
!= NULL
)
1411 *ReturnLength
= RequiredLength
;
1414 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1416 Status
= _SEH2_GetExceptionCode();
1423 case TokenDefaultDacl
:
1425 PTOKEN_DEFAULT_DACL tdd
= (PTOKEN_DEFAULT_DACL
)TokenInformation
;
1427 DPRINT("NtQueryInformationToken(TokenDefaultDacl)\n");
1428 RequiredLength
= sizeof(TOKEN_DEFAULT_DACL
);
1430 if (Token
->DefaultDacl
!= NULL
)
1432 RequiredLength
+= Token
->DefaultDacl
->AclSize
;
1437 if (TokenInformationLength
>= RequiredLength
)
1439 if (Token
->DefaultDacl
!= NULL
)
1441 tdd
->DefaultDacl
= (PACL
)(tdd
+ 1);
1442 RtlCopyMemory(tdd
->DefaultDacl
,
1444 Token
->DefaultDacl
->AclSize
);
1448 tdd
->DefaultDacl
= NULL
;
1453 Status
= STATUS_BUFFER_TOO_SMALL
;
1456 if (ReturnLength
!= NULL
)
1458 *ReturnLength
= RequiredLength
;
1461 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1463 Status
= _SEH2_GetExceptionCode();
1472 PTOKEN_SOURCE ts
= (PTOKEN_SOURCE
)TokenInformation
;
1474 DPRINT("NtQueryInformationToken(TokenSource)\n");
1475 RequiredLength
= sizeof(TOKEN_SOURCE
);
1479 if (TokenInformationLength
>= RequiredLength
)
1481 *ts
= Token
->TokenSource
;
1485 Status
= STATUS_BUFFER_TOO_SMALL
;
1488 if (ReturnLength
!= NULL
)
1490 *ReturnLength
= RequiredLength
;
1493 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1495 Status
= _SEH2_GetExceptionCode();
1504 PTOKEN_TYPE tt
= (PTOKEN_TYPE
)TokenInformation
;
1506 DPRINT("NtQueryInformationToken(TokenType)\n");
1507 RequiredLength
= sizeof(TOKEN_TYPE
);
1511 if (TokenInformationLength
>= RequiredLength
)
1513 *tt
= Token
->TokenType
;
1517 Status
= STATUS_BUFFER_TOO_SMALL
;
1520 if (ReturnLength
!= NULL
)
1522 *ReturnLength
= RequiredLength
;
1525 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1527 Status
= _SEH2_GetExceptionCode();
1534 case TokenImpersonationLevel
:
1536 PSECURITY_IMPERSONATION_LEVEL sil
= (PSECURITY_IMPERSONATION_LEVEL
)TokenInformation
;
1538 DPRINT("NtQueryInformationToken(TokenImpersonationLevel)\n");
1540 /* Fail if the token is not an impersonation token */
1541 if (Token
->TokenType
!= TokenImpersonation
)
1543 Status
= STATUS_INVALID_INFO_CLASS
;
1547 RequiredLength
= sizeof(SECURITY_IMPERSONATION_LEVEL
);
1551 if (TokenInformationLength
>= RequiredLength
)
1553 *sil
= Token
->ImpersonationLevel
;
1557 Status
= STATUS_BUFFER_TOO_SMALL
;
1560 if (ReturnLength
!= NULL
)
1562 *ReturnLength
= RequiredLength
;
1565 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1567 Status
= _SEH2_GetExceptionCode();
1574 case TokenStatistics
:
1576 PTOKEN_STATISTICS ts
= (PTOKEN_STATISTICS
)TokenInformation
;
1578 DPRINT("NtQueryInformationToken(TokenStatistics)\n");
1579 RequiredLength
= sizeof(TOKEN_STATISTICS
);
1583 if (TokenInformationLength
>= RequiredLength
)
1585 ts
->TokenId
= Token
->TokenId
;
1586 ts
->AuthenticationId
= Token
->AuthenticationId
;
1587 ts
->ExpirationTime
= Token
->ExpirationTime
;
1588 ts
->TokenType
= Token
->TokenType
;
1589 ts
->ImpersonationLevel
= Token
->ImpersonationLevel
;
1590 ts
->DynamicCharged
= Token
->DynamicCharged
;
1591 ts
->DynamicAvailable
= Token
->DynamicAvailable
;
1592 ts
->GroupCount
= Token
->UserAndGroupCount
- 1;
1593 ts
->PrivilegeCount
= Token
->PrivilegeCount
;
1594 ts
->ModifiedId
= Token
->ModifiedId
;
1598 Status
= STATUS_BUFFER_TOO_SMALL
;
1601 if (ReturnLength
!= NULL
)
1603 *ReturnLength
= RequiredLength
;
1606 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1608 Status
= _SEH2_GetExceptionCode();
1617 PTOKEN_ORIGIN to
= (PTOKEN_ORIGIN
)TokenInformation
;
1619 DPRINT("NtQueryInformationToken(TokenOrigin)\n");
1620 RequiredLength
= sizeof(TOKEN_ORIGIN
);
1624 if (TokenInformationLength
>= RequiredLength
)
1626 RtlCopyLuid(&to
->OriginatingLogonSession
,
1627 &Token
->AuthenticationId
);
1631 Status
= STATUS_BUFFER_TOO_SMALL
;
1634 if (ReturnLength
!= NULL
)
1636 *ReturnLength
= RequiredLength
;
1639 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1641 Status
= _SEH2_GetExceptionCode();
1648 case TokenGroupsAndPrivileges
:
1649 DPRINT1("NtQueryInformationToken(TokenGroupsAndPrivileges) not implemented\n");
1650 Status
= STATUS_NOT_IMPLEMENTED
;
1653 case TokenRestrictedSids
:
1655 PTOKEN_GROUPS tg
= (PTOKEN_GROUPS
)TokenInformation
;
1657 DPRINT("NtQueryInformationToken(TokenRestrictedSids)\n");
1658 RequiredLength
= sizeof(tg
->GroupCount
) +
1659 RtlLengthSidAndAttributes(Token
->RestrictedSidCount
, Token
->RestrictedSids
);
1663 if (TokenInformationLength
>= RequiredLength
)
1665 ULONG SidLen
= RequiredLength
- sizeof(tg
->GroupCount
) -
1666 (Token
->RestrictedSidCount
* sizeof(SID_AND_ATTRIBUTES
));
1667 PSID_AND_ATTRIBUTES Sid
= (PSID_AND_ATTRIBUTES
)((ULONG_PTR
)TokenInformation
+ sizeof(tg
->GroupCount
) +
1668 (Token
->RestrictedSidCount
* sizeof(SID_AND_ATTRIBUTES
)));
1670 tg
->GroupCount
= Token
->RestrictedSidCount
;
1671 Status
= RtlCopySidAndAttributesArray(Token
->RestrictedSidCount
,
1672 Token
->RestrictedSids
,
1681 Status
= STATUS_BUFFER_TOO_SMALL
;
1684 if (ReturnLength
!= NULL
)
1686 *ReturnLength
= RequiredLength
;
1689 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1691 Status
= _SEH2_GetExceptionCode();
1698 case TokenSandBoxInert
:
1699 DPRINT1("NtQueryInformationToken(TokenSandboxInert) not implemented\n");
1700 Status
= STATUS_NOT_IMPLEMENTED
;
1703 case TokenSessionId
:
1705 ULONG SessionId
= 0;
1707 DPRINT("NtQueryInformationToken(TokenSessionId)\n");
1709 Status
= SeQuerySessionIdToken(Token
,
1712 if (NT_SUCCESS(Status
))
1716 /* buffer size was already verified, no need to check here again */
1717 *(PULONG
)TokenInformation
= SessionId
;
1719 if (ReturnLength
!= NULL
)
1721 *ReturnLength
= sizeof(ULONG
);
1724 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1726 Status
= _SEH2_GetExceptionCode();
1735 DPRINT1("NtQueryInformationToken(%d) invalid information class\n", TokenInformationClass
);
1736 Status
= STATUS_INVALID_INFO_CLASS
;
1740 ObDereferenceObject(Token
);
1748 * NtSetTokenInformation: Partly implemented.
1750 * TokenOrigin, TokenDefaultDacl
1754 NtSetInformationToken(IN HANDLE TokenHandle
,
1755 IN TOKEN_INFORMATION_CLASS TokenInformationClass
,
1756 OUT PVOID TokenInformation
,
1757 IN ULONG TokenInformationLength
)
1760 KPROCESSOR_MODE PreviousMode
;
1761 ULONG NeededAccess
= TOKEN_ADJUST_DEFAULT
;
1766 PreviousMode
= ExGetPreviousMode();
1768 Status
= DefaultSetInfoBufferCheck(TokenInformationClass
,
1769 SeTokenInformationClass
,
1770 sizeof(SeTokenInformationClass
) / sizeof(SeTokenInformationClass
[0]),
1772 TokenInformationLength
,
1774 if (!NT_SUCCESS(Status
))
1776 /* Invalid buffers */
1777 DPRINT("NtSetInformationToken() failed, Status: 0x%x\n", Status
);
1781 if (TokenInformationClass
== TokenSessionId
)
1783 NeededAccess
|= TOKEN_ADJUST_SESSIONID
;
1786 Status
= ObReferenceObjectByHandle(TokenHandle
,
1792 if (NT_SUCCESS(Status
))
1794 switch (TokenInformationClass
)
1798 if (TokenInformationLength
>= sizeof(TOKEN_OWNER
))
1800 PTOKEN_OWNER to
= (PTOKEN_OWNER
)TokenInformation
;
1801 PSID InputSid
= NULL
, CapturedSid
;
1805 InputSid
= to
->Owner
;
1807 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1809 Status
= _SEH2_GetExceptionCode();
1814 Status
= SepCaptureSid(InputSid
,
1819 if (NT_SUCCESS(Status
))
1821 RtlCopySid(RtlLengthSid(CapturedSid
),
1822 Token
->UserAndGroups
[Token
->DefaultOwnerIndex
].Sid
,
1824 SepReleaseSid(CapturedSid
,
1831 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1836 case TokenPrimaryGroup
:
1838 if (TokenInformationLength
>= sizeof(TOKEN_PRIMARY_GROUP
))
1840 PTOKEN_PRIMARY_GROUP tpg
= (PTOKEN_PRIMARY_GROUP
)TokenInformation
;
1841 PSID InputSid
= NULL
, CapturedSid
;
1845 InputSid
= tpg
->PrimaryGroup
;
1847 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1849 Status
= _SEH2_GetExceptionCode();
1854 Status
= SepCaptureSid(InputSid
,
1859 if (NT_SUCCESS(Status
))
1861 RtlCopySid(RtlLengthSid(CapturedSid
),
1862 Token
->PrimaryGroup
,
1864 SepReleaseSid(CapturedSid
,
1871 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1876 case TokenDefaultDacl
:
1878 if (TokenInformationLength
>= sizeof(TOKEN_DEFAULT_DACL
))
1880 PTOKEN_DEFAULT_DACL tdd
= (PTOKEN_DEFAULT_DACL
)TokenInformation
;
1881 PACL InputAcl
= NULL
;
1885 InputAcl
= tdd
->DefaultDacl
;
1887 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1889 Status
= _SEH2_GetExceptionCode();
1894 if (InputAcl
!= NULL
)
1898 /* Capture and copy the dacl */
1899 Status
= SepCaptureAcl(InputAcl
,
1904 if (NT_SUCCESS(Status
))
1906 /* Free the previous dacl if present */
1907 if(Token
->DefaultDacl
!= NULL
)
1909 ExFreePoolWithTag(Token
->DefaultDacl
, TAG_TOKEN_ACL
);
1912 /* Set the new dacl */
1913 Token
->DefaultDacl
= CapturedAcl
;
1918 /* Clear and free the default dacl if present */
1919 if (Token
->DefaultDacl
!= NULL
)
1921 ExFreePoolWithTag(Token
->DefaultDacl
, TAG_TOKEN_ACL
);
1922 Token
->DefaultDacl
= NULL
;
1928 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1933 case TokenSessionId
:
1935 ULONG SessionId
= 0;
1939 /* Buffer size was already verified, no need to check here again */
1940 SessionId
= *(PULONG
)TokenInformation
;
1942 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1944 Status
= _SEH2_GetExceptionCode();
1949 if (!SeSinglePrivilegeCheck(SeTcbPrivilege
,
1952 Status
= STATUS_PRIVILEGE_NOT_HELD
;
1956 Token
->SessionId
= SessionId
;
1960 case TokenSessionReference
:
1962 ULONG SessionReference
;
1966 /* Buffer size was already verified, no need to check here again */
1967 SessionReference
= *(PULONG
)TokenInformation
;
1969 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1971 Status
= _SEH2_GetExceptionCode();
1976 if (!SeSinglePrivilegeCheck(SeTcbPrivilege
, PreviousMode
))
1978 Status
= STATUS_PRIVILEGE_NOT_HELD
;
1982 /* Check if it is 0 */
1983 if (SessionReference
== 0)
1985 /* Atomically set the flag in the token */
1986 RtlInterlockedSetBits(&Token
->TokenFlags
,
1987 TOKEN_SESSION_NOT_REFERENCED
);
1995 case TokenAuditPolicy
:
1997 PTOKEN_AUDIT_POLICY_INFORMATION PolicyInformation
=
1998 (PTOKEN_AUDIT_POLICY_INFORMATION
)TokenInformation
;
1999 SEP_AUDIT_POLICY AuditPolicy
;
2004 ProbeForRead(PolicyInformation
,
2005 FIELD_OFFSET(TOKEN_AUDIT_POLICY_INFORMATION
,
2006 Policies
[PolicyInformation
->PolicyCount
]),
2009 /* Loop all policies in the structure */
2010 for (i
= 0; i
< PolicyInformation
->PolicyCount
; i
++)
2012 /* Set the corresponding bits in the packed structure */
2013 switch (PolicyInformation
->Policies
[i
].Category
)
2015 case AuditCategorySystem
:
2016 AuditPolicy
.PolicyElements
.System
= PolicyInformation
->Policies
[i
].Value
;
2019 case AuditCategoryLogon
:
2020 AuditPolicy
.PolicyElements
.Logon
= PolicyInformation
->Policies
[i
].Value
;
2023 case AuditCategoryObjectAccess
:
2024 AuditPolicy
.PolicyElements
.ObjectAccess
= PolicyInformation
->Policies
[i
].Value
;
2027 case AuditCategoryPrivilegeUse
:
2028 AuditPolicy
.PolicyElements
.PrivilegeUse
= PolicyInformation
->Policies
[i
].Value
;
2031 case AuditCategoryDetailedTracking
:
2032 AuditPolicy
.PolicyElements
.DetailedTracking
= PolicyInformation
->Policies
[i
].Value
;
2035 case AuditCategoryPolicyChange
:
2036 AuditPolicy
.PolicyElements
.PolicyChange
= PolicyInformation
->Policies
[i
].Value
;
2039 case AuditCategoryAccountManagement
:
2040 AuditPolicy
.PolicyElements
.AccountManagement
= PolicyInformation
->Policies
[i
].Value
;
2043 case AuditCategoryDirectoryServiceAccess
:
2044 AuditPolicy
.PolicyElements
.DirectoryServiceAccess
= PolicyInformation
->Policies
[i
].Value
;
2047 case AuditCategoryAccountLogon
:
2048 AuditPolicy
.PolicyElements
.AccountLogon
= PolicyInformation
->Policies
[i
].Value
;
2053 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2055 Status
= _SEH2_GetExceptionCode();
2060 if (!SeSinglePrivilegeCheck(SeTcbPrivilege
,
2063 Status
= STATUS_PRIVILEGE_NOT_HELD
;
2067 /* Lock the token */
2068 SepAcquireTokenLockExclusive(Token
);
2070 /* Set the new audit policy */
2071 Token
->AuditPolicy
= AuditPolicy
;
2073 /* Unlock the token */
2074 SepReleaseTokenLock(Token
);
2081 TOKEN_ORIGIN TokenOrigin
;
2085 /* Copy the token origin */
2086 TokenOrigin
= *(PTOKEN_ORIGIN
)TokenInformation
;
2088 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2090 Status
= _SEH2_GetExceptionCode();
2095 /* Check for TCB privilege */
2096 if (!SeSinglePrivilegeCheck(SeTcbPrivilege
, PreviousMode
))
2098 Status
= STATUS_PRIVILEGE_NOT_HELD
;
2102 /* Lock the token */
2103 SepAcquireTokenLockExclusive(Token
);
2105 /* Check if there is no token origin set yet */
2106 if ((Token
->OriginatingLogonSession
.LowPart
== 0) &&
2107 (Token
->OriginatingLogonSession
.HighPart
== 0))
2109 /* Set the token origin */
2110 Token
->OriginatingLogonSession
=
2111 TokenOrigin
.OriginatingLogonSession
;
2114 /* Unlock the token */
2115 SepReleaseTokenLock(Token
);
2122 DPRINT1("Invalid TokenInformationClass: 0x%lx\n",
2123 TokenInformationClass
);
2124 Status
= STATUS_INVALID_INFO_CLASS
;
2129 ObDereferenceObject(Token
);
2132 if (!NT_SUCCESS(Status
))
2134 DPRINT1("NtSetInformationToken failed with Status 0x%lx\n", Status
);
2144 * NOTE: Some sources claim 4th param is ImpersonationLevel, but on W2K
2145 * this is certainly NOT true, thou i can't say for sure that EffectiveOnly
2146 * is correct either. -Gunnar
2147 * This is true. EffectiveOnly overrides SQOS.EffectiveOnly. - IAI
2150 NtDuplicateToken(IN HANDLE ExistingTokenHandle
,
2151 IN ACCESS_MASK DesiredAccess
,
2152 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
2153 IN BOOLEAN EffectiveOnly
,
2154 IN TOKEN_TYPE TokenType
,
2155 OUT PHANDLE NewTokenHandle
)
2157 KPROCESSOR_MODE PreviousMode
;
2161 PSECURITY_QUALITY_OF_SERVICE CapturedSecurityQualityOfService
;
2163 OBJECT_HANDLE_INFORMATION HandleInformation
;
2168 if (TokenType
!= TokenImpersonation
&&
2169 TokenType
!= TokenPrimary
)
2170 return STATUS_INVALID_PARAMETER
;
2172 PreviousMode
= KeGetPreviousMode();
2174 if (PreviousMode
!= KernelMode
)
2178 ProbeForWriteHandle(NewTokenHandle
);
2180 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2182 /* Return the exception code */
2183 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2188 Status
= SepCaptureSecurityQualityOfService(ObjectAttributes
,
2192 &CapturedSecurityQualityOfService
,
2194 if (!NT_SUCCESS(Status
))
2196 DPRINT1("NtDuplicateToken() failed to capture QoS! Status: 0x%x\n", Status
);
2200 Status
= ObReferenceObjectByHandle(ExistingTokenHandle
,
2205 &HandleInformation
);
2206 if (!NT_SUCCESS(Status
))
2208 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService
,
2215 * Fail, if the original token is an impersonation token and the caller
2216 * tries to raise the impersonation level of the new token above the
2217 * impersonation level of the original token.
2219 if (Token
->TokenType
== TokenImpersonation
)
2222 CapturedSecurityQualityOfService
->ImpersonationLevel
>Token
->ImpersonationLevel
)
2224 ObDereferenceObject(Token
);
2225 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService
,
2228 return STATUS_BAD_IMPERSONATION_LEVEL
;
2233 * Fail, if a primary token is to be created from an impersonation token
2234 * and and the impersonation level of the impersonation token is below SecurityImpersonation.
2236 if (Token
->TokenType
== TokenImpersonation
&&
2237 TokenType
== TokenPrimary
&&
2238 Token
->ImpersonationLevel
< SecurityImpersonation
)
2240 ObDereferenceObject(Token
);
2241 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService
,
2244 return STATUS_BAD_IMPERSONATION_LEVEL
;
2247 Status
= SepDuplicateToken(Token
,
2251 (QoSPresent
? CapturedSecurityQualityOfService
->ImpersonationLevel
: SecurityAnonymous
),
2255 ObDereferenceObject(Token
);
2257 if (NT_SUCCESS(Status
))
2259 Status
= ObInsertObject((PVOID
)NewToken
,
2261 (DesiredAccess
? DesiredAccess
: HandleInformation
.GrantedAccess
),
2265 if (NT_SUCCESS(Status
))
2269 *NewTokenHandle
= hToken
;
2271 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2273 Status
= _SEH2_GetExceptionCode();
2279 /* Free the captured structure */
2280 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService
,
2288 NtAdjustGroupsToken(IN HANDLE TokenHandle
,
2289 IN BOOLEAN ResetToDefault
,
2290 IN PTOKEN_GROUPS NewState
,
2291 IN ULONG BufferLength
,
2292 OUT PTOKEN_GROUPS PreviousState OPTIONAL
,
2293 OUT PULONG ReturnLength
)
2296 return(STATUS_NOT_IMPLEMENTED
);
2302 SepAdjustPrivileges(
2303 _Inout_ PTOKEN Token
,
2304 _In_ BOOLEAN DisableAllPrivileges
,
2305 _In_opt_ PLUID_AND_ATTRIBUTES NewState
,
2306 _In_ ULONG NewStateCount
,
2307 _Out_opt_ PTOKEN_PRIVILEGES PreviousState
,
2308 _In_ BOOLEAN ApplyChanges
,
2309 _Out_ PULONG ChangedPrivileges
)
2311 ULONG i
, j
, PrivilegeCount
, ChangeCount
, NewAttributes
;
2313 /* Count the found privileges and those that need to be changed */
2317 /* Loop all privileges in the token */
2318 for (i
= 0; i
< Token
->PrivilegeCount
; i
++)
2320 /* Shall all of them be disabled? */
2321 if (DisableAllPrivileges
)
2323 /* The new attributes are the old ones, but disabled */
2324 NewAttributes
= Token
->Privileges
[i
].Attributes
& ~SE_PRIVILEGE_ENABLED
;
2328 /* Otherwise loop all provided privileges */
2329 for (j
= 0; j
< NewStateCount
; j
++)
2331 /* Check if this is the LUID we are looking for */
2332 if (RtlEqualLuid(&Token
->Privileges
[i
].Luid
, &NewState
[j
].Luid
))
2334 DPRINT("Found privilege\n");
2336 /* Copy SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_REMOVED */
2337 NewAttributes
= NewState
[j
].Attributes
;
2338 NewAttributes
&= (SE_PRIVILEGE_ENABLED
| SE_PRIVILEGE_REMOVED
);
2339 NewAttributes
|= Token
->Privileges
[i
].Attributes
& ~SE_PRIVILEGE_ENABLED
;
2346 /* Check if we didn't find the privilege */
2347 if (j
== NewStateCount
)
2349 /* Continue with the token's next privilege */
2354 /* We found a privilege, count it */
2357 /* Does the privilege need to be changed? */
2358 if (Token
->Privileges
[i
].Attributes
!= NewAttributes
)
2360 /* Does the caller want the old privileges? */
2361 if (PreviousState
!= NULL
)
2363 /* Copy the old privilege */
2364 PreviousState
->Privileges
[ChangeCount
] = Token
->Privileges
[i
];
2367 /* Does the caller want to apply the changes? */
2370 /* Shall we remove the privilege? */
2371 if (NewAttributes
& SE_PRIVILEGE_REMOVED
)
2373 /* Set the token as disabled and update flags for it */
2374 Token
->Privileges
[i
].Attributes
&= ~SE_PRIVILEGE_ENABLED
;
2375 SepUpdateSinglePrivilegeFlagToken(Token
, i
);
2377 /* Remove the privilege */
2378 SepRemovePrivilegeToken(Token
, i
);
2380 /* Fix the running index */
2383 /* Continue with next */
2387 /* Set the new attributes and update flags */
2388 Token
->Privileges
[i
].Attributes
= NewAttributes
;
2389 SepUpdateSinglePrivilegeFlagToken(Token
, i
);
2392 /* Increment the change count */
2397 /* Set the number of saved privileges */
2398 if (PreviousState
!= NULL
)
2399 PreviousState
->PrivilegeCount
= ChangeCount
;
2401 /* Return the number of changed privileges */
2402 *ChangedPrivileges
= ChangeCount
;
2404 /* Check if we missed some */
2405 if (!DisableAllPrivileges
&& (PrivilegeCount
< NewStateCount
))
2407 return STATUS_NOT_ALL_ASSIGNED
;
2410 return STATUS_SUCCESS
;
2417 _Must_inspect_result_
2421 NtAdjustPrivilegesToken(
2422 _In_ HANDLE TokenHandle
,
2423 _In_ BOOLEAN DisableAllPrivileges
,
2424 _In_opt_ PTOKEN_PRIVILEGES NewState
,
2425 _In_ ULONG BufferLength
,
2426 _Out_writes_bytes_to_opt_(BufferLength
,*ReturnLength
)
2427 PTOKEN_PRIVILEGES PreviousState
,
2428 _When_(PreviousState
!=NULL
, _Out_
) PULONG ReturnLength
)
2430 PLUID_AND_ATTRIBUTES CapturedPrivileges
= NULL
;
2431 KPROCESSOR_MODE PreviousMode
;
2432 ULONG CapturedCount
= 0;
2433 ULONG CapturedLength
= 0;
2434 ULONG NewStateSize
= 0;
2436 ULONG RequiredLength
;
2441 DPRINT("NtAdjustPrivilegesToken() called\n");
2443 /* Fail, if we do not disable all privileges but NewState is NULL */
2444 if (DisableAllPrivileges
== FALSE
&& NewState
== NULL
)
2445 return STATUS_INVALID_PARAMETER
;
2447 PreviousMode
= KeGetPreviousMode ();
2448 if (PreviousMode
!= KernelMode
)
2452 /* Probe NewState */
2453 if (DisableAllPrivileges
== FALSE
)
2455 /* First probe the header */
2456 ProbeForRead(NewState
, sizeof(TOKEN_PRIVILEGES
), sizeof(ULONG
));
2458 CapturedCount
= NewState
->PrivilegeCount
;
2459 NewStateSize
= FIELD_OFFSET(TOKEN_PRIVILEGES
, Privileges
[CapturedCount
]);
2461 ProbeForRead(NewState
, NewStateSize
, sizeof(ULONG
));
2464 /* Probe PreviousState and ReturnLength */
2465 if (PreviousState
!= NULL
)
2467 ProbeForWrite(PreviousState
, BufferLength
, sizeof(ULONG
));
2468 ProbeForWrite(ReturnLength
, sizeof(ULONG
), sizeof(ULONG
));
2471 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2473 /* Return the exception code */
2474 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2480 /* This is kernel mode, we trust the caller */
2481 if (DisableAllPrivileges
== FALSE
)
2482 CapturedCount
= NewState
->PrivilegeCount
;
2485 /* Do we need to capture the new state? */
2486 if (DisableAllPrivileges
== FALSE
)
2490 /* Capture the new state array of privileges */
2491 Status
= SeCaptureLuidAndAttributesArray(NewState
->Privileges
,
2498 &CapturedPrivileges
,
2501 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2503 /* Return the exception code */
2504 Status
= _SEH2_GetExceptionCode();
2508 if (!NT_SUCCESS(Status
))
2512 /* Reference the token */
2513 Status
= ObReferenceObjectByHandle(TokenHandle
,
2514 TOKEN_ADJUST_PRIVILEGES
| (PreviousState
!= NULL
? TOKEN_QUERY
: 0),
2519 if (!NT_SUCCESS(Status
))
2521 DPRINT1("Failed to reference token (Status %lx)\n", Status
);
2523 /* Release the captured privileges */
2524 if (CapturedPrivileges
!= NULL
)
2525 SeReleaseLuidAndAttributesArray(CapturedPrivileges
,
2532 /* Lock the token */
2533 ExEnterCriticalRegionAndAcquireResourceExclusive(Token
->TokenLock
);
2535 /* Count the privileges that need to be changed, do not apply them yet */
2536 Status
= SepAdjustPrivileges(Token
,
2537 DisableAllPrivileges
,
2544 /* Check if the caller asked for the previous state */
2545 if (PreviousState
!= NULL
)
2547 /* Calculate the required length */
2548 RequiredLength
= FIELD_OFFSET(TOKEN_PRIVILEGES
, Privileges
[ChangeCount
]);
2550 /* Try to return the required buffer length */
2553 *ReturnLength
= RequiredLength
;
2555 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2557 /* Do cleanup and return the exception code */
2558 Status
= _SEH2_GetExceptionCode();
2563 /* Fail, if the buffer length is smaller than the required length */
2564 if (BufferLength
< RequiredLength
)
2566 Status
= STATUS_BUFFER_TOO_SMALL
;
2571 /* Now enter SEH, since we might return the old privileges */
2574 /* This time apply the changes */
2575 Status
= SepAdjustPrivileges(Token
,
2576 DisableAllPrivileges
,
2583 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2585 /* Do cleanup and return the exception code */
2586 Status
= _SEH2_GetExceptionCode();
2592 /* Unlock and dereference the token */
2593 ExReleaseResourceAndLeaveCriticalRegion(Token
->TokenLock
);
2594 ObDereferenceObject(Token
);
2596 /* Release the captured privileges */
2597 if (CapturedPrivileges
!= NULL
)
2598 SeReleaseLuidAndAttributesArray(CapturedPrivileges
,
2602 DPRINT ("NtAdjustPrivilegesToken() done\n");
2609 _Out_ PHANDLE TokenHandle
,
2610 _In_ ACCESS_MASK DesiredAccess
,
2611 _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes
,
2612 _In_ TOKEN_TYPE TokenType
,
2613 _In_ PLUID AuthenticationId
,
2614 _In_ PLARGE_INTEGER ExpirationTime
,
2615 _In_ PTOKEN_USER TokenUser
,
2616 _In_ PTOKEN_GROUPS TokenGroups
,
2617 _In_ PTOKEN_PRIVILEGES TokenPrivileges
,
2618 _In_opt_ PTOKEN_OWNER TokenOwner
,
2619 _In_ PTOKEN_PRIMARY_GROUP TokenPrimaryGroup
,
2620 _In_opt_ PTOKEN_DEFAULT_DACL TokenDefaultDacl
,
2621 _In_ PTOKEN_SOURCE TokenSource
)
2624 KPROCESSOR_MODE PreviousMode
;
2625 ULONG PrivilegeCount
, GroupCount
;
2626 PSID OwnerSid
, PrimaryGroupSid
;
2628 LARGE_INTEGER LocalExpirationTime
= {{0, 0}};
2629 LUID LocalAuthenticationId
;
2630 TOKEN_SOURCE LocalTokenSource
;
2631 SECURITY_QUALITY_OF_SERVICE LocalSecurityQos
;
2632 PLUID_AND_ATTRIBUTES CapturedPrivileges
= NULL
;
2633 PSID_AND_ATTRIBUTES CapturedUser
= NULL
;
2634 PSID_AND_ATTRIBUTES CapturedGroups
= NULL
;
2635 PSID CapturedOwnerSid
= NULL
;
2636 PSID CapturedPrimaryGroupSid
= NULL
;
2637 PACL CapturedDefaultDacl
= NULL
;
2638 ULONG PrivilegesLength
, UserLength
, GroupsLength
;
2643 PreviousMode
= ExGetPreviousMode();
2645 if (PreviousMode
!= KernelMode
)
2649 ProbeForWriteHandle(TokenHandle
);
2651 if (ObjectAttributes
!= NULL
)
2653 ProbeForRead(ObjectAttributes
,
2654 sizeof(OBJECT_ATTRIBUTES
),
2656 LocalSecurityQos
= *(SECURITY_QUALITY_OF_SERVICE
*)ObjectAttributes
->SecurityQualityOfService
;
2659 ProbeForRead(AuthenticationId
,
2662 LocalAuthenticationId
= *AuthenticationId
;
2664 LocalExpirationTime
= ProbeForReadLargeInteger(ExpirationTime
);
2666 ProbeForRead(TokenUser
,
2670 ProbeForRead(TokenGroups
,
2671 sizeof(TOKEN_GROUPS
),
2673 GroupCount
= TokenGroups
->GroupCount
;
2675 ProbeForRead(TokenPrivileges
,
2676 sizeof(TOKEN_PRIVILEGES
),
2678 PrivilegeCount
= TokenPrivileges
->PrivilegeCount
;
2680 if (TokenOwner
!= NULL
)
2682 ProbeForRead(TokenOwner
,
2683 sizeof(TOKEN_OWNER
),
2685 OwnerSid
= TokenOwner
->Owner
;
2692 ProbeForRead(TokenPrimaryGroup
,
2693 sizeof(TOKEN_PRIMARY_GROUP
),
2695 PrimaryGroupSid
= TokenPrimaryGroup
->PrimaryGroup
;
2697 if (TokenDefaultDacl
!= NULL
)
2699 ProbeForRead(TokenDefaultDacl
,
2700 sizeof(TOKEN_DEFAULT_DACL
),
2702 DefaultDacl
= TokenDefaultDacl
->DefaultDacl
;
2709 ProbeForRead(TokenSource
,
2710 sizeof(TOKEN_SOURCE
),
2712 LocalTokenSource
= *TokenSource
;
2714 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2716 /* Return the exception code */
2717 return _SEH2_GetExceptionCode();
2723 if (ObjectAttributes
!= NULL
)
2724 LocalSecurityQos
= *(SECURITY_QUALITY_OF_SERVICE
*)ObjectAttributes
->SecurityQualityOfService
;
2725 LocalAuthenticationId
= *AuthenticationId
;
2726 LocalExpirationTime
= *ExpirationTime
;
2727 GroupCount
= TokenGroups
->GroupCount
;
2728 PrivilegeCount
= TokenPrivileges
->PrivilegeCount
;
2729 OwnerSid
= TokenOwner
? TokenOwner
->Owner
: NULL
;
2730 PrimaryGroupSid
= TokenPrimaryGroup
->PrimaryGroup
;
2731 DefaultDacl
= TokenDefaultDacl
? TokenDefaultDacl
->DefaultDacl
: NULL
;
2732 LocalTokenSource
= *TokenSource
;
2735 /* Check token type */
2736 if ((TokenType
< TokenPrimary
) ||
2737 (TokenType
> TokenImpersonation
))
2739 return STATUS_BAD_TOKEN_TYPE
;
2742 /* Capture the user SID and attributes */
2743 Status
= SeCaptureSidAndAttributesArray(&TokenUser
->User
,
2752 if (!NT_SUCCESS(Status
))
2757 /* Capture the groups SID and attributes array */
2758 Status
= SeCaptureSidAndAttributesArray(&TokenGroups
->Groups
[0],
2767 if (!NT_SUCCESS(Status
))
2772 /* Capture privileges */
2773 Status
= SeCaptureLuidAndAttributesArray(&TokenPrivileges
->Privileges
[0],
2780 &CapturedPrivileges
,
2782 if (!NT_SUCCESS(Status
))
2787 /* Capture the token owner SID */
2788 if (TokenOwner
!= NULL
)
2790 Status
= SepCaptureSid(OwnerSid
,
2795 if (!NT_SUCCESS(Status
))
2801 /* Capture the token primary group SID */
2802 Status
= SepCaptureSid(PrimaryGroupSid
,
2806 &CapturedPrimaryGroupSid
);
2807 if (!NT_SUCCESS(Status
))
2812 /* Capture DefaultDacl */
2813 if (DefaultDacl
!= NULL
)
2815 Status
= SepCaptureAcl(DefaultDacl
,
2819 &CapturedDefaultDacl
);
2822 /* Call the internal function */
2823 Status
= SepCreateToken(&hToken
,
2828 LocalSecurityQos
.ImpersonationLevel
,
2829 &LocalAuthenticationId
,
2830 &LocalExpirationTime
,
2834 0, // FIXME: Should capture
2838 CapturedPrimaryGroupSid
,
2839 CapturedDefaultDacl
,
2842 if (NT_SUCCESS(Status
))
2846 *TokenHandle
= hToken
;
2848 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2850 Status
= _SEH2_GetExceptionCode();
2857 /* Release what we captured */
2858 SeReleaseSidAndAttributesArray(CapturedUser
, PreviousMode
, FALSE
);
2859 SeReleaseSidAndAttributesArray(CapturedGroups
, PreviousMode
, FALSE
);
2860 SeReleaseLuidAndAttributesArray(CapturedPrivileges
, PreviousMode
, FALSE
);
2861 SepReleaseSid(CapturedOwnerSid
, PreviousMode
, FALSE
);
2862 SepReleaseSid(CapturedPrimaryGroupSid
, PreviousMode
, FALSE
);
2863 SepReleaseAcl(CapturedDefaultDacl
, PreviousMode
, FALSE
);
2873 NtOpenThreadTokenEx(IN HANDLE ThreadHandle
,
2874 IN ACCESS_MASK DesiredAccess
,
2875 IN BOOLEAN OpenAsSelf
,
2876 IN ULONG HandleAttributes
,
2877 OUT PHANDLE TokenHandle
)
2879 PETHREAD Thread
, NewThread
;
2881 PTOKEN Token
, NewToken
= NULL
, PrimaryToken
;
2882 BOOLEAN CopyOnOpen
, EffectiveOnly
;
2883 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
;
2884 SE_IMPERSONATION_STATE ImpersonationState
;
2885 OBJECT_ATTRIBUTES ObjectAttributes
;
2886 SECURITY_DESCRIPTOR SecurityDescriptor
;
2888 KPROCESSOR_MODE PreviousMode
;
2890 BOOLEAN RestoreImpersonation
= FALSE
;
2894 PreviousMode
= ExGetPreviousMode();
2896 if (PreviousMode
!= KernelMode
)
2900 ProbeForWriteHandle(TokenHandle
);
2902 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2904 /* Return the exception code */
2905 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2911 * At first open the thread token for information access and verify
2912 * that the token associated with thread is valid.
2915 Status
= ObReferenceObjectByHandle(ThreadHandle
, THREAD_QUERY_INFORMATION
,
2916 PsThreadType
, PreviousMode
, (PVOID
*)&Thread
,
2918 if (!NT_SUCCESS(Status
))
2923 Token
= PsReferenceImpersonationToken(Thread
, &CopyOnOpen
, &EffectiveOnly
,
2924 &ImpersonationLevel
);
2927 ObDereferenceObject(Thread
);
2928 return STATUS_NO_TOKEN
;
2931 if (ImpersonationLevel
== SecurityAnonymous
)
2933 PsDereferenceImpersonationToken(Token
);
2934 ObDereferenceObject(Thread
);
2935 return STATUS_CANT_OPEN_ANONYMOUS
;
2939 * Revert to self if OpenAsSelf is specified.
2944 RestoreImpersonation
= PsDisableImpersonation(PsGetCurrentThread(),
2945 &ImpersonationState
);
2950 Status
= ObReferenceObjectByHandle(ThreadHandle
, THREAD_ALL_ACCESS
,
2951 PsThreadType
, KernelMode
,
2952 (PVOID
*)&NewThread
, NULL
);
2953 if (NT_SUCCESS(Status
))
2955 PrimaryToken
= PsReferencePrimaryToken(NewThread
->ThreadsProcess
);
2957 Status
= SepCreateImpersonationTokenDacl(Token
, PrimaryToken
, &Dacl
);
2959 ObFastDereferenceObject(&NewThread
->ThreadsProcess
->Token
, PrimaryToken
);
2961 if (NT_SUCCESS(Status
))
2965 RtlCreateSecurityDescriptor(&SecurityDescriptor
,
2966 SECURITY_DESCRIPTOR_REVISION
);
2967 RtlSetDaclSecurityDescriptor(&SecurityDescriptor
, TRUE
, Dacl
,
2971 InitializeObjectAttributes(&ObjectAttributes
, NULL
, HandleAttributes
,
2972 NULL
, Dacl
? &SecurityDescriptor
: NULL
);
2975 Status
= SepDuplicateToken(Token
, &ObjectAttributes
, EffectiveOnly
,
2976 TokenImpersonation
, ImpersonationLevel
,
2977 KernelMode
, &NewToken
);
2978 if (NT_SUCCESS(Status
))
2980 ObReferenceObject(NewToken
);
2981 Status
= ObInsertObject(NewToken
, NULL
, DesiredAccess
, 0, NULL
,
2989 Status
= ObOpenObjectByPointer(Token
, HandleAttributes
,
2990 NULL
, DesiredAccess
, SeTokenObjectType
,
2991 PreviousMode
, &hToken
);
2994 if (Dacl
) ExFreePoolWithTag(Dacl
, TAG_TOKEN_ACL
);
2996 if (RestoreImpersonation
)
2998 PsRestoreImpersonation(PsGetCurrentThread(), &ImpersonationState
);
3001 ObDereferenceObject(Token
);
3003 if (NT_SUCCESS(Status
) && CopyOnOpen
)
3005 PsImpersonateClient(Thread
, NewToken
, FALSE
, EffectiveOnly
, ImpersonationLevel
);
3008 if (NewToken
) ObDereferenceObject(NewToken
);
3010 if (CopyOnOpen
&& NewThread
) ObDereferenceObject(NewThread
);
3012 if (NT_SUCCESS(Status
))
3016 *TokenHandle
= hToken
;
3018 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3020 Status
= _SEH2_GetExceptionCode();
3032 NtOpenThreadToken(IN HANDLE ThreadHandle
,
3033 IN ACCESS_MASK DesiredAccess
,
3034 IN BOOLEAN OpenAsSelf
,
3035 OUT PHANDLE TokenHandle
)
3037 return NtOpenThreadTokenEx(ThreadHandle
, DesiredAccess
, OpenAsSelf
, 0,
3048 NtCompareTokens(IN HANDLE FirstTokenHandle
,
3049 IN HANDLE SecondTokenHandle
,
3052 KPROCESSOR_MODE PreviousMode
;
3053 PTOKEN FirstToken
, SecondToken
;
3059 PreviousMode
= ExGetPreviousMode();
3061 if (PreviousMode
!= KernelMode
)
3065 ProbeForWriteBoolean(Equal
);
3067 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3069 /* Return the exception code */
3070 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3075 Status
= ObReferenceObjectByHandle(FirstTokenHandle
,
3079 (PVOID
*)&FirstToken
,
3081 if (!NT_SUCCESS(Status
))
3084 Status
= ObReferenceObjectByHandle(SecondTokenHandle
,
3088 (PVOID
*)&SecondToken
,
3090 if (!NT_SUCCESS(Status
))
3092 ObDereferenceObject(FirstToken
);
3096 if (FirstToken
!= SecondToken
)
3098 Status
= SepCompareTokens(FirstToken
,
3105 ObDereferenceObject(FirstToken
);
3106 ObDereferenceObject(SecondToken
);
3108 if (NT_SUCCESS(Status
))
3114 _SEH2_EXCEPT(ExSystemExceptionFilter())
3116 Status
= _SEH2_GetExceptionCode();
3126 NtFilterToken(IN HANDLE ExistingTokenHandle
,
3128 IN PTOKEN_GROUPS SidsToDisable OPTIONAL
,
3129 IN PTOKEN_PRIVILEGES PrivilegesToDelete OPTIONAL
,
3130 IN PTOKEN_GROUPS RestrictedSids OPTIONAL
,
3131 OUT PHANDLE NewTokenHandle
)
3134 return STATUS_NOT_IMPLEMENTED
;
3142 NtImpersonateAnonymousToken(IN HANDLE Thread
)
3145 return STATUS_NOT_IMPLEMENTED
;