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 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 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;
298 /* Dereference the Token */
299 ObDereferenceObject(OldToken
);
303 RtlLengthSidAndAttributes(ULONG Count
,
304 PSID_AND_ATTRIBUTES Src
)
311 uLength
= Count
* sizeof(SID_AND_ATTRIBUTES
);
312 for (i
= 0; i
< Count
; i
++)
313 uLength
+= RtlLengthSid(Src
[i
].Sid
);
321 SepFindPrimaryGroupAndDefaultOwner(PTOKEN Token
,
327 Token
->PrimaryGroup
= 0;
331 Token
->DefaultOwnerIndex
= Token
->UserAndGroupCount
;
334 /* Validate and set the primary group and user pointers */
335 for (i
= 0; i
< Token
->UserAndGroupCount
; i
++)
338 RtlEqualSid(Token
->UserAndGroups
[i
].Sid
, DefaultOwner
))
340 Token
->DefaultOwnerIndex
= i
;
343 if (RtlEqualSid(Token
->UserAndGroups
[i
].Sid
, PrimaryGroup
))
345 Token
->PrimaryGroup
= Token
->UserAndGroups
[i
].Sid
;
349 if (Token
->DefaultOwnerIndex
== Token
->UserAndGroupCount
)
351 return(STATUS_INVALID_OWNER
);
354 if (Token
->PrimaryGroup
== 0)
356 return(STATUS_INVALID_PRIMARY_GROUP
);
359 return STATUS_SUCCESS
;
365 SepDuplicateToken(PTOKEN Token
,
366 POBJECT_ATTRIBUTES ObjectAttributes
,
367 BOOLEAN EffectiveOnly
,
368 TOKEN_TYPE TokenType
,
369 SECURITY_IMPERSONATION_LEVEL Level
,
370 KPROCESSOR_MODE PreviousMode
,
371 PTOKEN
* NewAccessToken
)
376 PTOKEN AccessToken
= NULL
;
381 Status
= ObCreateObject(PreviousMode
,
389 (PVOID
*)&AccessToken
);
390 if (!NT_SUCCESS(Status
))
392 DPRINT1("ObCreateObject() failed (Status %lx)\n", Status
);
396 /* Zero out the buffer */
397 RtlZeroMemory(AccessToken
, sizeof(TOKEN
));
399 ExAllocateLocallyUniqueId(&AccessToken
->TokenId
);
401 AccessToken
->TokenLock
= &SepTokenLock
;
403 AccessToken
->TokenType
= TokenType
;
404 AccessToken
->ImpersonationLevel
= Level
;
405 RtlCopyLuid(&AccessToken
->AuthenticationId
, &Token
->AuthenticationId
);
406 RtlCopyLuid(&AccessToken
->ModifiedId
, &Token
->ModifiedId
);
408 AccessToken
->TokenSource
.SourceIdentifier
.LowPart
= Token
->TokenSource
.SourceIdentifier
.LowPart
;
409 AccessToken
->TokenSource
.SourceIdentifier
.HighPart
= Token
->TokenSource
.SourceIdentifier
.HighPart
;
410 memcpy(AccessToken
->TokenSource
.SourceName
,
411 Token
->TokenSource
.SourceName
,
412 sizeof(Token
->TokenSource
.SourceName
));
413 AccessToken
->ExpirationTime
.QuadPart
= Token
->ExpirationTime
.QuadPart
;
414 AccessToken
->UserAndGroupCount
= Token
->UserAndGroupCount
;
415 AccessToken
->DefaultOwnerIndex
= Token
->DefaultOwnerIndex
;
417 uLength
= sizeof(SID_AND_ATTRIBUTES
) * AccessToken
->UserAndGroupCount
;
418 for (i
= 0; i
< Token
->UserAndGroupCount
; i
++)
419 uLength
+= RtlLengthSid(Token
->UserAndGroups
[i
].Sid
);
421 AccessToken
->UserAndGroups
= ExAllocatePoolWithTag(PagedPool
,
424 if (AccessToken
->UserAndGroups
== NULL
)
426 Status
= STATUS_INSUFFICIENT_RESOURCES
;
430 EndMem
= &AccessToken
->UserAndGroups
[AccessToken
->UserAndGroupCount
];
432 Status
= RtlCopySidAndAttributesArray(AccessToken
->UserAndGroupCount
,
433 Token
->UserAndGroups
,
435 AccessToken
->UserAndGroups
,
439 if (!NT_SUCCESS(Status
))
442 Status
= SepFindPrimaryGroupAndDefaultOwner(AccessToken
,
445 if (!NT_SUCCESS(Status
))
448 AccessToken
->PrivilegeCount
= Token
->PrivilegeCount
;
450 uLength
= AccessToken
->PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
);
451 AccessToken
->Privileges
= ExAllocatePoolWithTag(PagedPool
,
453 TAG_TOKEN_PRIVILAGES
);
454 if (AccessToken
->Privileges
== NULL
)
456 Status
= STATUS_INSUFFICIENT_RESOURCES
;
460 for (i
= 0; i
< AccessToken
->PrivilegeCount
; i
++)
462 RtlCopyLuid(&AccessToken
->Privileges
[i
].Luid
,
463 &Token
->Privileges
[i
].Luid
);
464 AccessToken
->Privileges
[i
].Attributes
=
465 Token
->Privileges
[i
].Attributes
;
468 if (Token
->DefaultDacl
)
470 AccessToken
->DefaultDacl
= ExAllocatePoolWithTag(PagedPool
,
471 Token
->DefaultDacl
->AclSize
,
473 if (AccessToken
->DefaultDacl
== NULL
)
475 Status
= STATUS_INSUFFICIENT_RESOURCES
;
479 memcpy(AccessToken
->DefaultDacl
,
481 Token
->DefaultDacl
->AclSize
);
484 *NewAccessToken
= AccessToken
;
486 /* Reference the logon session */
487 SepRmReferenceLogonSession(&AccessToken
->AuthenticationId
);
490 if (!NT_SUCCESS(Status
))
494 if (AccessToken
->UserAndGroups
)
495 ExFreePoolWithTag(AccessToken
->UserAndGroups
, TAG_TOKEN_USERS
);
497 if (AccessToken
->Privileges
)
498 ExFreePoolWithTag(AccessToken
->Privileges
, TAG_TOKEN_PRIVILAGES
);
500 if (AccessToken
->DefaultDacl
)
501 ExFreePoolWithTag(AccessToken
->DefaultDacl
, TAG_TOKEN_ACL
);
503 ObDereferenceObject(AccessToken
);
512 SeSubProcessToken(IN PTOKEN ParentToken
,
518 OBJECT_ATTRIBUTES ObjectAttributes
;
521 /* Initialize the attributes and duplicate it */
522 InitializeObjectAttributes(&ObjectAttributes
, NULL
, 0, NULL
, NULL
);
523 Status
= SepDuplicateToken(ParentToken
,
527 ParentToken
->ImpersonationLevel
,
530 if (NT_SUCCESS(Status
))
533 Status
= ObInsertObject(NewToken
,
539 if (NT_SUCCESS(Status
))
541 /* Set the session ID */
542 NewToken
->SessionId
= SessionId
;
543 NewToken
->TokenInUse
= InUse
;
545 /* Return the token */
556 SeIsTokenChild(IN PTOKEN Token
,
557 OUT PBOOLEAN IsChild
)
560 LUID ProcessLuid
, CallerLuid
;
565 /* Reference the process token */
566 ProcessToken
= PsReferencePrimaryToken(PsGetCurrentProcess());
569 ProcessLuid
= ProcessToken
->AuthenticationId
;
571 /* Dereference the token */
572 ObFastDereferenceObject(&PsGetCurrentProcess()->Token
, ProcessToken
);
575 CallerLuid
= Token
->AuthenticationId
;
577 /* Compare the LUIDs */
578 if (RtlEqualLuid(&CallerLuid
, &ProcessLuid
)) *IsChild
= TRUE
;
581 return STATUS_SUCCESS
;
586 SeCopyClientToken(IN PACCESS_TOKEN Token
,
587 IN SECURITY_IMPERSONATION_LEVEL Level
,
588 IN KPROCESSOR_MODE PreviousMode
,
589 OUT PACCESS_TOKEN
* NewToken
)
592 OBJECT_ATTRIBUTES ObjectAttributes
;
596 InitializeObjectAttributes(&ObjectAttributes
,
601 Status
= SepDuplicateToken(Token
,
614 SepDeleteToken(PVOID ObjectBody
)
616 PTOKEN AccessToken
= (PTOKEN
)ObjectBody
;
618 DPRINT("SepDeleteToken()\n");
620 /* Dereference the logon session */
621 SepRmDereferenceLogonSession(&AccessToken
->AuthenticationId
);
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;
715 /* Loop all groups */
716 for (i
= 0; i
< GroupCount
; i
++)
718 /* Check for mandatory groups */
719 if (Groups
[i
].Attributes
& SE_GROUP_MANDATORY
)
721 /* Force them to be enabled */
722 Groups
[i
].Attributes
|= (SE_GROUP_ENABLED
| SE_GROUP_ENABLED_BY_DEFAULT
);
725 /* Check of the group is an admin group */
726 if (RtlEqualSid(SeAliasAdminsSid
, Groups
[i
].Sid
))
728 /* Remember this so we can optimize queries later */
729 TokenFlags
|= TOKEN_HAS_ADMIN_GROUP
;
733 ExAllocateLocallyUniqueId(&TokenId
);
734 ExAllocateLocallyUniqueId(&ModifiedId
);
736 Status
= ObCreateObject(PreviousMode
,
744 (PVOID
*)&AccessToken
);
745 if (!NT_SUCCESS(Status
))
747 DPRINT1("ObCreateObject() failed (Status %lx)\n", Status
);
751 /* Zero out the buffer */
752 RtlZeroMemory(AccessToken
, sizeof(TOKEN
));
754 AccessToken
->TokenLock
= &SepTokenLock
;
756 RtlCopyLuid(&AccessToken
->TokenSource
.SourceIdentifier
,
757 &TokenSource
->SourceIdentifier
);
758 memcpy(AccessToken
->TokenSource
.SourceName
,
759 TokenSource
->SourceName
,
760 sizeof(TokenSource
->SourceName
));
762 RtlCopyLuid(&AccessToken
->TokenId
, &TokenId
);
763 RtlCopyLuid(&AccessToken
->AuthenticationId
, AuthenticationId
);
764 AccessToken
->ExpirationTime
= *ExpirationTime
;
765 RtlCopyLuid(&AccessToken
->ModifiedId
, &ModifiedId
);
767 AccessToken
->UserAndGroupCount
= GroupCount
+ 1;
768 AccessToken
->PrivilegeCount
= PrivilegeCount
;
770 AccessToken
->TokenFlags
= TokenFlags
;
771 AccessToken
->TokenType
= TokenType
;
772 AccessToken
->ImpersonationLevel
= ImpersonationLevel
;
775 * Normally we would just point these members into the variable information
776 * area; however, our ObCreateObject() call can't allocate a variable information
777 * area, so we allocate them seperately and provide a destroy function.
780 uLength
= sizeof(SID_AND_ATTRIBUTES
) * AccessToken
->UserAndGroupCount
;
781 uLength
+= RtlLengthSid(User
->Sid
);
782 for (i
= 0; i
< GroupCount
; i
++)
783 uLength
+= RtlLengthSid(Groups
[i
].Sid
);
785 // FIXME: should use the object itself
786 AccessToken
->UserAndGroups
= ExAllocatePoolWithTag(PagedPool
,
789 if (AccessToken
->UserAndGroups
== NULL
)
791 Status
= STATUS_INSUFFICIENT_RESOURCES
;
795 EndMem
= &AccessToken
->UserAndGroups
[AccessToken
->UserAndGroupCount
];
797 Status
= RtlCopySidAndAttributesArray(1,
800 AccessToken
->UserAndGroups
,
804 if (!NT_SUCCESS(Status
))
807 Status
= RtlCopySidAndAttributesArray(GroupCount
,
810 &AccessToken
->UserAndGroups
[1],
814 if (!NT_SUCCESS(Status
))
817 Status
= SepFindPrimaryGroupAndDefaultOwner(AccessToken
,
820 if (!NT_SUCCESS(Status
))
823 // FIXME: should use the object itself
824 uLength
= PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
);
825 if (uLength
== 0) uLength
= sizeof(PVOID
);
826 AccessToken
->Privileges
= ExAllocatePoolWithTag(PagedPool
,
828 TAG_TOKEN_PRIVILAGES
);
829 if (AccessToken
->Privileges
== NULL
)
831 Status
= STATUS_INSUFFICIENT_RESOURCES
;
835 if (PreviousMode
!= KernelMode
)
839 RtlCopyMemory(AccessToken
->Privileges
,
841 PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
));
843 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
845 Status
= _SEH2_GetExceptionCode();
851 RtlCopyMemory(AccessToken
->Privileges
,
853 PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
));
856 if (!NT_SUCCESS(Status
))
859 /* Update privilege flags */
860 SepUpdatePrivilegeFlagsToken(AccessToken
);
862 if (DefaultDacl
!= NULL
)
864 // FIXME: should use the object itself
865 AccessToken
->DefaultDacl
= ExAllocatePoolWithTag(PagedPool
,
866 DefaultDacl
->AclSize
,
868 if (AccessToken
->DefaultDacl
== NULL
)
870 Status
= STATUS_INSUFFICIENT_RESOURCES
;
874 RtlCopyMemory(AccessToken
->DefaultDacl
,
876 DefaultDacl
->AclSize
);
880 AccessToken
->DefaultDacl
= NULL
;
885 Status
= ObInsertObject((PVOID
)AccessToken
,
891 if (!NT_SUCCESS(Status
))
893 DPRINT1("ObInsertObject() failed (Status %lx)\n", Status
);
898 /* Return pointer instead of handle */
899 *TokenHandle
= (HANDLE
)AccessToken
;
902 /* Reference the logon session */
903 SepRmReferenceLogonSession(AuthenticationId
);
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 PSECURITY_IMPERSONATION_LEVEL SeImpersonationLvl
;
1089 if (TokenInformationClass
>= MaxTokenInfoClass
)
1091 DPRINT1("SeQueryInformationToken(%d) invalid information class\n", TokenInformationClass
);
1092 return STATUS_INVALID_INFO_CLASS
;
1095 switch (TokenInformationClass
)
1097 case TokenImpersonationLevel
:
1098 /* It is mandatory to have an impersonation token */
1099 if (((PTOKEN
)Token
)->TokenType
!= TokenImpersonation
)
1101 Status
= STATUS_INVALID_INFO_CLASS
;
1105 /* Allocate the output buffer */
1106 SeImpersonationLvl
= ExAllocatePoolWithTag(PagedPool
, sizeof(SECURITY_IMPERSONATION_LEVEL
), TAG_SE
);
1107 if (SeImpersonationLvl
== NULL
)
1109 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1113 /* Set impersonation level and return the structure */
1114 *SeImpersonationLvl
= ((PTOKEN
)Token
)->ImpersonationLevel
;
1115 *TokenInformation
= SeImpersonationLvl
;
1116 Status
= STATUS_SUCCESS
;
1121 Status
= STATUS_NOT_IMPLEMENTED
;
1133 SeQuerySessionIdToken(IN PACCESS_TOKEN Token
,
1134 IN PULONG pSessionId
)
1136 *pSessionId
= ((PTOKEN
)Token
)->SessionId
;
1137 return STATUS_SUCCESS
;
1145 SeQueryAuthenticationIdToken(IN PACCESS_TOKEN Token
,
1150 *LogonId
= ((PTOKEN
)Token
)->AuthenticationId
;
1152 return STATUS_SUCCESS
;
1159 SECURITY_IMPERSONATION_LEVEL
1161 SeTokenImpersonationLevel(IN PACCESS_TOKEN Token
)
1165 return ((PTOKEN
)Token
)->ImpersonationLevel
;
1173 SeTokenType(IN PACCESS_TOKEN Token
)
1177 return ((PTOKEN
)Token
)->TokenType
;
1186 SeTokenIsAdmin(IN PACCESS_TOKEN Token
)
1190 return (((PTOKEN
)Token
)->TokenFlags
& TOKEN_WRITE_RESTRICTED
) != 0;
1198 SeTokenIsRestricted(IN PACCESS_TOKEN Token
)
1202 return (((PTOKEN
)Token
)->TokenFlags
& TOKEN_IS_RESTRICTED
) != 0;
1210 SeTokenIsWriteRestricted(IN PACCESS_TOKEN Token
)
1214 return (((PTOKEN
)Token
)->TokenFlags
& TOKEN_HAS_RESTORE_PRIVILEGE
) != 0;
1217 /* SYSTEM CALLS ***************************************************************/
1223 NtQueryInformationToken(IN HANDLE TokenHandle
,
1224 IN TOKEN_INFORMATION_CLASS TokenInformationClass
,
1225 OUT PVOID TokenInformation
,
1226 IN ULONG TokenInformationLength
,
1227 OUT PULONG ReturnLength
)
1235 ULONG RequiredLength
;
1236 KPROCESSOR_MODE PreviousMode
;
1241 PreviousMode
= ExGetPreviousMode();
1243 /* Check buffers and class validity */
1244 Status
= DefaultQueryInfoBufferCheck(TokenInformationClass
,
1245 SeTokenInformationClass
,
1246 sizeof(SeTokenInformationClass
) / sizeof(SeTokenInformationClass
[0]),
1248 TokenInformationLength
,
1252 if (!NT_SUCCESS(Status
))
1254 DPRINT("NtQueryInformationToken() failed, Status: 0x%x\n", Status
);
1258 Status
= ObReferenceObjectByHandle(TokenHandle
,
1259 (TokenInformationClass
== TokenSource
) ? TOKEN_QUERY_SOURCE
: TOKEN_QUERY
,
1264 if (NT_SUCCESS(Status
))
1266 switch (TokenInformationClass
)
1270 PTOKEN_USER tu
= (PTOKEN_USER
)TokenInformation
;
1272 DPRINT("NtQueryInformationToken(TokenUser)\n");
1273 RequiredLength
= sizeof(TOKEN_USER
) +
1274 RtlLengthSid(Token
->UserAndGroups
[0].Sid
);
1278 if (TokenInformationLength
>= RequiredLength
)
1280 Status
= RtlCopySidAndAttributesArray(1,
1281 &Token
->UserAndGroups
[0],
1282 RequiredLength
- sizeof(TOKEN_USER
),
1290 Status
= STATUS_BUFFER_TOO_SMALL
;
1293 if (ReturnLength
!= NULL
)
1295 *ReturnLength
= RequiredLength
;
1298 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1300 Status
= _SEH2_GetExceptionCode();
1309 PTOKEN_GROUPS tg
= (PTOKEN_GROUPS
)TokenInformation
;
1311 DPRINT("NtQueryInformationToken(TokenGroups)\n");
1312 RequiredLength
= sizeof(tg
->GroupCount
) +
1313 RtlLengthSidAndAttributes(Token
->UserAndGroupCount
- 1, &Token
->UserAndGroups
[1]);
1317 if (TokenInformationLength
>= RequiredLength
)
1319 ULONG SidLen
= RequiredLength
- sizeof(tg
->GroupCount
) -
1320 ((Token
->UserAndGroupCount
- 1) * sizeof(SID_AND_ATTRIBUTES
));
1321 PSID_AND_ATTRIBUTES Sid
= (PSID_AND_ATTRIBUTES
)((ULONG_PTR
)TokenInformation
+ sizeof(tg
->GroupCount
) +
1322 ((Token
->UserAndGroupCount
- 1) * sizeof(SID_AND_ATTRIBUTES
)));
1324 tg
->GroupCount
= Token
->UserAndGroupCount
- 1;
1325 Status
= RtlCopySidAndAttributesArray(Token
->UserAndGroupCount
- 1,
1326 &Token
->UserAndGroups
[1],
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 TokenPrivileges
:
1354 PTOKEN_PRIVILEGES tp
= (PTOKEN_PRIVILEGES
)TokenInformation
;
1356 DPRINT("NtQueryInformationToken(TokenPrivileges)\n");
1357 RequiredLength
= sizeof(tp
->PrivilegeCount
) +
1358 (Token
->PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
));
1362 if (TokenInformationLength
>= RequiredLength
)
1364 tp
->PrivilegeCount
= Token
->PrivilegeCount
;
1365 RtlCopyLuidAndAttributesArray(Token
->PrivilegeCount
,
1367 &tp
->Privileges
[0]);
1371 Status
= STATUS_BUFFER_TOO_SMALL
;
1374 if (ReturnLength
!= NULL
)
1376 *ReturnLength
= RequiredLength
;
1379 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1381 Status
= _SEH2_GetExceptionCode();
1391 PTOKEN_OWNER to
= (PTOKEN_OWNER
)TokenInformation
;
1393 DPRINT("NtQueryInformationToken(TokenOwner)\n");
1394 SidLen
= RtlLengthSid(Token
->UserAndGroups
[Token
->DefaultOwnerIndex
].Sid
);
1395 RequiredLength
= sizeof(TOKEN_OWNER
) + SidLen
;
1399 if (TokenInformationLength
>= RequiredLength
)
1401 to
->Owner
= (PSID
)(to
+ 1);
1402 Status
= RtlCopySid(SidLen
,
1404 Token
->UserAndGroups
[Token
->DefaultOwnerIndex
].Sid
);
1408 Status
= STATUS_BUFFER_TOO_SMALL
;
1411 if (ReturnLength
!= NULL
)
1413 *ReturnLength
= RequiredLength
;
1416 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1418 Status
= _SEH2_GetExceptionCode();
1425 case TokenPrimaryGroup
:
1428 PTOKEN_PRIMARY_GROUP tpg
= (PTOKEN_PRIMARY_GROUP
)TokenInformation
;
1430 DPRINT("NtQueryInformationToken(TokenPrimaryGroup)\n");
1431 SidLen
= RtlLengthSid(Token
->PrimaryGroup
);
1432 RequiredLength
= sizeof(TOKEN_PRIMARY_GROUP
) + SidLen
;
1436 if (TokenInformationLength
>= RequiredLength
)
1438 tpg
->PrimaryGroup
= (PSID
)(tpg
+ 1);
1439 Status
= RtlCopySid(SidLen
,
1441 Token
->PrimaryGroup
);
1445 Status
= STATUS_BUFFER_TOO_SMALL
;
1448 if (ReturnLength
!= NULL
)
1450 *ReturnLength
= RequiredLength
;
1453 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1455 Status
= _SEH2_GetExceptionCode();
1462 case TokenDefaultDacl
:
1464 PTOKEN_DEFAULT_DACL tdd
= (PTOKEN_DEFAULT_DACL
)TokenInformation
;
1466 DPRINT("NtQueryInformationToken(TokenDefaultDacl)\n");
1467 RequiredLength
= sizeof(TOKEN_DEFAULT_DACL
);
1469 if (Token
->DefaultDacl
!= NULL
)
1471 RequiredLength
+= Token
->DefaultDacl
->AclSize
;
1476 if (TokenInformationLength
>= RequiredLength
)
1478 if (Token
->DefaultDacl
!= NULL
)
1480 tdd
->DefaultDacl
= (PACL
)(tdd
+ 1);
1481 RtlCopyMemory(tdd
->DefaultDacl
,
1483 Token
->DefaultDacl
->AclSize
);
1487 tdd
->DefaultDacl
= NULL
;
1492 Status
= STATUS_BUFFER_TOO_SMALL
;
1495 if (ReturnLength
!= NULL
)
1497 *ReturnLength
= RequiredLength
;
1500 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1502 Status
= _SEH2_GetExceptionCode();
1511 PTOKEN_SOURCE ts
= (PTOKEN_SOURCE
)TokenInformation
;
1513 DPRINT("NtQueryInformationToken(TokenSource)\n");
1514 RequiredLength
= sizeof(TOKEN_SOURCE
);
1518 if (TokenInformationLength
>= RequiredLength
)
1520 *ts
= Token
->TokenSource
;
1524 Status
= STATUS_BUFFER_TOO_SMALL
;
1527 if (ReturnLength
!= NULL
)
1529 *ReturnLength
= RequiredLength
;
1532 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1534 Status
= _SEH2_GetExceptionCode();
1543 PTOKEN_TYPE tt
= (PTOKEN_TYPE
)TokenInformation
;
1545 DPRINT("NtQueryInformationToken(TokenType)\n");
1546 RequiredLength
= sizeof(TOKEN_TYPE
);
1550 if (TokenInformationLength
>= RequiredLength
)
1552 *tt
= Token
->TokenType
;
1556 Status
= STATUS_BUFFER_TOO_SMALL
;
1559 if (ReturnLength
!= NULL
)
1561 *ReturnLength
= RequiredLength
;
1564 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1566 Status
= _SEH2_GetExceptionCode();
1573 case TokenImpersonationLevel
:
1575 PSECURITY_IMPERSONATION_LEVEL sil
= (PSECURITY_IMPERSONATION_LEVEL
)TokenInformation
;
1577 DPRINT("NtQueryInformationToken(TokenImpersonationLevel)\n");
1579 /* Fail if the token is not an impersonation token */
1580 if (Token
->TokenType
!= TokenImpersonation
)
1582 Status
= STATUS_INVALID_INFO_CLASS
;
1586 RequiredLength
= sizeof(SECURITY_IMPERSONATION_LEVEL
);
1590 if (TokenInformationLength
>= RequiredLength
)
1592 *sil
= Token
->ImpersonationLevel
;
1596 Status
= STATUS_BUFFER_TOO_SMALL
;
1599 if (ReturnLength
!= NULL
)
1601 *ReturnLength
= RequiredLength
;
1604 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1606 Status
= _SEH2_GetExceptionCode();
1613 case TokenStatistics
:
1615 PTOKEN_STATISTICS ts
= (PTOKEN_STATISTICS
)TokenInformation
;
1617 DPRINT("NtQueryInformationToken(TokenStatistics)\n");
1618 RequiredLength
= sizeof(TOKEN_STATISTICS
);
1622 if (TokenInformationLength
>= RequiredLength
)
1624 ts
->TokenId
= Token
->TokenId
;
1625 ts
->AuthenticationId
= Token
->AuthenticationId
;
1626 ts
->ExpirationTime
= Token
->ExpirationTime
;
1627 ts
->TokenType
= Token
->TokenType
;
1628 ts
->ImpersonationLevel
= Token
->ImpersonationLevel
;
1629 ts
->DynamicCharged
= Token
->DynamicCharged
;
1630 ts
->DynamicAvailable
= Token
->DynamicAvailable
;
1631 ts
->GroupCount
= Token
->UserAndGroupCount
- 1;
1632 ts
->PrivilegeCount
= Token
->PrivilegeCount
;
1633 ts
->ModifiedId
= Token
->ModifiedId
;
1637 Status
= STATUS_BUFFER_TOO_SMALL
;
1640 if (ReturnLength
!= NULL
)
1642 *ReturnLength
= RequiredLength
;
1645 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1647 Status
= _SEH2_GetExceptionCode();
1656 PTOKEN_ORIGIN to
= (PTOKEN_ORIGIN
)TokenInformation
;
1658 DPRINT("NtQueryInformationToken(TokenOrigin)\n");
1659 RequiredLength
= sizeof(TOKEN_ORIGIN
);
1663 if (TokenInformationLength
>= RequiredLength
)
1665 RtlCopyLuid(&to
->OriginatingLogonSession
,
1666 &Token
->AuthenticationId
);
1670 Status
= STATUS_BUFFER_TOO_SMALL
;
1673 if (ReturnLength
!= NULL
)
1675 *ReturnLength
= RequiredLength
;
1678 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1680 Status
= _SEH2_GetExceptionCode();
1687 case TokenGroupsAndPrivileges
:
1688 DPRINT1("NtQueryInformationToken(TokenGroupsAndPrivileges) not implemented\n");
1689 Status
= STATUS_NOT_IMPLEMENTED
;
1692 case TokenRestrictedSids
:
1694 PTOKEN_GROUPS tg
= (PTOKEN_GROUPS
)TokenInformation
;
1696 DPRINT("NtQueryInformationToken(TokenRestrictedSids)\n");
1697 RequiredLength
= sizeof(tg
->GroupCount
) +
1698 RtlLengthSidAndAttributes(Token
->RestrictedSidCount
, Token
->RestrictedSids
);
1702 if (TokenInformationLength
>= RequiredLength
)
1704 ULONG SidLen
= RequiredLength
- sizeof(tg
->GroupCount
) -
1705 (Token
->RestrictedSidCount
* sizeof(SID_AND_ATTRIBUTES
));
1706 PSID_AND_ATTRIBUTES Sid
= (PSID_AND_ATTRIBUTES
)((ULONG_PTR
)TokenInformation
+ sizeof(tg
->GroupCount
) +
1707 (Token
->RestrictedSidCount
* sizeof(SID_AND_ATTRIBUTES
)));
1709 tg
->GroupCount
= Token
->RestrictedSidCount
;
1710 Status
= RtlCopySidAndAttributesArray(Token
->RestrictedSidCount
,
1711 Token
->RestrictedSids
,
1720 Status
= STATUS_BUFFER_TOO_SMALL
;
1723 if (ReturnLength
!= NULL
)
1725 *ReturnLength
= RequiredLength
;
1728 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1730 Status
= _SEH2_GetExceptionCode();
1737 case TokenSandBoxInert
:
1738 DPRINT1("NtQueryInformationToken(TokenSandboxInert) not implemented\n");
1739 Status
= STATUS_NOT_IMPLEMENTED
;
1742 case TokenSessionId
:
1744 ULONG SessionId
= 0;
1746 DPRINT("NtQueryInformationToken(TokenSessionId)\n");
1748 Status
= SeQuerySessionIdToken(Token
,
1751 if (NT_SUCCESS(Status
))
1755 /* buffer size was already verified, no need to check here again */
1756 *(PULONG
)TokenInformation
= SessionId
;
1758 if (ReturnLength
!= NULL
)
1760 *ReturnLength
= sizeof(ULONG
);
1763 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1765 Status
= _SEH2_GetExceptionCode();
1774 DPRINT1("NtQueryInformationToken(%d) invalid information class\n", TokenInformationClass
);
1775 Status
= STATUS_INVALID_INFO_CLASS
;
1779 ObDereferenceObject(Token
);
1787 * NtSetTokenInformation: Partly implemented.
1789 * TokenOrigin, TokenDefaultDacl
1793 NtSetInformationToken(IN HANDLE TokenHandle
,
1794 IN TOKEN_INFORMATION_CLASS TokenInformationClass
,
1795 OUT PVOID TokenInformation
,
1796 IN ULONG TokenInformationLength
)
1799 KPROCESSOR_MODE PreviousMode
;
1800 ULONG NeededAccess
= TOKEN_ADJUST_DEFAULT
;
1805 PreviousMode
= ExGetPreviousMode();
1807 Status
= DefaultSetInfoBufferCheck(TokenInformationClass
,
1808 SeTokenInformationClass
,
1809 sizeof(SeTokenInformationClass
) / sizeof(SeTokenInformationClass
[0]),
1811 TokenInformationLength
,
1813 if (!NT_SUCCESS(Status
))
1815 /* Invalid buffers */
1816 DPRINT("NtSetInformationToken() failed, Status: 0x%x\n", Status
);
1820 if (TokenInformationClass
== TokenSessionId
)
1822 NeededAccess
|= TOKEN_ADJUST_SESSIONID
;
1825 Status
= ObReferenceObjectByHandle(TokenHandle
,
1831 if (NT_SUCCESS(Status
))
1833 switch (TokenInformationClass
)
1837 if (TokenInformationLength
>= sizeof(TOKEN_OWNER
))
1839 PTOKEN_OWNER to
= (PTOKEN_OWNER
)TokenInformation
;
1840 PSID InputSid
= NULL
, CapturedSid
;
1844 InputSid
= to
->Owner
;
1846 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1848 Status
= _SEH2_GetExceptionCode();
1853 Status
= SepCaptureSid(InputSid
,
1858 if (NT_SUCCESS(Status
))
1860 RtlCopySid(RtlLengthSid(CapturedSid
),
1861 Token
->UserAndGroups
[Token
->DefaultOwnerIndex
].Sid
,
1863 SepReleaseSid(CapturedSid
,
1870 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1875 case TokenPrimaryGroup
:
1877 if (TokenInformationLength
>= sizeof(TOKEN_PRIMARY_GROUP
))
1879 PTOKEN_PRIMARY_GROUP tpg
= (PTOKEN_PRIMARY_GROUP
)TokenInformation
;
1880 PSID InputSid
= NULL
, CapturedSid
;
1884 InputSid
= tpg
->PrimaryGroup
;
1886 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1888 Status
= _SEH2_GetExceptionCode();
1893 Status
= SepCaptureSid(InputSid
,
1898 if (NT_SUCCESS(Status
))
1900 RtlCopySid(RtlLengthSid(CapturedSid
),
1901 Token
->PrimaryGroup
,
1903 SepReleaseSid(CapturedSid
,
1910 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1915 case TokenDefaultDacl
:
1917 if (TokenInformationLength
>= sizeof(TOKEN_DEFAULT_DACL
))
1919 PTOKEN_DEFAULT_DACL tdd
= (PTOKEN_DEFAULT_DACL
)TokenInformation
;
1920 PACL InputAcl
= NULL
;
1924 InputAcl
= tdd
->DefaultDacl
;
1926 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1928 Status
= _SEH2_GetExceptionCode();
1933 if (InputAcl
!= NULL
)
1937 /* Capture and copy the dacl */
1938 Status
= SepCaptureAcl(InputAcl
,
1943 if (NT_SUCCESS(Status
))
1945 /* Free the previous dacl if present */
1946 if(Token
->DefaultDacl
!= NULL
)
1948 ExFreePoolWithTag(Token
->DefaultDacl
, TAG_TOKEN_ACL
);
1951 Token
->DefaultDacl
= ExAllocatePoolWithTag(PagedPool
,
1952 CapturedAcl
->AclSize
,
1954 if (!Token
->DefaultDacl
)
1956 ExFreePoolWithTag(CapturedAcl
, TAG_ACL
);
1957 Status
= STATUS_NO_MEMORY
;
1961 /* Set the new dacl */
1962 RtlCopyMemory(Token
->DefaultDacl
, CapturedAcl
, CapturedAcl
->AclSize
);
1963 ExFreePoolWithTag(CapturedAcl
, TAG_ACL
);
1969 /* Clear and free the default dacl if present */
1970 if (Token
->DefaultDacl
!= NULL
)
1972 ExFreePoolWithTag(Token
->DefaultDacl
, TAG_TOKEN_ACL
);
1973 Token
->DefaultDacl
= NULL
;
1979 Status
= STATUS_INFO_LENGTH_MISMATCH
;
1984 case TokenSessionId
:
1986 ULONG SessionId
= 0;
1990 /* Buffer size was already verified, no need to check here again */
1991 SessionId
= *(PULONG
)TokenInformation
;
1993 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1995 Status
= _SEH2_GetExceptionCode();
2000 if (!SeSinglePrivilegeCheck(SeTcbPrivilege
,
2003 Status
= STATUS_PRIVILEGE_NOT_HELD
;
2007 Token
->SessionId
= SessionId
;
2011 case TokenSessionReference
:
2013 ULONG SessionReference
;
2017 /* Buffer size was already verified, no need to check here again */
2018 SessionReference
= *(PULONG
)TokenInformation
;
2020 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2022 Status
= _SEH2_GetExceptionCode();
2027 if (!SeSinglePrivilegeCheck(SeTcbPrivilege
, PreviousMode
))
2029 Status
= STATUS_PRIVILEGE_NOT_HELD
;
2033 /* Check if it is 0 */
2034 if (SessionReference
== 0)
2036 /* Atomically set the flag in the token */
2037 RtlInterlockedSetBits(&Token
->TokenFlags
,
2038 TOKEN_SESSION_NOT_REFERENCED
);
2046 case TokenAuditPolicy
:
2048 PTOKEN_AUDIT_POLICY_INFORMATION PolicyInformation
=
2049 (PTOKEN_AUDIT_POLICY_INFORMATION
)TokenInformation
;
2050 SEP_AUDIT_POLICY AuditPolicy
;
2055 ProbeForRead(PolicyInformation
,
2056 FIELD_OFFSET(TOKEN_AUDIT_POLICY_INFORMATION
,
2057 Policies
[PolicyInformation
->PolicyCount
]),
2060 /* Loop all policies in the structure */
2061 for (i
= 0; i
< PolicyInformation
->PolicyCount
; i
++)
2063 /* Set the corresponding bits in the packed structure */
2064 switch (PolicyInformation
->Policies
[i
].Category
)
2066 case AuditCategorySystem
:
2067 AuditPolicy
.PolicyElements
.System
= PolicyInformation
->Policies
[i
].Value
;
2070 case AuditCategoryLogon
:
2071 AuditPolicy
.PolicyElements
.Logon
= PolicyInformation
->Policies
[i
].Value
;
2074 case AuditCategoryObjectAccess
:
2075 AuditPolicy
.PolicyElements
.ObjectAccess
= PolicyInformation
->Policies
[i
].Value
;
2078 case AuditCategoryPrivilegeUse
:
2079 AuditPolicy
.PolicyElements
.PrivilegeUse
= PolicyInformation
->Policies
[i
].Value
;
2082 case AuditCategoryDetailedTracking
:
2083 AuditPolicy
.PolicyElements
.DetailedTracking
= PolicyInformation
->Policies
[i
].Value
;
2086 case AuditCategoryPolicyChange
:
2087 AuditPolicy
.PolicyElements
.PolicyChange
= PolicyInformation
->Policies
[i
].Value
;
2090 case AuditCategoryAccountManagement
:
2091 AuditPolicy
.PolicyElements
.AccountManagement
= PolicyInformation
->Policies
[i
].Value
;
2094 case AuditCategoryDirectoryServiceAccess
:
2095 AuditPolicy
.PolicyElements
.DirectoryServiceAccess
= PolicyInformation
->Policies
[i
].Value
;
2098 case AuditCategoryAccountLogon
:
2099 AuditPolicy
.PolicyElements
.AccountLogon
= PolicyInformation
->Policies
[i
].Value
;
2104 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2106 Status
= _SEH2_GetExceptionCode();
2111 if (!SeSinglePrivilegeCheck(SeTcbPrivilege
,
2114 Status
= STATUS_PRIVILEGE_NOT_HELD
;
2118 /* Lock the token */
2119 SepAcquireTokenLockExclusive(Token
);
2121 /* Set the new audit policy */
2122 Token
->AuditPolicy
= AuditPolicy
;
2124 /* Unlock the token */
2125 SepReleaseTokenLock(Token
);
2132 TOKEN_ORIGIN TokenOrigin
;
2136 /* Copy the token origin */
2137 TokenOrigin
= *(PTOKEN_ORIGIN
)TokenInformation
;
2139 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2141 Status
= _SEH2_GetExceptionCode();
2146 /* Check for TCB privilege */
2147 if (!SeSinglePrivilegeCheck(SeTcbPrivilege
, PreviousMode
))
2149 Status
= STATUS_PRIVILEGE_NOT_HELD
;
2153 /* Lock the token */
2154 SepAcquireTokenLockExclusive(Token
);
2156 /* Check if there is no token origin set yet */
2157 if ((Token
->OriginatingLogonSession
.LowPart
== 0) &&
2158 (Token
->OriginatingLogonSession
.HighPart
== 0))
2160 /* Set the token origin */
2161 Token
->OriginatingLogonSession
=
2162 TokenOrigin
.OriginatingLogonSession
;
2165 /* Unlock the token */
2166 SepReleaseTokenLock(Token
);
2173 DPRINT1("Invalid TokenInformationClass: 0x%lx\n",
2174 TokenInformationClass
);
2175 Status
= STATUS_INVALID_INFO_CLASS
;
2180 ObDereferenceObject(Token
);
2183 if (!NT_SUCCESS(Status
))
2185 DPRINT1("NtSetInformationToken failed with Status 0x%lx\n", Status
);
2195 * NOTE: Some sources claim 4th param is ImpersonationLevel, but on W2K
2196 * this is certainly NOT true, thou i can't say for sure that EffectiveOnly
2197 * is correct either. -Gunnar
2198 * This is true. EffectiveOnly overrides SQOS.EffectiveOnly. - IAI
2201 NtDuplicateToken(IN HANDLE ExistingTokenHandle
,
2202 IN ACCESS_MASK DesiredAccess
,
2203 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
2204 IN BOOLEAN EffectiveOnly
,
2205 IN TOKEN_TYPE TokenType
,
2206 OUT PHANDLE NewTokenHandle
)
2208 KPROCESSOR_MODE PreviousMode
;
2212 PSECURITY_QUALITY_OF_SERVICE CapturedSecurityQualityOfService
;
2214 OBJECT_HANDLE_INFORMATION HandleInformation
;
2219 if (TokenType
!= TokenImpersonation
&&
2220 TokenType
!= TokenPrimary
)
2221 return STATUS_INVALID_PARAMETER
;
2223 PreviousMode
= KeGetPreviousMode();
2225 if (PreviousMode
!= KernelMode
)
2229 ProbeForWriteHandle(NewTokenHandle
);
2231 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2233 /* Return the exception code */
2234 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2239 Status
= SepCaptureSecurityQualityOfService(ObjectAttributes
,
2243 &CapturedSecurityQualityOfService
,
2245 if (!NT_SUCCESS(Status
))
2247 DPRINT1("NtDuplicateToken() failed to capture QoS! Status: 0x%x\n", Status
);
2251 Status
= ObReferenceObjectByHandle(ExistingTokenHandle
,
2256 &HandleInformation
);
2257 if (!NT_SUCCESS(Status
))
2259 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService
,
2266 * Fail, if the original token is an impersonation token and the caller
2267 * tries to raise the impersonation level of the new token above the
2268 * impersonation level of the original token.
2270 if (Token
->TokenType
== TokenImpersonation
)
2273 CapturedSecurityQualityOfService
->ImpersonationLevel
>Token
->ImpersonationLevel
)
2275 ObDereferenceObject(Token
);
2276 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService
,
2279 return STATUS_BAD_IMPERSONATION_LEVEL
;
2284 * Fail, if a primary token is to be created from an impersonation token
2285 * and and the impersonation level of the impersonation token is below SecurityImpersonation.
2287 if (Token
->TokenType
== TokenImpersonation
&&
2288 TokenType
== TokenPrimary
&&
2289 Token
->ImpersonationLevel
< SecurityImpersonation
)
2291 ObDereferenceObject(Token
);
2292 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService
,
2295 return STATUS_BAD_IMPERSONATION_LEVEL
;
2298 Status
= SepDuplicateToken(Token
,
2302 (QoSPresent
? CapturedSecurityQualityOfService
->ImpersonationLevel
: SecurityAnonymous
),
2306 ObDereferenceObject(Token
);
2308 if (NT_SUCCESS(Status
))
2310 Status
= ObInsertObject((PVOID
)NewToken
,
2312 (DesiredAccess
? DesiredAccess
: HandleInformation
.GrantedAccess
),
2316 if (NT_SUCCESS(Status
))
2320 *NewTokenHandle
= hToken
;
2322 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2324 Status
= _SEH2_GetExceptionCode();
2330 /* Free the captured structure */
2331 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService
,
2339 NtAdjustGroupsToken(IN HANDLE TokenHandle
,
2340 IN BOOLEAN ResetToDefault
,
2341 IN PTOKEN_GROUPS NewState
,
2342 IN ULONG BufferLength
,
2343 OUT PTOKEN_GROUPS PreviousState OPTIONAL
,
2344 OUT PULONG ReturnLength
)
2347 return(STATUS_NOT_IMPLEMENTED
);
2353 SepAdjustPrivileges(
2354 _Inout_ PTOKEN Token
,
2355 _In_ BOOLEAN DisableAllPrivileges
,
2356 _In_opt_ PLUID_AND_ATTRIBUTES NewState
,
2357 _In_ ULONG NewStateCount
,
2358 _Out_opt_ PTOKEN_PRIVILEGES PreviousState
,
2359 _In_ BOOLEAN ApplyChanges
,
2360 _Out_ PULONG ChangedPrivileges
)
2362 ULONG i
, j
, PrivilegeCount
, ChangeCount
, NewAttributes
;
2364 /* Count the found privileges and those that need to be changed */
2368 /* Loop all privileges in the token */
2369 for (i
= 0; i
< Token
->PrivilegeCount
; i
++)
2371 /* Shall all of them be disabled? */
2372 if (DisableAllPrivileges
)
2374 /* The new attributes are the old ones, but disabled */
2375 NewAttributes
= Token
->Privileges
[i
].Attributes
& ~SE_PRIVILEGE_ENABLED
;
2379 /* Otherwise loop all provided privileges */
2380 for (j
= 0; j
< NewStateCount
; j
++)
2382 /* Check if this is the LUID we are looking for */
2383 if (RtlEqualLuid(&Token
->Privileges
[i
].Luid
, &NewState
[j
].Luid
))
2385 DPRINT("Found privilege\n");
2387 /* Copy SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_REMOVED */
2388 NewAttributes
= NewState
[j
].Attributes
;
2389 NewAttributes
&= (SE_PRIVILEGE_ENABLED
| SE_PRIVILEGE_REMOVED
);
2390 NewAttributes
|= Token
->Privileges
[i
].Attributes
& ~SE_PRIVILEGE_ENABLED
;
2397 /* Check if we didn't find the privilege */
2398 if (j
== NewStateCount
)
2400 /* Continue with the token's next privilege */
2405 /* We found a privilege, count it */
2408 /* Does the privilege need to be changed? */
2409 if (Token
->Privileges
[i
].Attributes
!= NewAttributes
)
2411 /* Does the caller want the old privileges? */
2412 if (PreviousState
!= NULL
)
2414 /* Copy the old privilege */
2415 PreviousState
->Privileges
[ChangeCount
] = Token
->Privileges
[i
];
2418 /* Does the caller want to apply the changes? */
2421 /* Shall we remove the privilege? */
2422 if (NewAttributes
& SE_PRIVILEGE_REMOVED
)
2424 /* Set the token as disabled and update flags for it */
2425 Token
->Privileges
[i
].Attributes
&= ~SE_PRIVILEGE_ENABLED
;
2426 SepUpdateSinglePrivilegeFlagToken(Token
, i
);
2428 /* Remove the privilege */
2429 SepRemovePrivilegeToken(Token
, i
);
2431 /* Fix the running index */
2434 /* Continue with next */
2438 /* Set the new attributes and update flags */
2439 Token
->Privileges
[i
].Attributes
= NewAttributes
;
2440 SepUpdateSinglePrivilegeFlagToken(Token
, i
);
2443 /* Increment the change count */
2448 /* Set the number of saved privileges */
2449 if (PreviousState
!= NULL
)
2450 PreviousState
->PrivilegeCount
= ChangeCount
;
2452 /* Return the number of changed privileges */
2453 *ChangedPrivileges
= ChangeCount
;
2455 /* Check if we missed some */
2456 if (!DisableAllPrivileges
&& (PrivilegeCount
< NewStateCount
))
2458 return STATUS_NOT_ALL_ASSIGNED
;
2461 return STATUS_SUCCESS
;
2468 _Must_inspect_result_
2472 NtAdjustPrivilegesToken(
2473 _In_ HANDLE TokenHandle
,
2474 _In_ BOOLEAN DisableAllPrivileges
,
2475 _In_opt_ PTOKEN_PRIVILEGES NewState
,
2476 _In_ ULONG BufferLength
,
2477 _Out_writes_bytes_to_opt_(BufferLength
,*ReturnLength
)
2478 PTOKEN_PRIVILEGES PreviousState
,
2479 _When_(PreviousState
!=NULL
, _Out_
) PULONG ReturnLength
)
2481 PLUID_AND_ATTRIBUTES CapturedPrivileges
= NULL
;
2482 KPROCESSOR_MODE PreviousMode
;
2483 ULONG CapturedCount
= 0;
2484 ULONG CapturedLength
= 0;
2485 ULONG NewStateSize
= 0;
2487 ULONG RequiredLength
;
2492 DPRINT("NtAdjustPrivilegesToken() called\n");
2494 /* Fail, if we do not disable all privileges but NewState is NULL */
2495 if (DisableAllPrivileges
== FALSE
&& NewState
== NULL
)
2496 return STATUS_INVALID_PARAMETER
;
2498 PreviousMode
= KeGetPreviousMode ();
2499 if (PreviousMode
!= KernelMode
)
2503 /* Probe NewState */
2504 if (DisableAllPrivileges
== FALSE
)
2506 /* First probe the header */
2507 ProbeForRead(NewState
, sizeof(TOKEN_PRIVILEGES
), sizeof(ULONG
));
2509 CapturedCount
= NewState
->PrivilegeCount
;
2510 NewStateSize
= FIELD_OFFSET(TOKEN_PRIVILEGES
, Privileges
[CapturedCount
]);
2512 ProbeForRead(NewState
, NewStateSize
, sizeof(ULONG
));
2515 /* Probe PreviousState and ReturnLength */
2516 if (PreviousState
!= NULL
)
2518 ProbeForWrite(PreviousState
, BufferLength
, sizeof(ULONG
));
2519 ProbeForWrite(ReturnLength
, sizeof(ULONG
), sizeof(ULONG
));
2522 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2524 /* Return the exception code */
2525 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2531 /* This is kernel mode, we trust the caller */
2532 if (DisableAllPrivileges
== FALSE
)
2533 CapturedCount
= NewState
->PrivilegeCount
;
2536 /* Do we need to capture the new state? */
2537 if (DisableAllPrivileges
== FALSE
)
2541 /* Capture the new state array of privileges */
2542 Status
= SeCaptureLuidAndAttributesArray(NewState
->Privileges
,
2549 &CapturedPrivileges
,
2552 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2554 /* Return the exception code */
2555 Status
= _SEH2_GetExceptionCode();
2559 if (!NT_SUCCESS(Status
))
2563 /* Reference the token */
2564 Status
= ObReferenceObjectByHandle(TokenHandle
,
2565 TOKEN_ADJUST_PRIVILEGES
| (PreviousState
!= NULL
? TOKEN_QUERY
: 0),
2570 if (!NT_SUCCESS(Status
))
2572 DPRINT1("Failed to reference token (Status %lx)\n", Status
);
2574 /* Release the captured privileges */
2575 if (CapturedPrivileges
!= NULL
)
2576 SeReleaseLuidAndAttributesArray(CapturedPrivileges
,
2583 /* Lock the token */
2584 ExEnterCriticalRegionAndAcquireResourceExclusive(Token
->TokenLock
);
2586 /* Count the privileges that need to be changed, do not apply them yet */
2587 Status
= SepAdjustPrivileges(Token
,
2588 DisableAllPrivileges
,
2595 /* Check if the caller asked for the previous state */
2596 if (PreviousState
!= NULL
)
2598 /* Calculate the required length */
2599 RequiredLength
= FIELD_OFFSET(TOKEN_PRIVILEGES
, Privileges
[ChangeCount
]);
2601 /* Try to return the required buffer length */
2604 *ReturnLength
= RequiredLength
;
2606 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2608 /* Do cleanup and return the exception code */
2609 Status
= _SEH2_GetExceptionCode();
2614 /* Fail, if the buffer length is smaller than the required length */
2615 if (BufferLength
< RequiredLength
)
2617 Status
= STATUS_BUFFER_TOO_SMALL
;
2622 /* Now enter SEH, since we might return the old privileges */
2625 /* This time apply the changes */
2626 Status
= SepAdjustPrivileges(Token
,
2627 DisableAllPrivileges
,
2634 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2636 /* Do cleanup and return the exception code */
2637 Status
= _SEH2_GetExceptionCode();
2643 /* Unlock and dereference the token */
2644 ExReleaseResourceAndLeaveCriticalRegion(Token
->TokenLock
);
2645 ObDereferenceObject(Token
);
2647 /* Release the captured privileges */
2648 if (CapturedPrivileges
!= NULL
)
2649 SeReleaseLuidAndAttributesArray(CapturedPrivileges
,
2653 DPRINT ("NtAdjustPrivilegesToken() done\n");
2660 _Out_ PHANDLE TokenHandle
,
2661 _In_ ACCESS_MASK DesiredAccess
,
2662 _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes
,
2663 _In_ TOKEN_TYPE TokenType
,
2664 _In_ PLUID AuthenticationId
,
2665 _In_ PLARGE_INTEGER ExpirationTime
,
2666 _In_ PTOKEN_USER TokenUser
,
2667 _In_ PTOKEN_GROUPS TokenGroups
,
2668 _In_ PTOKEN_PRIVILEGES TokenPrivileges
,
2669 _In_opt_ PTOKEN_OWNER TokenOwner
,
2670 _In_ PTOKEN_PRIMARY_GROUP TokenPrimaryGroup
,
2671 _In_opt_ PTOKEN_DEFAULT_DACL TokenDefaultDacl
,
2672 _In_ PTOKEN_SOURCE TokenSource
)
2675 KPROCESSOR_MODE PreviousMode
;
2676 ULONG PrivilegeCount
, GroupCount
;
2677 PSID OwnerSid
, PrimaryGroupSid
;
2679 LARGE_INTEGER LocalExpirationTime
= {{0, 0}};
2680 LUID LocalAuthenticationId
;
2681 TOKEN_SOURCE LocalTokenSource
;
2682 SECURITY_QUALITY_OF_SERVICE LocalSecurityQos
;
2683 PLUID_AND_ATTRIBUTES CapturedPrivileges
= NULL
;
2684 PSID_AND_ATTRIBUTES CapturedUser
= NULL
;
2685 PSID_AND_ATTRIBUTES CapturedGroups
= NULL
;
2686 PSID CapturedOwnerSid
= NULL
;
2687 PSID CapturedPrimaryGroupSid
= NULL
;
2688 PACL CapturedDefaultDacl
= NULL
;
2689 ULONG PrivilegesLength
, UserLength
, GroupsLength
;
2694 PreviousMode
= ExGetPreviousMode();
2696 if (PreviousMode
!= KernelMode
)
2700 ProbeForWriteHandle(TokenHandle
);
2702 if (ObjectAttributes
!= NULL
)
2704 ProbeForRead(ObjectAttributes
,
2705 sizeof(OBJECT_ATTRIBUTES
),
2707 LocalSecurityQos
= *(SECURITY_QUALITY_OF_SERVICE
*)ObjectAttributes
->SecurityQualityOfService
;
2710 ProbeForRead(AuthenticationId
,
2713 LocalAuthenticationId
= *AuthenticationId
;
2715 LocalExpirationTime
= ProbeForReadLargeInteger(ExpirationTime
);
2717 ProbeForRead(TokenUser
,
2721 ProbeForRead(TokenGroups
,
2722 sizeof(TOKEN_GROUPS
),
2724 GroupCount
= TokenGroups
->GroupCount
;
2726 ProbeForRead(TokenPrivileges
,
2727 sizeof(TOKEN_PRIVILEGES
),
2729 PrivilegeCount
= TokenPrivileges
->PrivilegeCount
;
2731 if (TokenOwner
!= NULL
)
2733 ProbeForRead(TokenOwner
,
2734 sizeof(TOKEN_OWNER
),
2736 OwnerSid
= TokenOwner
->Owner
;
2743 ProbeForRead(TokenPrimaryGroup
,
2744 sizeof(TOKEN_PRIMARY_GROUP
),
2746 PrimaryGroupSid
= TokenPrimaryGroup
->PrimaryGroup
;
2748 if (TokenDefaultDacl
!= NULL
)
2750 ProbeForRead(TokenDefaultDacl
,
2751 sizeof(TOKEN_DEFAULT_DACL
),
2753 DefaultDacl
= TokenDefaultDacl
->DefaultDacl
;
2760 ProbeForRead(TokenSource
,
2761 sizeof(TOKEN_SOURCE
),
2763 LocalTokenSource
= *TokenSource
;
2765 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2767 /* Return the exception code */
2768 return _SEH2_GetExceptionCode();
2774 if (ObjectAttributes
!= NULL
)
2775 LocalSecurityQos
= *(SECURITY_QUALITY_OF_SERVICE
*)ObjectAttributes
->SecurityQualityOfService
;
2776 LocalAuthenticationId
= *AuthenticationId
;
2777 LocalExpirationTime
= *ExpirationTime
;
2778 GroupCount
= TokenGroups
->GroupCount
;
2779 PrivilegeCount
= TokenPrivileges
->PrivilegeCount
;
2780 OwnerSid
= TokenOwner
? TokenOwner
->Owner
: NULL
;
2781 PrimaryGroupSid
= TokenPrimaryGroup
->PrimaryGroup
;
2782 DefaultDacl
= TokenDefaultDacl
? TokenDefaultDacl
->DefaultDacl
: NULL
;
2783 LocalTokenSource
= *TokenSource
;
2786 /* Check token type */
2787 if ((TokenType
< TokenPrimary
) ||
2788 (TokenType
> TokenImpersonation
))
2790 return STATUS_BAD_TOKEN_TYPE
;
2793 /* Capture the user SID and attributes */
2794 Status
= SeCaptureSidAndAttributesArray(&TokenUser
->User
,
2803 if (!NT_SUCCESS(Status
))
2808 /* Capture the groups SID and attributes array */
2809 Status
= SeCaptureSidAndAttributesArray(&TokenGroups
->Groups
[0],
2818 if (!NT_SUCCESS(Status
))
2823 /* Capture privileges */
2824 Status
= SeCaptureLuidAndAttributesArray(&TokenPrivileges
->Privileges
[0],
2831 &CapturedPrivileges
,
2833 if (!NT_SUCCESS(Status
))
2838 /* Capture the token owner SID */
2839 if (TokenOwner
!= NULL
)
2841 Status
= SepCaptureSid(OwnerSid
,
2846 if (!NT_SUCCESS(Status
))
2852 /* Capture the token primary group SID */
2853 Status
= SepCaptureSid(PrimaryGroupSid
,
2857 &CapturedPrimaryGroupSid
);
2858 if (!NT_SUCCESS(Status
))
2863 /* Capture DefaultDacl */
2864 if (DefaultDacl
!= NULL
)
2866 Status
= SepCaptureAcl(DefaultDacl
,
2870 &CapturedDefaultDacl
);
2871 if (!NT_SUCCESS(Status
))
2877 /* Call the internal function */
2878 Status
= SepCreateToken(&hToken
,
2883 LocalSecurityQos
.ImpersonationLevel
,
2884 &LocalAuthenticationId
,
2885 &LocalExpirationTime
,
2889 0, // FIXME: Should capture
2893 CapturedPrimaryGroupSid
,
2894 CapturedDefaultDacl
,
2897 if (NT_SUCCESS(Status
))
2901 *TokenHandle
= hToken
;
2903 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2905 Status
= _SEH2_GetExceptionCode();
2912 /* Release what we captured */
2913 SeReleaseSidAndAttributesArray(CapturedUser
, PreviousMode
, FALSE
);
2914 SeReleaseSidAndAttributesArray(CapturedGroups
, PreviousMode
, FALSE
);
2915 SeReleaseLuidAndAttributesArray(CapturedPrivileges
, PreviousMode
, FALSE
);
2916 SepReleaseSid(CapturedOwnerSid
, PreviousMode
, FALSE
);
2917 SepReleaseSid(CapturedPrimaryGroupSid
, PreviousMode
, FALSE
);
2918 SepReleaseAcl(CapturedDefaultDacl
, PreviousMode
, FALSE
);
2928 NtOpenThreadTokenEx(IN HANDLE ThreadHandle
,
2929 IN ACCESS_MASK DesiredAccess
,
2930 IN BOOLEAN OpenAsSelf
,
2931 IN ULONG HandleAttributes
,
2932 OUT PHANDLE TokenHandle
)
2934 PETHREAD Thread
, NewThread
;
2936 PTOKEN Token
, NewToken
= NULL
, PrimaryToken
;
2937 BOOLEAN CopyOnOpen
, EffectiveOnly
;
2938 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
;
2939 SE_IMPERSONATION_STATE ImpersonationState
;
2940 OBJECT_ATTRIBUTES ObjectAttributes
;
2941 SECURITY_DESCRIPTOR SecurityDescriptor
;
2943 KPROCESSOR_MODE PreviousMode
;
2945 BOOLEAN RestoreImpersonation
= FALSE
;
2949 PreviousMode
= ExGetPreviousMode();
2951 if (PreviousMode
!= KernelMode
)
2955 ProbeForWriteHandle(TokenHandle
);
2957 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2959 /* Return the exception code */
2960 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2965 /* Validate object attributes */
2966 HandleAttributes
= ObpValidateAttributes(HandleAttributes
, PreviousMode
);
2969 * At first open the thread token for information access and verify
2970 * that the token associated with thread is valid. */
2972 Status
= ObReferenceObjectByHandle(ThreadHandle
, THREAD_QUERY_INFORMATION
,
2973 PsThreadType
, PreviousMode
, (PVOID
*)&Thread
,
2975 if (!NT_SUCCESS(Status
))
2980 Token
= PsReferenceImpersonationToken(Thread
, &CopyOnOpen
, &EffectiveOnly
,
2981 &ImpersonationLevel
);
2984 ObDereferenceObject(Thread
);
2985 return STATUS_NO_TOKEN
;
2988 if (ImpersonationLevel
== SecurityAnonymous
)
2990 PsDereferenceImpersonationToken(Token
);
2991 ObDereferenceObject(Thread
);
2992 return STATUS_CANT_OPEN_ANONYMOUS
;
2996 * Revert to self if OpenAsSelf is specified.
3001 RestoreImpersonation
= PsDisableImpersonation(PsGetCurrentThread(),
3002 &ImpersonationState
);
3007 Status
= ObReferenceObjectByHandle(ThreadHandle
, THREAD_ALL_ACCESS
,
3008 PsThreadType
, KernelMode
,
3009 (PVOID
*)&NewThread
, NULL
);
3010 if (NT_SUCCESS(Status
))
3012 PrimaryToken
= PsReferencePrimaryToken(NewThread
->ThreadsProcess
);
3014 Status
= SepCreateImpersonationTokenDacl(Token
, PrimaryToken
, &Dacl
);
3016 ObFastDereferenceObject(&NewThread
->ThreadsProcess
->Token
, PrimaryToken
);
3018 if (NT_SUCCESS(Status
))
3022 RtlCreateSecurityDescriptor(&SecurityDescriptor
,
3023 SECURITY_DESCRIPTOR_REVISION
);
3024 RtlSetDaclSecurityDescriptor(&SecurityDescriptor
, TRUE
, Dacl
,
3028 InitializeObjectAttributes(&ObjectAttributes
, NULL
, HandleAttributes
,
3029 NULL
, Dacl
? &SecurityDescriptor
: NULL
);
3032 Status
= SepDuplicateToken(Token
, &ObjectAttributes
, EffectiveOnly
,
3033 TokenImpersonation
, ImpersonationLevel
,
3034 KernelMode
, &NewToken
);
3035 if (NT_SUCCESS(Status
))
3037 ObReferenceObject(NewToken
);
3038 Status
= ObInsertObject(NewToken
, NULL
, DesiredAccess
, 0, NULL
,
3046 Status
= ObOpenObjectByPointer(Token
, HandleAttributes
,
3047 NULL
, DesiredAccess
, SeTokenObjectType
,
3048 PreviousMode
, &hToken
);
3051 if (Dacl
) ExFreePoolWithTag(Dacl
, TAG_TOKEN_ACL
);
3053 if (RestoreImpersonation
)
3055 PsRestoreImpersonation(PsGetCurrentThread(), &ImpersonationState
);
3058 ObDereferenceObject(Token
);
3060 if (NT_SUCCESS(Status
) && CopyOnOpen
)
3062 PsImpersonateClient(Thread
, NewToken
, FALSE
, EffectiveOnly
, ImpersonationLevel
);
3065 if (NewToken
) ObDereferenceObject(NewToken
);
3067 if (CopyOnOpen
&& NewThread
) ObDereferenceObject(NewThread
);
3069 ObDereferenceObject(Thread
);
3071 if (NT_SUCCESS(Status
))
3075 *TokenHandle
= hToken
;
3077 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3079 Status
= _SEH2_GetExceptionCode();
3091 NtOpenThreadToken(IN HANDLE ThreadHandle
,
3092 IN ACCESS_MASK DesiredAccess
,
3093 IN BOOLEAN OpenAsSelf
,
3094 OUT PHANDLE TokenHandle
)
3096 return NtOpenThreadTokenEx(ThreadHandle
, DesiredAccess
, OpenAsSelf
, 0,
3107 NtCompareTokens(IN HANDLE FirstTokenHandle
,
3108 IN HANDLE SecondTokenHandle
,
3111 KPROCESSOR_MODE PreviousMode
;
3112 PTOKEN FirstToken
, SecondToken
;
3118 PreviousMode
= ExGetPreviousMode();
3120 if (PreviousMode
!= KernelMode
)
3124 ProbeForWriteBoolean(Equal
);
3126 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3128 /* Return the exception code */
3129 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3134 Status
= ObReferenceObjectByHandle(FirstTokenHandle
,
3138 (PVOID
*)&FirstToken
,
3140 if (!NT_SUCCESS(Status
))
3143 Status
= ObReferenceObjectByHandle(SecondTokenHandle
,
3147 (PVOID
*)&SecondToken
,
3149 if (!NT_SUCCESS(Status
))
3151 ObDereferenceObject(FirstToken
);
3155 if (FirstToken
!= SecondToken
)
3157 Status
= SepCompareTokens(FirstToken
,
3164 ObDereferenceObject(FirstToken
);
3165 ObDereferenceObject(SecondToken
);
3167 if (NT_SUCCESS(Status
))
3173 _SEH2_EXCEPT(ExSystemExceptionFilter())
3175 Status
= _SEH2_GetExceptionCode();
3185 NtFilterToken(IN HANDLE ExistingTokenHandle
,
3187 IN PTOKEN_GROUPS SidsToDisable OPTIONAL
,
3188 IN PTOKEN_PRIVILEGES PrivilegesToDelete OPTIONAL
,
3189 IN PTOKEN_GROUPS RestrictedSids OPTIONAL
,
3190 OUT PHANDLE NewTokenHandle
)
3193 return STATUS_NOT_IMPLEMENTED
;
3201 NtImpersonateAnonymousToken(IN HANDLE Thread
)
3204 return STATUS_NOT_IMPLEMENTED
;