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
; // FIXME: Global lock!
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 MS! */
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 /* Lock the tokens */
101 SepAcquireTokenLockShared(FirstToken
);
102 SepAcquireTokenLockShared(SecondToken
);
104 /* FIXME: Check if every SID that is present in either token is also present in the other one */
106 Restricted
= SeTokenIsRestricted(FirstToken
);
107 if (Restricted
== SeTokenIsRestricted(SecondToken
))
111 /* FIXME: Check if every SID that is restricted in either token is also restricted in the other one */
114 /* FIXME: Check if every privilege that is present in either token is also present in the other one */
115 DPRINT1("FIXME: Pretending tokens are equal!\n");
119 /* Unlock the tokens */
120 SepReleaseTokenLock(SecondToken
);
121 SepReleaseTokenLock(FirstToken
);
124 return STATUS_SUCCESS
;
129 SepUpdateSinglePrivilegeFlagToken(
130 _Inout_ PTOKEN Token
,
134 ASSERT(Index
< Token
->PrivilegeCount
);
136 /* The high part of all values we are interested in is 0 */
137 if (Token
->Privileges
[Index
].Luid
.HighPart
!= 0)
142 /* Check for certain privileges to update flags */
143 if (Token
->Privileges
[Index
].Luid
.LowPart
== SE_CHANGE_NOTIFY_PRIVILEGE
)
145 TokenFlag
= TOKEN_HAS_TRAVERSE_PRIVILEGE
;
147 else if (Token
->Privileges
[Index
].Luid
.LowPart
== SE_BACKUP_PRIVILEGE
)
149 TokenFlag
= TOKEN_HAS_BACKUP_PRIVILEGE
;
151 else if (Token
->Privileges
[Index
].Luid
.LowPart
== SE_RESTORE_PRIVILEGE
)
153 TokenFlag
= TOKEN_HAS_RESTORE_PRIVILEGE
;
155 else if (Token
->Privileges
[Index
].Luid
.LowPart
== SE_IMPERSONATE_PRIVILEGE
)
157 TokenFlag
= TOKEN_HAS_IMPERSONATE_PRIVILEGE
;
165 /* Check if the specified privilege is enabled */
166 if (Token
->Privileges
[Index
].Attributes
& SE_PRIVILEGE_ENABLED
)
168 /* It is enabled, so set the flag */
169 Token
->TokenFlags
|= TokenFlag
;
173 /* Is is disabled, so remove the flag */
174 Token
->TokenFlags
&= ~TokenFlag
;
180 SepUpdatePrivilegeFlagsToken(
181 _Inout_ PTOKEN Token
)
185 /* Loop all privileges */
186 for (i
= 0; i
< Token
->PrivilegeCount
; i
++)
188 /* Updates the flags dor this privilege */
189 SepUpdateSinglePrivilegeFlagToken(Token
, i
);
195 SepRemovePrivilegeToken(
196 _Inout_ PTOKEN Token
,
200 ASSERT(Index
< Token
->PrivilegeCount
);
202 /* Calculate the number of trailing privileges */
203 MoveCount
= Token
->PrivilegeCount
- Index
- 1;
206 /* Move them one location ahead */
207 RtlMoveMemory(&Token
->Privileges
[Index
],
208 &Token
->Privileges
[Index
+ 1],
209 MoveCount
* sizeof(LUID_AND_ATTRIBUTES
));
212 /* Update privilege count */
213 Token
->PrivilegeCount
--;
218 SepFreeProxyData(PVOID ProxyData
)
225 SepCopyProxyData(PVOID
* Dest
,
229 return STATUS_NOT_IMPLEMENTED
;
234 SeExchangePrimaryToken(
235 _In_ PEPROCESS Process
,
236 _In_ PACCESS_TOKEN NewAccessToken
,
237 _Out_ PACCESS_TOKEN
* OldAccessToken
)
240 PTOKEN NewToken
= (PTOKEN
)NewAccessToken
;
244 if (NewToken
->TokenType
!= TokenPrimary
)
245 return STATUS_BAD_TOKEN_TYPE
;
247 if (NewToken
->TokenInUse
)
252 /* Maybe we're trying to set the same token */
253 OldToken
= PsReferencePrimaryToken(Process
);
254 if (OldToken
== NewToken
)
257 *OldAccessToken
= OldToken
;
258 return STATUS_SUCCESS
;
261 Status
= SepCompareTokens(OldToken
, NewToken
, &IsEqual
);
262 if (!NT_SUCCESS(Status
))
264 PsDereferencePrimaryToken(OldToken
);
265 *OldAccessToken
= NULL
;
271 PsDereferencePrimaryToken(OldToken
);
272 *OldAccessToken
= NULL
;
273 return STATUS_TOKEN_ALREADY_IN_USE
;
275 /* Silently return STATUS_SUCCESS but do not set the new token,
276 * as it's already in use elsewhere. */
277 *OldAccessToken
= OldToken
;
278 return STATUS_SUCCESS
;
281 /* Lock the new token */
282 SepAcquireTokenLockExclusive(NewToken
);
284 /* Mark new token in use */
285 NewToken
->TokenInUse
= TRUE
;
287 // TODO: Set a correct SessionId for NewToken
289 /* Unlock the new token */
290 SepReleaseTokenLock(NewToken
);
292 /* Reference the new token */
293 ObReferenceObject(NewToken
);
295 /* Replace the old with the new */
296 OldToken
= ObFastReplaceObject(&Process
->Token
, NewToken
);
298 /* Lock the old token */
299 SepAcquireTokenLockExclusive(OldToken
);
301 /* Mark the old token as free */
302 OldToken
->TokenInUse
= FALSE
;
304 /* Unlock the old token */
305 SepReleaseTokenLock(OldToken
);
307 *OldAccessToken
= (PACCESS_TOKEN
)OldToken
;
308 return STATUS_SUCCESS
;
313 SeDeassignPrimaryToken(PEPROCESS Process
)
317 /* Remove the Token */
318 OldToken
= ObFastReplaceObject(&Process
->Token
, NULL
);
320 /* Mark the Old Token as free */
321 OldToken
->TokenInUse
= FALSE
;
323 /* Dereference the Token */
324 ObDereferenceObject(OldToken
);
328 RtlLengthSidAndAttributes(ULONG Count
,
329 PSID_AND_ATTRIBUTES Src
)
336 uLength
= Count
* sizeof(SID_AND_ATTRIBUTES
);
337 for (i
= 0; i
< Count
; i
++)
338 uLength
+= RtlLengthSid(Src
[i
].Sid
);
345 SepFindPrimaryGroupAndDefaultOwner(
347 _In_ PSID PrimaryGroup
,
348 _In_opt_ PSID DefaultOwner
,
349 _Out_opt_ PULONG PrimaryGroupIndex
,
350 _Out_opt_ PULONG DefaultOwnerIndex
)
354 /* We should return at least a search result */
355 if (!PrimaryGroupIndex
&& !DefaultOwnerIndex
)
356 return STATUS_INVALID_PARAMETER
;
358 if (PrimaryGroupIndex
)
360 /* Initialize with an invalid index */
361 // Token->PrimaryGroup = NULL;
362 *PrimaryGroupIndex
= Token
->UserAndGroupCount
;
365 if (DefaultOwnerIndex
)
369 /* An owner is specified: check whether this is actually the user */
370 if (RtlEqualSid(Token
->UserAndGroups
[0].Sid
, DefaultOwner
))
373 * It's the user (first element in array): set it
374 * as the owner and stop the search for it.
376 *DefaultOwnerIndex
= 0;
377 DefaultOwnerIndex
= NULL
;
381 /* An owner is specified: initialize with an invalid index */
382 *DefaultOwnerIndex
= Token
->UserAndGroupCount
;
388 * No owner specified: set the user (first element in array)
389 * as the owner and stop the search for it.
391 *DefaultOwnerIndex
= 0;
392 DefaultOwnerIndex
= NULL
;
396 /* Validate and set the primary group and default owner indices */
397 for (i
= 0; i
< Token
->UserAndGroupCount
; i
++)
399 /* Stop the search if we have found what we searched for */
400 if (!PrimaryGroupIndex
&& !DefaultOwnerIndex
)
403 if (DefaultOwnerIndex
&& DefaultOwner
&&
404 RtlEqualSid(Token
->UserAndGroups
[i
].Sid
, DefaultOwner
) &&
405 (Token
->UserAndGroups
[i
].Attributes
& SE_GROUP_OWNER
))
407 /* Owner is found, stop the search for it */
408 *DefaultOwnerIndex
= i
;
409 DefaultOwnerIndex
= NULL
;
412 if (PrimaryGroupIndex
&&
413 RtlEqualSid(Token
->UserAndGroups
[i
].Sid
, PrimaryGroup
))
415 /* Primary group is found, stop the search for it */
416 // Token->PrimaryGroup = Token->UserAndGroups[i].Sid;
417 *PrimaryGroupIndex
= i
;
418 PrimaryGroupIndex
= NULL
;
422 if (DefaultOwnerIndex
)
424 if (*DefaultOwnerIndex
== Token
->UserAndGroupCount
)
425 return STATUS_INVALID_OWNER
;
428 if (PrimaryGroupIndex
)
430 if (*PrimaryGroupIndex
== Token
->UserAndGroupCount
)
431 // if (Token->PrimaryGroup == NULL)
432 return STATUS_INVALID_PRIMARY_GROUP
;
435 return STATUS_SUCCESS
;
443 _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes
,
444 _In_ BOOLEAN EffectiveOnly
,
445 _In_ TOKEN_TYPE TokenType
,
446 _In_ SECURITY_IMPERSONATION_LEVEL Level
,
447 _In_ KPROCESSOR_MODE PreviousMode
,
448 _Out_ PTOKEN
* NewAccessToken
)
453 ULONG VariableLength
;
458 /* Compute how much size we need to allocate for the token */
459 VariableLength
= Token
->VariableLength
;
460 TotalSize
= FIELD_OFFSET(TOKEN
, VariablePart
) + VariableLength
;
462 Status
= ObCreateObject(PreviousMode
,
470 (PVOID
*)&AccessToken
);
471 if (!NT_SUCCESS(Status
))
473 DPRINT1("ObCreateObject() failed (Status 0x%lx)\n", Status
);
477 /* Zero out the buffer and initialize the token */
478 RtlZeroMemory(AccessToken
, TotalSize
);
480 ExAllocateLocallyUniqueId(&AccessToken
->TokenId
);
482 AccessToken
->TokenType
= TokenType
;
483 AccessToken
->ImpersonationLevel
= Level
;
485 AccessToken
->TokenLock
= &SepTokenLock
; // FIXME: Global lock!
487 /* Copy the immutable fields */
488 RtlCopyLuid(&AccessToken
->TokenSource
.SourceIdentifier
,
489 &Token
->TokenSource
.SourceIdentifier
);
490 RtlCopyMemory(AccessToken
->TokenSource
.SourceName
,
491 Token
->TokenSource
.SourceName
,
492 sizeof(Token
->TokenSource
.SourceName
));
494 AccessToken
->AuthenticationId
= Token
->AuthenticationId
;
495 AccessToken
->ParentTokenId
= Token
->ParentTokenId
;
496 AccessToken
->ExpirationTime
= Token
->ExpirationTime
;
497 AccessToken
->OriginatingLogonSession
= Token
->OriginatingLogonSession
;
500 /* Lock the source token and copy the mutable fields */
501 SepAcquireTokenLockExclusive(Token
);
503 AccessToken
->SessionId
= Token
->SessionId
;
504 RtlCopyLuid(&AccessToken
->ModifiedId
, &Token
->ModifiedId
);
506 AccessToken
->TokenFlags
= Token
->TokenFlags
& ~TOKEN_SESSION_NOT_REFERENCED
;
508 /* Copy and reference the logon session */
509 // RtlCopyLuid(&AccessToken->AuthenticationId, &Token->AuthenticationId);
510 Status
= SepRmReferenceLogonSession(&AccessToken
->AuthenticationId
);
511 if (!NT_SUCCESS(Status
))
513 /* No logon session could be found, bail out */
514 DPRINT1("SepRmReferenceLogonSession() failed (Status 0x%lx)\n", Status
);
515 /* Set the flag for proper cleanup by the delete procedure */
516 AccessToken
->TokenFlags
|= TOKEN_SESSION_NOT_REFERENCED
;
520 /* Assign the data that reside in the TOKEN's variable information area */
521 AccessToken
->VariableLength
= VariableLength
;
522 EndMem
= (PVOID
)&AccessToken
->VariablePart
;
524 /* Copy the privileges */
525 AccessToken
->PrivilegeCount
= 0;
526 AccessToken
->Privileges
= NULL
;
527 if (Token
->Privileges
&& (Token
->PrivilegeCount
> 0))
529 ULONG PrivilegesLength
= Token
->PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
);
530 PrivilegesLength
= ALIGN_UP_BY(PrivilegesLength
, sizeof(PVOID
));
532 ASSERT(VariableLength
>= PrivilegesLength
);
534 AccessToken
->PrivilegeCount
= Token
->PrivilegeCount
;
535 AccessToken
->Privileges
= EndMem
;
536 EndMem
= (PVOID
)((ULONG_PTR
)EndMem
+ PrivilegesLength
);
537 VariableLength
-= PrivilegesLength
;
539 RtlCopyMemory(AccessToken
->Privileges
,
541 AccessToken
->PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
));
544 /* Copy the user and groups */
545 AccessToken
->UserAndGroupCount
= 0;
546 AccessToken
->UserAndGroups
= NULL
;
547 if (Token
->UserAndGroups
&& (Token
->UserAndGroupCount
> 0))
549 AccessToken
->UserAndGroupCount
= Token
->UserAndGroupCount
;
550 AccessToken
->UserAndGroups
= EndMem
;
551 EndMem
= &AccessToken
->UserAndGroups
[AccessToken
->UserAndGroupCount
];
552 VariableLength
-= ((ULONG_PTR
)EndMem
- (ULONG_PTR
)AccessToken
->UserAndGroups
);
554 Status
= RtlCopySidAndAttributesArray(AccessToken
->UserAndGroupCount
,
555 Token
->UserAndGroups
,
557 AccessToken
->UserAndGroups
,
561 if (!NT_SUCCESS(Status
))
563 DPRINT1("RtlCopySidAndAttributesArray(UserAndGroups) failed (Status 0x%lx)\n", Status
);
570 ULONG PrimaryGroupIndex
;
572 /* Find the token primary group */
573 Status
= SepFindPrimaryGroupAndDefaultOwner(AccessToken
,
578 if (!NT_SUCCESS(Status
))
580 DPRINT1("SepFindPrimaryGroupAndDefaultOwner failed (Status 0x%lx)\n", Status
);
583 AccessToken
->PrimaryGroup
= AccessToken
->UserAndGroups
[PrimaryGroupIndex
].Sid
;
586 AccessToken
->PrimaryGroup
= (PVOID
)((ULONG_PTR
)AccessToken
+ (ULONG_PTR
)Token
->PrimaryGroup
- (ULONG_PTR
)Token
->UserAndGroups
);
588 AccessToken
->DefaultOwnerIndex
= Token
->DefaultOwnerIndex
;
590 /* Copy the restricted SIDs */
591 AccessToken
->RestrictedSidCount
= 0;
592 AccessToken
->RestrictedSids
= NULL
;
593 if (Token
->RestrictedSids
&& (Token
->RestrictedSidCount
> 0))
595 AccessToken
->RestrictedSidCount
= Token
->RestrictedSidCount
;
596 AccessToken
->RestrictedSids
= EndMem
;
597 EndMem
= &AccessToken
->RestrictedSids
[AccessToken
->RestrictedSidCount
];
598 VariableLength
-= ((ULONG_PTR
)EndMem
- (ULONG_PTR
)AccessToken
->RestrictedSids
);
600 Status
= RtlCopySidAndAttributesArray(AccessToken
->RestrictedSidCount
,
601 Token
->RestrictedSids
,
603 AccessToken
->RestrictedSids
,
607 if (!NT_SUCCESS(Status
))
609 DPRINT1("RtlCopySidAndAttributesArray(RestrictedSids) failed (Status 0x%lx)\n", Status
);
616 // FIXME: Implement the "EffectiveOnly" option, that removes all
617 // the disabled parts (privileges and groups) of the token.
622 // NOTE: So far our dynamic area only contains
623 // the default dacl, so this makes the following
624 // code pretty simple. The day where it stores
625 // other data, the code will require adaptations.
628 /* Now allocate the TOKEN's dynamic information area and set the data */
629 AccessToken
->DynamicAvailable
= 0; // Unused memory in the dynamic area.
630 AccessToken
->DynamicPart
= NULL
;
631 if (Token
->DynamicPart
&& Token
->DefaultDacl
)
633 AccessToken
->DynamicPart
= ExAllocatePoolWithTag(PagedPool
,
634 Token
->DefaultDacl
->AclSize
,
636 if (AccessToken
->DynamicPart
== NULL
)
638 Status
= STATUS_INSUFFICIENT_RESOURCES
;
641 EndMem
= (PVOID
)AccessToken
->DynamicPart
;
643 AccessToken
->DefaultDacl
= EndMem
;
645 RtlCopyMemory(AccessToken
->DefaultDacl
,
647 Token
->DefaultDacl
->AclSize
);
650 /* Unlock the source token */
651 SepReleaseTokenLock(Token
);
653 /* Return the token */
654 *NewAccessToken
= AccessToken
;
655 Status
= STATUS_SUCCESS
;
658 if (!NT_SUCCESS(Status
))
660 /* Unlock the source token */
661 SepReleaseTokenLock(Token
);
663 /* Dereference the token, the delete procedure will clean it up */
664 ObDereferenceObject(AccessToken
);
672 SeSubProcessToken(IN PTOKEN ParentToken
,
678 OBJECT_ATTRIBUTES ObjectAttributes
;
681 /* Initialize the attributes and duplicate it */
682 InitializeObjectAttributes(&ObjectAttributes
, NULL
, 0, NULL
, NULL
);
683 Status
= SepDuplicateToken(ParentToken
,
687 ParentToken
->ImpersonationLevel
,
690 if (NT_SUCCESS(Status
))
693 Status
= ObInsertObject(NewToken
,
699 if (NT_SUCCESS(Status
))
701 /* Set the session ID */
702 NewToken
->SessionId
= SessionId
;
703 NewToken
->TokenInUse
= InUse
;
705 /* Return the token */
716 SeIsTokenChild(IN PTOKEN Token
,
717 OUT PBOOLEAN IsChild
)
720 LUID ProcessTokenId
, CallerParentId
;
725 /* Reference the process token */
726 ProcessToken
= PsReferencePrimaryToken(PsGetCurrentProcess());
728 return STATUS_UNSUCCESSFUL
;
730 /* Get its token ID */
731 ProcessTokenId
= ProcessToken
->TokenId
;
733 /* Dereference the token */
734 ObFastDereferenceObject(&PsGetCurrentProcess()->Token
, ProcessToken
);
736 /* Get our parent token ID */
737 CallerParentId
= Token
->ParentTokenId
;
739 /* Compare the token IDs */
740 if (RtlEqualLuid(&CallerParentId
, &ProcessTokenId
))
744 return STATUS_SUCCESS
;
749 SeIsTokenSibling(IN PTOKEN Token
,
750 OUT PBOOLEAN IsSibling
)
753 LUID ProcessParentId
, ProcessAuthId
;
754 LUID CallerParentId
, CallerAuthId
;
759 /* Reference the process token */
760 ProcessToken
= PsReferencePrimaryToken(PsGetCurrentProcess());
762 return STATUS_UNSUCCESSFUL
;
764 /* Get its parent and authentication IDs */
765 ProcessParentId
= ProcessToken
->ParentTokenId
;
766 ProcessAuthId
= ProcessToken
->AuthenticationId
;
768 /* Dereference the token */
769 ObFastDereferenceObject(&PsGetCurrentProcess()->Token
, ProcessToken
);
771 /* Get our parent and authentication IDs */
772 CallerParentId
= Token
->ParentTokenId
;
773 CallerAuthId
= Token
->AuthenticationId
;
775 /* Compare the token IDs */
776 if (RtlEqualLuid(&CallerParentId
, &ProcessParentId
) &&
777 RtlEqualLuid(&CallerAuthId
, &ProcessAuthId
))
783 return STATUS_SUCCESS
;
788 SeCopyClientToken(IN PACCESS_TOKEN Token
,
789 IN SECURITY_IMPERSONATION_LEVEL Level
,
790 IN KPROCESSOR_MODE PreviousMode
,
791 OUT PACCESS_TOKEN
* NewToken
)
794 OBJECT_ATTRIBUTES ObjectAttributes
;
798 InitializeObjectAttributes(&ObjectAttributes
,
804 Status
= SepDuplicateToken(Token
,
817 SepDeleteToken(PVOID ObjectBody
)
819 PTOKEN AccessToken
= (PTOKEN
)ObjectBody
;
821 DPRINT("SepDeleteToken()\n");
823 /* Dereference the logon session */
824 if ((AccessToken
->TokenFlags
& TOKEN_SESSION_NOT_REFERENCED
) == 0)
825 SepRmDereferenceLogonSession(&AccessToken
->AuthenticationId
);
827 /* Delete the dynamic information area */
828 if (AccessToken
->DynamicPart
)
829 ExFreePoolWithTag(AccessToken
->DynamicPart
, TAG_TOKEN_DYNAMIC
);
836 SepInitializeTokenImplementation(VOID
)
839 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
841 ExInitializeResource(&SepTokenLock
); // FIXME: Global lock!
843 DPRINT("Creating Token Object Type\n");
845 /* Initialize the Token type */
846 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
847 RtlInitUnicodeString(&Name
, L
"Token");
848 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
849 ObjectTypeInitializer
.InvalidAttributes
= OBJ_OPENLINK
;
850 ObjectTypeInitializer
.SecurityRequired
= TRUE
;
851 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(TOKEN
);
852 ObjectTypeInitializer
.GenericMapping
= SepTokenMapping
;
853 ObjectTypeInitializer
.PoolType
= PagedPool
;
854 ObjectTypeInitializer
.ValidAccessMask
= TOKEN_ALL_ACCESS
;
855 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
856 ObjectTypeInitializer
.DeleteProcedure
= SepDeleteToken
;
857 ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &SeTokenObjectType
);
862 SeAssignPrimaryToken(IN PEPROCESS Process
,
868 ASSERT(Token
->TokenType
== TokenPrimary
);
869 ASSERT(!Token
->TokenInUse
);
871 /* Clean any previous token */
872 if (Process
->Token
.Object
) SeDeassignPrimaryToken(Process
);
874 /* Set the new token */
875 ObReferenceObject(Token
);
876 Token
->TokenInUse
= TRUE
;
877 ObInitializeFastReference(&Process
->Token
, Token
);
883 _Out_ PHANDLE TokenHandle
,
884 _In_ KPROCESSOR_MODE PreviousMode
,
885 _In_ ACCESS_MASK DesiredAccess
,
886 _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes
,
887 _In_ TOKEN_TYPE TokenType
,
888 _In_ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
,
889 _In_ PLUID AuthenticationId
,
890 _In_ PLARGE_INTEGER ExpirationTime
,
891 _In_ PSID_AND_ATTRIBUTES User
,
892 _In_ ULONG GroupCount
,
893 _In_ PSID_AND_ATTRIBUTES Groups
,
894 _In_ ULONG GroupsLength
,
895 _In_ ULONG PrivilegeCount
,
896 _In_ PLUID_AND_ATTRIBUTES Privileges
,
898 _In_ PSID PrimaryGroup
,
899 _In_opt_ PACL DefaultDacl
,
900 _In_ PTOKEN_SOURCE TokenSource
,
901 _In_ BOOLEAN SystemToken
)
905 ULONG TokenFlags
= 0;
906 ULONG PrimaryGroupIndex
, DefaultOwnerIndex
;
910 ULONG PrivilegesLength
;
911 ULONG UserGroupsLength
;
912 ULONG VariableLength
;
918 /* Loop all groups */
919 for (i
= 0; i
< GroupCount
; i
++)
921 /* Check for mandatory groups */
922 if (Groups
[i
].Attributes
& SE_GROUP_MANDATORY
)
924 /* Force them to be enabled */
925 Groups
[i
].Attributes
|= (SE_GROUP_ENABLED
| SE_GROUP_ENABLED_BY_DEFAULT
);
928 /* Check of the group is an admin group */
929 if (RtlEqualSid(SeAliasAdminsSid
, Groups
[i
].Sid
))
931 /* Remember this so we can optimize queries later */
932 TokenFlags
|= TOKEN_HAS_ADMIN_GROUP
;
936 /* Allocate unique IDs for the token */
937 ExAllocateLocallyUniqueId(&TokenId
);
938 ExAllocateLocallyUniqueId(&ModifiedId
);
940 /* Compute how much size we need to allocate for the token */
942 /* Privileges size */
943 PrivilegesLength
= PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
);
944 PrivilegesLength
= ALIGN_UP_BY(PrivilegesLength
, sizeof(PVOID
));
946 /* User and groups size */
947 UserGroupsLength
= (1 + GroupCount
) * sizeof(SID_AND_ATTRIBUTES
);
948 UserGroupsLength
+= RtlLengthSid(User
->Sid
);
949 for (i
= 0; i
< GroupCount
; i
++)
951 UserGroupsLength
+= RtlLengthSid(Groups
[i
].Sid
);
953 UserGroupsLength
= ALIGN_UP_BY(UserGroupsLength
, sizeof(PVOID
));
955 /* Add the additional groups array length */
956 UserGroupsLength
+= ALIGN_UP_BY(GroupsLength
, sizeof(PVOID
));
958 VariableLength
= PrivilegesLength
+ UserGroupsLength
;
959 TotalSize
= FIELD_OFFSET(TOKEN
, VariablePart
) + VariableLength
;
961 Status
= ObCreateObject(PreviousMode
,
969 (PVOID
*)&AccessToken
);
970 if (!NT_SUCCESS(Status
))
972 DPRINT1("ObCreateObject() failed (Status 0x%lx)\n", Status
);
976 /* Zero out the buffer and initialize the token */
977 RtlZeroMemory(AccessToken
, TotalSize
);
979 RtlCopyLuid(&AccessToken
->TokenId
, &TokenId
);
981 AccessToken
->TokenType
= TokenType
;
982 AccessToken
->ImpersonationLevel
= ImpersonationLevel
;
984 AccessToken
->TokenLock
= &SepTokenLock
; // FIXME: Global lock!
986 RtlCopyLuid(&AccessToken
->TokenSource
.SourceIdentifier
,
987 &TokenSource
->SourceIdentifier
);
988 RtlCopyMemory(AccessToken
->TokenSource
.SourceName
,
989 TokenSource
->SourceName
,
990 sizeof(TokenSource
->SourceName
));
992 AccessToken
->ExpirationTime
= *ExpirationTime
;
993 RtlCopyLuid(&AccessToken
->ModifiedId
, &ModifiedId
);
995 AccessToken
->TokenFlags
= TokenFlags
& ~TOKEN_SESSION_NOT_REFERENCED
;
997 /* Copy and reference the logon session */
998 RtlCopyLuid(&AccessToken
->AuthenticationId
, AuthenticationId
);
999 Status
= SepRmReferenceLogonSession(&AccessToken
->AuthenticationId
);
1000 if (!NT_SUCCESS(Status
))
1002 /* No logon session could be found, bail out */
1003 DPRINT1("SepRmReferenceLogonSession() failed (Status 0x%lx)\n", Status
);
1004 /* Set the flag for proper cleanup by the delete procedure */
1005 AccessToken
->TokenFlags
|= TOKEN_SESSION_NOT_REFERENCED
;
1009 /* Assign the data that reside in the TOKEN's variable information area */
1010 AccessToken
->VariableLength
= VariableLength
;
1011 EndMem
= (PVOID
)&AccessToken
->VariablePart
;
1013 /* Copy the privileges */
1014 AccessToken
->PrivilegeCount
= PrivilegeCount
;
1015 AccessToken
->Privileges
= NULL
;
1016 if (PrivilegeCount
> 0)
1018 AccessToken
->Privileges
= EndMem
;
1019 EndMem
= (PVOID
)((ULONG_PTR
)EndMem
+ PrivilegesLength
);
1020 VariableLength
-= PrivilegesLength
;
1022 if (PreviousMode
!= KernelMode
)
1026 RtlCopyMemory(AccessToken
->Privileges
,
1028 PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
));
1030 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1032 Status
= _SEH2_GetExceptionCode();
1038 RtlCopyMemory(AccessToken
->Privileges
,
1040 PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
));
1043 if (!NT_SUCCESS(Status
))
1047 /* Update the privilege flags */
1048 SepUpdatePrivilegeFlagsToken(AccessToken
);
1050 /* Copy the user and groups */
1051 AccessToken
->UserAndGroupCount
= 1 + GroupCount
;
1052 AccessToken
->UserAndGroups
= EndMem
;
1053 EndMem
= &AccessToken
->UserAndGroups
[AccessToken
->UserAndGroupCount
];
1054 VariableLength
-= ((ULONG_PTR
)EndMem
- (ULONG_PTR
)AccessToken
->UserAndGroups
);
1056 Status
= RtlCopySidAndAttributesArray(1,
1059 &AccessToken
->UserAndGroups
[0],
1063 if (!NT_SUCCESS(Status
))
1066 Status
= RtlCopySidAndAttributesArray(GroupCount
,
1069 &AccessToken
->UserAndGroups
[1],
1073 if (!NT_SUCCESS(Status
))
1076 /* Find the token primary group and default owner */
1077 Status
= SepFindPrimaryGroupAndDefaultOwner(AccessToken
,
1081 &DefaultOwnerIndex
);
1082 if (!NT_SUCCESS(Status
))
1084 DPRINT1("SepFindPrimaryGroupAndDefaultOwner failed (Status 0x%lx)\n", Status
);
1088 AccessToken
->PrimaryGroup
= AccessToken
->UserAndGroups
[PrimaryGroupIndex
].Sid
;
1089 AccessToken
->DefaultOwnerIndex
= DefaultOwnerIndex
;
1091 /* Now allocate the TOKEN's dynamic information area and set the data */
1092 AccessToken
->DynamicAvailable
= 0; // Unused memory in the dynamic area.
1093 AccessToken
->DynamicPart
= NULL
;
1094 if (DefaultDacl
!= NULL
)
1096 AccessToken
->DynamicPart
= ExAllocatePoolWithTag(PagedPool
,
1097 DefaultDacl
->AclSize
,
1099 if (AccessToken
->DynamicPart
== NULL
)
1101 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1104 EndMem
= (PVOID
)AccessToken
->DynamicPart
;
1106 AccessToken
->DefaultDacl
= EndMem
;
1108 RtlCopyMemory(AccessToken
->DefaultDacl
,
1110 DefaultDacl
->AclSize
);
1113 /* Insert the token only if it's not the system token, otherwise return it directly */
1116 Status
= ObInsertObject(AccessToken
,
1122 if (!NT_SUCCESS(Status
))
1124 DPRINT1("ObInsertObject() failed (Status 0x%lx)\n", Status
);
1129 /* Return pointer instead of handle */
1130 *TokenHandle
= (HANDLE
)AccessToken
;
1134 if (!NT_SUCCESS(Status
))
1136 /* Dereference the token, the delete procedure will clean it up */
1137 ObDereferenceObject(AccessToken
);
1145 SepCreateSystemProcessToken(VOID
)
1147 LUID_AND_ATTRIBUTES Privileges
[25];
1148 ULONG GroupAttributes
, OwnerAttributes
;
1149 SID_AND_ATTRIBUTES Groups
[32];
1150 LARGE_INTEGER Expiration
;
1151 SID_AND_ATTRIBUTES UserSid
;
1154 OBJECT_ATTRIBUTES ObjectAttributes
;
1160 /* Don't ever expire */
1161 Expiration
.QuadPart
= -1;
1163 /* All groups mandatory and enabled */
1164 GroupAttributes
= SE_GROUP_ENABLED
| SE_GROUP_MANDATORY
| SE_GROUP_ENABLED_BY_DEFAULT
;
1165 OwnerAttributes
= SE_GROUP_ENABLED
| SE_GROUP_OWNER
| SE_GROUP_ENABLED_BY_DEFAULT
;
1167 /* User is Local System */
1168 UserSid
.Sid
= SeLocalSystemSid
;
1169 UserSid
.Attributes
= 0;
1171 /* Primary group is Local System */
1172 PrimaryGroup
= SeLocalSystemSid
;
1174 /* Owner is Administrators */
1175 Owner
= SeAliasAdminsSid
;
1177 /* Groups are Administrators, World, and Authenticated Users */
1178 Groups
[0].Sid
= SeAliasAdminsSid
;
1179 Groups
[0].Attributes
= OwnerAttributes
;
1180 Groups
[1].Sid
= SeWorldSid
;
1181 Groups
[1].Attributes
= GroupAttributes
;
1182 Groups
[2].Sid
= SeAuthenticatedUsersSid
;
1183 Groups
[2].Attributes
= GroupAttributes
;
1184 GroupsLength
= sizeof(SID_AND_ATTRIBUTES
) +
1185 SeLengthSid(Groups
[0].Sid
) +
1186 SeLengthSid(Groups
[1].Sid
) +
1187 SeLengthSid(Groups
[2].Sid
);
1188 ASSERT(GroupsLength
<= sizeof(Groups
));
1190 /* Setup the privileges */
1192 Privileges
[i
].Attributes
= SE_PRIVILEGE_ENABLED_BY_DEFAULT
| SE_PRIVILEGE_ENABLED
;
1193 Privileges
[i
++].Luid
= SeTcbPrivilege
;
1195 Privileges
[i
].Attributes
= 0;
1196 Privileges
[i
++].Luid
= SeCreateTokenPrivilege
;
1198 Privileges
[i
].Attributes
= 0;
1199 Privileges
[i
++].Luid
= SeTakeOwnershipPrivilege
;
1201 Privileges
[i
].Attributes
= SE_PRIVILEGE_ENABLED_BY_DEFAULT
| SE_PRIVILEGE_ENABLED
;
1202 Privileges
[i
++].Luid
= SeCreatePagefilePrivilege
;
1204 Privileges
[i
].Attributes
= SE_PRIVILEGE_ENABLED_BY_DEFAULT
| SE_PRIVILEGE_ENABLED
;
1205 Privileges
[i
++].Luid
= SeLockMemoryPrivilege
;
1207 Privileges
[i
].Attributes
= 0;
1208 Privileges
[i
++].Luid
= SeAssignPrimaryTokenPrivilege
;
1210 Privileges
[i
].Attributes
= 0;
1211 Privileges
[i
++].Luid
= SeIncreaseQuotaPrivilege
;
1213 Privileges
[i
].Attributes
= SE_PRIVILEGE_ENABLED_BY_DEFAULT
| SE_PRIVILEGE_ENABLED
;
1214 Privileges
[i
++].Luid
= SeIncreaseBasePriorityPrivilege
;
1216 Privileges
[i
].Attributes
= SE_PRIVILEGE_ENABLED_BY_DEFAULT
| SE_PRIVILEGE_ENABLED
;
1217 Privileges
[i
++].Luid
= SeCreatePermanentPrivilege
;
1219 Privileges
[i
].Attributes
= SE_PRIVILEGE_ENABLED_BY_DEFAULT
| SE_PRIVILEGE_ENABLED
;
1220 Privileges
[i
++].Luid
= SeDebugPrivilege
;
1222 Privileges
[i
].Attributes
= SE_PRIVILEGE_ENABLED_BY_DEFAULT
| SE_PRIVILEGE_ENABLED
;
1223 Privileges
[i
++].Luid
= SeAuditPrivilege
;
1225 Privileges
[i
].Attributes
= 0;
1226 Privileges
[i
++].Luid
= SeSecurityPrivilege
;
1228 Privileges
[i
].Attributes
= 0;
1229 Privileges
[i
++].Luid
= SeSystemEnvironmentPrivilege
;
1231 Privileges
[i
].Attributes
= SE_PRIVILEGE_ENABLED_BY_DEFAULT
| SE_PRIVILEGE_ENABLED
;
1232 Privileges
[i
++].Luid
= SeChangeNotifyPrivilege
;
1234 Privileges
[i
].Attributes
= 0;
1235 Privileges
[i
++].Luid
= SeBackupPrivilege
;
1237 Privileges
[i
].Attributes
= 0;
1238 Privileges
[i
++].Luid
= SeRestorePrivilege
;
1240 Privileges
[i
].Attributes
= 0;
1241 Privileges
[i
++].Luid
= SeShutdownPrivilege
;
1243 Privileges
[i
].Attributes
= 0;
1244 Privileges
[i
++].Luid
= SeLoadDriverPrivilege
;
1246 Privileges
[i
].Attributes
= SE_PRIVILEGE_ENABLED_BY_DEFAULT
| SE_PRIVILEGE_ENABLED
;
1247 Privileges
[i
++].Luid
= SeProfileSingleProcessPrivilege
;
1249 Privileges
[i
].Attributes
= 0;
1250 Privileges
[i
++].Luid
= SeSystemtimePrivilege
;
1253 /* Setup the object attributes */
1254 InitializeObjectAttributes(&ObjectAttributes
, NULL
, 0, NULL
, NULL
);
1255 ASSERT(SeSystemDefaultDacl
!= NULL
);
1257 /* Create the token */
1258 Status
= SepCreateToken((PHANDLE
)&Token
,
1264 &SeSystemAuthenticationId
,
1274 SeSystemDefaultDacl
,
1275 &SeSystemTokenSource
,
1277 ASSERT(Status
== STATUS_SUCCESS
);
1279 /* Return the token */
1283 /* PUBLIC FUNCTIONS ***********************************************************/
1290 SeFilterToken(IN PACCESS_TOKEN ExistingToken
,
1292 IN PTOKEN_GROUPS SidsToDisable OPTIONAL
,
1293 IN PTOKEN_PRIVILEGES PrivilegesToDelete OPTIONAL
,
1294 IN PTOKEN_GROUPS RestrictedSids OPTIONAL
,
1295 OUT PACCESS_TOKEN
* FilteredToken
)
1298 return STATUS_NOT_IMPLEMENTED
;
1304 * NOTE: SeQueryInformationToken is just NtQueryInformationToken without all
1305 * the bells and whistles needed for user-mode buffer access protection.
1309 SeQueryInformationToken(IN PACCESS_TOKEN AccessToken
,
1310 IN TOKEN_INFORMATION_CLASS TokenInformationClass
,
1311 OUT PVOID
*TokenInformation
)
1314 PTOKEN Token
= (PTOKEN
)AccessToken
;
1315 ULONG RequiredLength
;
1324 if (TokenInformationClass
>= MaxTokenInfoClass
)
1326 DPRINT1("SeQueryInformationToken(%d) invalid information class\n", TokenInformationClass
);
1327 return STATUS_INVALID_INFO_CLASS
;
1330 // TODO: Lock the token
1332 switch (TokenInformationClass
)
1338 DPRINT("SeQueryInformationToken(TokenUser)\n");
1339 RequiredLength
= sizeof(TOKEN_USER
) +
1340 RtlLengthSid(Token
->UserAndGroups
[0].Sid
);
1342 /* Allocate the output buffer */
1343 tu
= ExAllocatePoolWithTag(PagedPool
, RequiredLength
, TAG_SE
);
1346 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1350 Status
= RtlCopySidAndAttributesArray(1,
1351 &Token
->UserAndGroups
[0],
1352 RequiredLength
- sizeof(TOKEN_USER
),
1358 /* Return the structure */
1359 *TokenInformation
= tu
;
1360 Status
= STATUS_SUCCESS
;
1370 DPRINT("SeQueryInformationToken(TokenGroups)\n");
1371 RequiredLength
= sizeof(tg
->GroupCount
) +
1372 RtlLengthSidAndAttributes(Token
->UserAndGroupCount
- 1, &Token
->UserAndGroups
[1]);
1374 SidLen
= RequiredLength
- sizeof(tg
->GroupCount
) -
1375 ((Token
->UserAndGroupCount
- 1) * sizeof(SID_AND_ATTRIBUTES
));
1377 /* Allocate the output buffer */
1378 tg
= ExAllocatePoolWithTag(PagedPool
, RequiredLength
, TAG_SE
);
1381 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1385 Sid
= (PSID
)((ULONG_PTR
)tg
+ sizeof(tg
->GroupCount
) +
1386 ((Token
->UserAndGroupCount
- 1) * sizeof(SID_AND_ATTRIBUTES
)));
1388 tg
->GroupCount
= Token
->UserAndGroupCount
- 1;
1389 Status
= RtlCopySidAndAttributesArray(Token
->UserAndGroupCount
- 1,
1390 &Token
->UserAndGroups
[1],
1397 /* Return the structure */
1398 *TokenInformation
= tg
;
1399 Status
= STATUS_SUCCESS
;
1403 case TokenPrivileges
:
1405 PTOKEN_PRIVILEGES tp
;
1407 DPRINT("SeQueryInformationToken(TokenPrivileges)\n");
1408 RequiredLength
= sizeof(tp
->PrivilegeCount
) +
1409 (Token
->PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
));
1411 /* Allocate the output buffer */
1412 tp
= ExAllocatePoolWithTag(PagedPool
, RequiredLength
, TAG_SE
);
1415 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1419 tp
->PrivilegeCount
= Token
->PrivilegeCount
;
1420 RtlCopyLuidAndAttributesArray(Token
->PrivilegeCount
,
1422 &tp
->Privileges
[0]);
1424 /* Return the structure */
1425 *TokenInformation
= tp
;
1426 Status
= STATUS_SUCCESS
;
1435 DPRINT("SeQueryInformationToken(TokenOwner)\n");
1436 SidLen
= RtlLengthSid(Token
->UserAndGroups
[Token
->DefaultOwnerIndex
].Sid
);
1437 RequiredLength
= sizeof(TOKEN_OWNER
) + SidLen
;
1439 /* Allocate the output buffer */
1440 to
= ExAllocatePoolWithTag(PagedPool
, RequiredLength
, TAG_SE
);
1443 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1447 to
->Owner
= (PSID
)(to
+ 1);
1448 Status
= RtlCopySid(SidLen
,
1450 Token
->UserAndGroups
[Token
->DefaultOwnerIndex
].Sid
);
1452 /* Return the structure */
1453 *TokenInformation
= to
;
1454 Status
= STATUS_SUCCESS
;
1458 case TokenPrimaryGroup
:
1460 PTOKEN_PRIMARY_GROUP tpg
;
1463 DPRINT("SeQueryInformationToken(TokenPrimaryGroup)\n");
1464 SidLen
= RtlLengthSid(Token
->PrimaryGroup
);
1465 RequiredLength
= sizeof(TOKEN_PRIMARY_GROUP
) + SidLen
;
1467 /* Allocate the output buffer */
1468 tpg
= ExAllocatePoolWithTag(PagedPool
, RequiredLength
, TAG_SE
);
1471 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1475 tpg
->PrimaryGroup
= (PSID
)(tpg
+ 1);
1476 Status
= RtlCopySid(SidLen
,
1478 Token
->PrimaryGroup
);
1480 /* Return the structure */
1481 *TokenInformation
= tpg
;
1482 Status
= STATUS_SUCCESS
;
1486 case TokenDefaultDacl
:
1488 PTOKEN_DEFAULT_DACL tdd
;
1490 DPRINT("SeQueryInformationToken(TokenDefaultDacl)\n");
1491 RequiredLength
= sizeof(TOKEN_DEFAULT_DACL
);
1493 if (Token
->DefaultDacl
!= NULL
)
1494 RequiredLength
+= Token
->DefaultDacl
->AclSize
;
1496 /* Allocate the output buffer */
1497 tdd
= ExAllocatePoolWithTag(PagedPool
, RequiredLength
, TAG_SE
);
1500 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1504 if (Token
->DefaultDacl
!= NULL
)
1506 tdd
->DefaultDacl
= (PACL
)(tdd
+ 1);
1507 RtlCopyMemory(tdd
->DefaultDacl
,
1509 Token
->DefaultDacl
->AclSize
);
1513 tdd
->DefaultDacl
= NULL
;
1516 /* Return the structure */
1517 *TokenInformation
= tdd
;
1518 Status
= STATUS_SUCCESS
;
1526 DPRINT("SeQueryInformationToken(TokenSource)\n");
1527 RequiredLength
= sizeof(TOKEN_SOURCE
);
1529 /* Allocate the output buffer */
1530 ts
= ExAllocatePoolWithTag(PagedPool
, RequiredLength
, TAG_SE
);
1533 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1537 *ts
= Token
->TokenSource
;
1539 /* Return the structure */
1540 *TokenInformation
= ts
;
1541 Status
= STATUS_SUCCESS
;
1549 DPRINT("SeQueryInformationToken(TokenType)\n");
1550 RequiredLength
= sizeof(TOKEN_TYPE
);
1552 /* Allocate the output buffer */
1553 tt
= ExAllocatePoolWithTag(PagedPool
, RequiredLength
, TAG_SE
);
1556 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1560 *tt
= Token
->TokenType
;
1562 /* Return the structure */
1563 *TokenInformation
= tt
;
1564 Status
= STATUS_SUCCESS
;
1568 case TokenImpersonationLevel
:
1570 PSECURITY_IMPERSONATION_LEVEL sil
;
1572 DPRINT("SeQueryInformationToken(TokenImpersonationLevel)\n");
1573 RequiredLength
= sizeof(SECURITY_IMPERSONATION_LEVEL
);
1575 /* Fail if the token is not an impersonation token */
1576 if (Token
->TokenType
!= TokenImpersonation
)
1578 Status
= STATUS_INVALID_INFO_CLASS
;
1582 /* Allocate the output buffer */
1583 sil
= ExAllocatePoolWithTag(PagedPool
, RequiredLength
, TAG_SE
);
1586 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1590 *sil
= Token
->ImpersonationLevel
;
1592 /* Return the structure */
1593 *TokenInformation
= sil
;
1594 Status
= STATUS_SUCCESS
;
1598 case TokenStatistics
:
1600 PTOKEN_STATISTICS ts
;
1602 DPRINT("SeQueryInformationToken(TokenStatistics)\n");
1603 RequiredLength
= sizeof(TOKEN_STATISTICS
);
1605 /* Allocate the output buffer */
1606 ts
= ExAllocatePoolWithTag(PagedPool
, RequiredLength
, TAG_SE
);
1609 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1613 ts
->TokenId
= Token
->TokenId
;
1614 ts
->AuthenticationId
= Token
->AuthenticationId
;
1615 ts
->ExpirationTime
= Token
->ExpirationTime
;
1616 ts
->TokenType
= Token
->TokenType
;
1617 ts
->ImpersonationLevel
= Token
->ImpersonationLevel
;
1618 ts
->DynamicCharged
= Token
->DynamicCharged
;
1619 ts
->DynamicAvailable
= Token
->DynamicAvailable
;
1620 ts
->GroupCount
= Token
->UserAndGroupCount
- 1;
1621 ts
->PrivilegeCount
= Token
->PrivilegeCount
;
1622 ts
->ModifiedId
= Token
->ModifiedId
;
1624 /* Return the structure */
1625 *TokenInformation
= ts
;
1626 Status
= STATUS_SUCCESS
;
1631 * The following 4 cases are only implemented in NtQueryInformationToken
1639 DPRINT("SeQueryInformationToken(TokenOrigin)\n");
1640 RequiredLength
= sizeof(TOKEN_ORIGIN
);
1642 /* Allocate the output buffer */
1643 to
= ExAllocatePoolWithTag(PagedPool
, RequiredLength
, TAG_SE
);
1646 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1650 RtlCopyLuid(&to
->OriginatingLogonSession
,
1651 &Token
->AuthenticationId
);
1653 /* Return the structure */
1654 *TokenInformation
= to
;
1655 Status
= STATUS_SUCCESS
;
1659 case TokenGroupsAndPrivileges
:
1660 DPRINT1("SeQueryInformationToken(TokenGroupsAndPrivileges) not implemented\n");
1661 Status
= STATUS_NOT_IMPLEMENTED
;
1664 case TokenRestrictedSids
:
1666 PTOKEN_GROUPS tg
= (PTOKEN_GROUPS
)TokenInformation
;
1670 DPRINT("SeQueryInformationToken(TokenRestrictedSids)\n");
1671 RequiredLength
= sizeof(tg
->GroupCount
) +
1672 RtlLengthSidAndAttributes(Token
->RestrictedSidCount
, Token
->RestrictedSids
);
1674 SidLen
= RequiredLength
- sizeof(tg
->GroupCount
) -
1675 (Token
->RestrictedSidCount
* sizeof(SID_AND_ATTRIBUTES
));
1677 /* Allocate the output buffer */
1678 tg
= ExAllocatePoolWithTag(PagedPool
, RequiredLength
, TAG_SE
);
1681 Status
= STATUS_INSUFFICIENT_RESOURCES
;
1685 Sid
= (PSID
)((ULONG_PTR
)tg
+ sizeof(tg
->GroupCount
) +
1686 (Token
->RestrictedSidCount
* sizeof(SID_AND_ATTRIBUTES
)));
1688 tg
->GroupCount
= Token
->RestrictedSidCount
;
1689 Status
= RtlCopySidAndAttributesArray(Token
->RestrictedSidCount
,
1690 Token
->RestrictedSids
,
1697 /* Return the structure */
1698 *TokenInformation
= tg
;
1699 Status
= STATUS_SUCCESS
;
1703 case TokenSandBoxInert
:
1704 DPRINT1("SeQueryInformationToken(TokenSandboxInert) not implemented\n");
1705 Status
= STATUS_NOT_IMPLEMENTED
;
1710 case TokenSessionId
:
1712 DPRINT("SeQueryInformationToken(TokenSessionId)\n");
1713 Status
= SeQuerySessionIdToken(Token
, (PULONG
)TokenInformation
);
1718 DPRINT1("SeQueryInformationToken(%d) invalid information class\n", TokenInformationClass
);
1719 Status
= STATUS_INVALID_INFO_CLASS
;
1731 SeQuerySessionIdToken(IN PACCESS_TOKEN Token
,
1732 IN PULONG pSessionId
)
1736 /* Lock the token */
1737 SepAcquireTokenLockShared(Token
);
1739 *pSessionId
= ((PTOKEN
)Token
)->SessionId
;
1741 /* Unlock the token */
1742 SepReleaseTokenLock(Token
);
1744 return STATUS_SUCCESS
;
1752 SeQueryAuthenticationIdToken(IN PACCESS_TOKEN Token
,
1757 *LogonId
= ((PTOKEN
)Token
)->AuthenticationId
;
1759 return STATUS_SUCCESS
;
1766 SECURITY_IMPERSONATION_LEVEL
1768 SeTokenImpersonationLevel(IN PACCESS_TOKEN Token
)
1772 return ((PTOKEN
)Token
)->ImpersonationLevel
;
1780 SeTokenType(IN PACCESS_TOKEN Token
)
1784 return ((PTOKEN
)Token
)->TokenType
;
1793 SeTokenIsAdmin(IN PACCESS_TOKEN Token
)
1797 // NOTE: Win7+ instead really checks the list of groups in the token
1798 // (since TOKEN_HAS_ADMIN_GROUP == TOKEN_WRITE_RESTRICTED ...)
1799 return (((PTOKEN
)Token
)->TokenFlags
& TOKEN_HAS_ADMIN_GROUP
) != 0;
1807 SeTokenIsRestricted(IN PACCESS_TOKEN Token
)
1811 return (((PTOKEN
)Token
)->TokenFlags
& TOKEN_IS_RESTRICTED
) != 0;
1816 * @note First introduced in NT 5.1 SP2 x86 (5.1.2600.2622), absent in NT 5.2,
1817 * then finally re-introduced in Vista+.
1821 SeTokenIsWriteRestricted(IN PACCESS_TOKEN Token
)
1825 // NOTE: NT 5.1 SP2 x86 checks the SE_BACKUP_PRIVILEGES_CHECKED flag
1826 // while Vista+ checks the TOKEN_WRITE_RESTRICTED flag as one expects.
1827 return (((PTOKEN
)Token
)->TokenFlags
& SE_BACKUP_PRIVILEGES_CHECKED
) != 0;
1830 /* SYSTEM CALLS ***************************************************************/
1835 _Must_inspect_result_
1839 NtQueryInformationToken(
1840 _In_ HANDLE TokenHandle
,
1841 _In_ TOKEN_INFORMATION_CLASS TokenInformationClass
,
1842 _Out_writes_bytes_to_opt_(TokenInformationLength
, *ReturnLength
)
1843 PVOID TokenInformation
,
1844 _In_ ULONG TokenInformationLength
,
1845 _Out_ PULONG ReturnLength
)
1848 KPROCESSOR_MODE PreviousMode
;
1850 ULONG RequiredLength
;
1859 PreviousMode
= ExGetPreviousMode();
1861 /* Check buffers and class validity */
1862 Status
= DefaultQueryInfoBufferCheck(TokenInformationClass
,
1863 SeTokenInformationClass
,
1864 RTL_NUMBER_OF(SeTokenInformationClass
),
1866 TokenInformationLength
,
1870 if (!NT_SUCCESS(Status
))
1872 DPRINT("NtQueryInformationToken() failed, Status: 0x%x\n", Status
);
1876 Status
= ObReferenceObjectByHandle(TokenHandle
,
1877 (TokenInformationClass
== TokenSource
) ? TOKEN_QUERY_SOURCE
: TOKEN_QUERY
,
1882 if (NT_SUCCESS(Status
))
1884 /* Lock the token */
1885 SepAcquireTokenLockShared(Token
);
1887 switch (TokenInformationClass
)
1891 PTOKEN_USER tu
= (PTOKEN_USER
)TokenInformation
;
1893 DPRINT("NtQueryInformationToken(TokenUser)\n");
1894 RequiredLength
= sizeof(TOKEN_USER
) +
1895 RtlLengthSid(Token
->UserAndGroups
[0].Sid
);
1899 if (TokenInformationLength
>= RequiredLength
)
1901 Status
= RtlCopySidAndAttributesArray(1,
1902 &Token
->UserAndGroups
[0],
1903 RequiredLength
- sizeof(TOKEN_USER
),
1911 Status
= STATUS_BUFFER_TOO_SMALL
;
1914 if (ReturnLength
!= NULL
)
1916 *ReturnLength
= RequiredLength
;
1919 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1921 Status
= _SEH2_GetExceptionCode();
1930 PTOKEN_GROUPS tg
= (PTOKEN_GROUPS
)TokenInformation
;
1932 DPRINT("NtQueryInformationToken(TokenGroups)\n");
1933 RequiredLength
= sizeof(tg
->GroupCount
) +
1934 RtlLengthSidAndAttributes(Token
->UserAndGroupCount
- 1, &Token
->UserAndGroups
[1]);
1938 if (TokenInformationLength
>= RequiredLength
)
1940 ULONG SidLen
= RequiredLength
- sizeof(tg
->GroupCount
) -
1941 ((Token
->UserAndGroupCount
- 1) * sizeof(SID_AND_ATTRIBUTES
));
1942 PSID Sid
= (PSID_AND_ATTRIBUTES
)((ULONG_PTR
)tg
+ sizeof(tg
->GroupCount
) +
1943 ((Token
->UserAndGroupCount
- 1) * sizeof(SID_AND_ATTRIBUTES
)));
1945 tg
->GroupCount
= Token
->UserAndGroupCount
- 1;
1946 Status
= RtlCopySidAndAttributesArray(Token
->UserAndGroupCount
- 1,
1947 &Token
->UserAndGroups
[1],
1956 Status
= STATUS_BUFFER_TOO_SMALL
;
1959 if (ReturnLength
!= NULL
)
1961 *ReturnLength
= RequiredLength
;
1964 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1966 Status
= _SEH2_GetExceptionCode();
1973 case TokenPrivileges
:
1975 PTOKEN_PRIVILEGES tp
= (PTOKEN_PRIVILEGES
)TokenInformation
;
1977 DPRINT("NtQueryInformationToken(TokenPrivileges)\n");
1978 RequiredLength
= sizeof(tp
->PrivilegeCount
) +
1979 (Token
->PrivilegeCount
* sizeof(LUID_AND_ATTRIBUTES
));
1983 if (TokenInformationLength
>= RequiredLength
)
1985 tp
->PrivilegeCount
= Token
->PrivilegeCount
;
1986 RtlCopyLuidAndAttributesArray(Token
->PrivilegeCount
,
1988 &tp
->Privileges
[0]);
1992 Status
= STATUS_BUFFER_TOO_SMALL
;
1995 if (ReturnLength
!= NULL
)
1997 *ReturnLength
= RequiredLength
;
2000 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2002 Status
= _SEH2_GetExceptionCode();
2011 PTOKEN_OWNER to
= (PTOKEN_OWNER
)TokenInformation
;
2014 DPRINT("NtQueryInformationToken(TokenOwner)\n");
2015 SidLen
= RtlLengthSid(Token
->UserAndGroups
[Token
->DefaultOwnerIndex
].Sid
);
2016 RequiredLength
= sizeof(TOKEN_OWNER
) + SidLen
;
2020 if (TokenInformationLength
>= RequiredLength
)
2022 to
->Owner
= (PSID
)(to
+ 1);
2023 Status
= RtlCopySid(SidLen
,
2025 Token
->UserAndGroups
[Token
->DefaultOwnerIndex
].Sid
);
2029 Status
= STATUS_BUFFER_TOO_SMALL
;
2032 if (ReturnLength
!= NULL
)
2034 *ReturnLength
= RequiredLength
;
2037 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2039 Status
= _SEH2_GetExceptionCode();
2046 case TokenPrimaryGroup
:
2048 PTOKEN_PRIMARY_GROUP tpg
= (PTOKEN_PRIMARY_GROUP
)TokenInformation
;
2051 DPRINT("NtQueryInformationToken(TokenPrimaryGroup)\n");
2052 SidLen
= RtlLengthSid(Token
->PrimaryGroup
);
2053 RequiredLength
= sizeof(TOKEN_PRIMARY_GROUP
) + SidLen
;
2057 if (TokenInformationLength
>= RequiredLength
)
2059 tpg
->PrimaryGroup
= (PSID
)(tpg
+ 1);
2060 Status
= RtlCopySid(SidLen
,
2062 Token
->PrimaryGroup
);
2066 Status
= STATUS_BUFFER_TOO_SMALL
;
2069 if (ReturnLength
!= NULL
)
2071 *ReturnLength
= RequiredLength
;
2074 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2076 Status
= _SEH2_GetExceptionCode();
2083 case TokenDefaultDacl
:
2085 PTOKEN_DEFAULT_DACL tdd
= (PTOKEN_DEFAULT_DACL
)TokenInformation
;
2087 DPRINT("NtQueryInformationToken(TokenDefaultDacl)\n");
2088 RequiredLength
= sizeof(TOKEN_DEFAULT_DACL
);
2090 if (Token
->DefaultDacl
!= NULL
)
2091 RequiredLength
+= Token
->DefaultDacl
->AclSize
;
2095 if (TokenInformationLength
>= RequiredLength
)
2097 if (Token
->DefaultDacl
!= NULL
)
2099 tdd
->DefaultDacl
= (PACL
)(tdd
+ 1);
2100 RtlCopyMemory(tdd
->DefaultDacl
,
2102 Token
->DefaultDacl
->AclSize
);
2106 tdd
->DefaultDacl
= NULL
;
2111 Status
= STATUS_BUFFER_TOO_SMALL
;
2114 if (ReturnLength
!= NULL
)
2116 *ReturnLength
= RequiredLength
;
2119 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2121 Status
= _SEH2_GetExceptionCode();
2130 PTOKEN_SOURCE ts
= (PTOKEN_SOURCE
)TokenInformation
;
2132 DPRINT("NtQueryInformationToken(TokenSource)\n");
2133 RequiredLength
= sizeof(TOKEN_SOURCE
);
2137 if (TokenInformationLength
>= RequiredLength
)
2139 *ts
= Token
->TokenSource
;
2143 Status
= STATUS_BUFFER_TOO_SMALL
;
2146 if (ReturnLength
!= NULL
)
2148 *ReturnLength
= RequiredLength
;
2151 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2153 Status
= _SEH2_GetExceptionCode();
2162 PTOKEN_TYPE tt
= (PTOKEN_TYPE
)TokenInformation
;
2164 DPRINT("NtQueryInformationToken(TokenType)\n");
2165 RequiredLength
= sizeof(TOKEN_TYPE
);
2169 if (TokenInformationLength
>= RequiredLength
)
2171 *tt
= Token
->TokenType
;
2175 Status
= STATUS_BUFFER_TOO_SMALL
;
2178 if (ReturnLength
!= NULL
)
2180 *ReturnLength
= RequiredLength
;
2183 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2185 Status
= _SEH2_GetExceptionCode();
2192 case TokenImpersonationLevel
:
2194 PSECURITY_IMPERSONATION_LEVEL sil
= (PSECURITY_IMPERSONATION_LEVEL
)TokenInformation
;
2196 DPRINT("NtQueryInformationToken(TokenImpersonationLevel)\n");
2198 /* Fail if the token is not an impersonation token */
2199 if (Token
->TokenType
!= TokenImpersonation
)
2201 Status
= STATUS_INVALID_INFO_CLASS
;
2205 RequiredLength
= sizeof(SECURITY_IMPERSONATION_LEVEL
);
2209 if (TokenInformationLength
>= RequiredLength
)
2211 *sil
= Token
->ImpersonationLevel
;
2215 Status
= STATUS_BUFFER_TOO_SMALL
;
2218 if (ReturnLength
!= NULL
)
2220 *ReturnLength
= RequiredLength
;
2223 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2225 Status
= _SEH2_GetExceptionCode();
2232 case TokenStatistics
:
2234 PTOKEN_STATISTICS ts
= (PTOKEN_STATISTICS
)TokenInformation
;
2236 DPRINT("NtQueryInformationToken(TokenStatistics)\n");
2237 RequiredLength
= sizeof(TOKEN_STATISTICS
);
2241 if (TokenInformationLength
>= RequiredLength
)
2243 ts
->TokenId
= Token
->TokenId
;
2244 ts
->AuthenticationId
= Token
->AuthenticationId
;
2245 ts
->ExpirationTime
= Token
->ExpirationTime
;
2246 ts
->TokenType
= Token
->TokenType
;
2247 ts
->ImpersonationLevel
= Token
->ImpersonationLevel
;
2248 ts
->DynamicCharged
= Token
->DynamicCharged
;
2249 ts
->DynamicAvailable
= Token
->DynamicAvailable
;
2250 ts
->GroupCount
= Token
->UserAndGroupCount
- 1;
2251 ts
->PrivilegeCount
= Token
->PrivilegeCount
;
2252 ts
->ModifiedId
= Token
->ModifiedId
;
2256 Status
= STATUS_BUFFER_TOO_SMALL
;
2259 if (ReturnLength
!= NULL
)
2261 *ReturnLength
= RequiredLength
;
2264 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2266 Status
= _SEH2_GetExceptionCode();
2275 PTOKEN_ORIGIN to
= (PTOKEN_ORIGIN
)TokenInformation
;
2277 DPRINT("NtQueryInformationToken(TokenOrigin)\n");
2278 RequiredLength
= sizeof(TOKEN_ORIGIN
);
2282 if (TokenInformationLength
>= RequiredLength
)
2284 RtlCopyLuid(&to
->OriginatingLogonSession
,
2285 &Token
->AuthenticationId
);
2289 Status
= STATUS_BUFFER_TOO_SMALL
;
2292 if (ReturnLength
!= NULL
)
2294 *ReturnLength
= RequiredLength
;
2297 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2299 Status
= _SEH2_GetExceptionCode();
2306 case TokenGroupsAndPrivileges
:
2307 DPRINT1("NtQueryInformationToken(TokenGroupsAndPrivileges) not implemented\n");
2308 Status
= STATUS_NOT_IMPLEMENTED
;
2311 case TokenRestrictedSids
:
2313 PTOKEN_GROUPS tg
= (PTOKEN_GROUPS
)TokenInformation
;
2315 DPRINT("NtQueryInformationToken(TokenRestrictedSids)\n");
2316 RequiredLength
= sizeof(tg
->GroupCount
) +
2317 RtlLengthSidAndAttributes(Token
->RestrictedSidCount
, Token
->RestrictedSids
);
2321 if (TokenInformationLength
>= RequiredLength
)
2323 ULONG SidLen
= RequiredLength
- sizeof(tg
->GroupCount
) -
2324 (Token
->RestrictedSidCount
* sizeof(SID_AND_ATTRIBUTES
));
2325 PSID Sid
= (PSID
)((ULONG_PTR
)tg
+ sizeof(tg
->GroupCount
) +
2326 (Token
->RestrictedSidCount
* sizeof(SID_AND_ATTRIBUTES
)));
2328 tg
->GroupCount
= Token
->RestrictedSidCount
;
2329 Status
= RtlCopySidAndAttributesArray(Token
->RestrictedSidCount
,
2330 Token
->RestrictedSids
,
2339 Status
= STATUS_BUFFER_TOO_SMALL
;
2342 if (ReturnLength
!= NULL
)
2344 *ReturnLength
= RequiredLength
;
2347 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2349 Status
= _SEH2_GetExceptionCode();
2356 case TokenSandBoxInert
:
2357 DPRINT1("NtQueryInformationToken(TokenSandboxInert) not implemented\n");
2358 Status
= STATUS_NOT_IMPLEMENTED
;
2361 case TokenSessionId
:
2363 ULONG SessionId
= 0;
2365 DPRINT("NtQueryInformationToken(TokenSessionId)\n");
2367 Status
= SeQuerySessionIdToken(Token
, &SessionId
);
2368 if (NT_SUCCESS(Status
))
2372 /* Buffer size was already verified, no need to check here again */
2373 *(PULONG
)TokenInformation
= SessionId
;
2375 if (ReturnLength
!= NULL
)
2377 *ReturnLength
= sizeof(ULONG
);
2380 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2382 Status
= _SEH2_GetExceptionCode();
2391 DPRINT1("NtQueryInformationToken(%d) invalid information class\n", TokenInformationClass
);
2392 Status
= STATUS_INVALID_INFO_CLASS
;
2396 /* Unlock and dereference the token */
2397 SepReleaseTokenLock(Token
);
2398 ObDereferenceObject(Token
);
2406 * NtSetTokenInformation: Partly implemented.
2408 * TokenOrigin, TokenDefaultDacl
2410 _Must_inspect_result_
2414 NtSetInformationToken(
2415 _In_ HANDLE TokenHandle
,
2416 _In_ TOKEN_INFORMATION_CLASS TokenInformationClass
,
2417 _In_reads_bytes_(TokenInformationLength
) PVOID TokenInformation
,
2418 _In_ ULONG TokenInformationLength
)
2422 KPROCESSOR_MODE PreviousMode
;
2423 ULONG NeededAccess
= TOKEN_ADJUST_DEFAULT
;
2427 PreviousMode
= ExGetPreviousMode();
2429 Status
= DefaultSetInfoBufferCheck(TokenInformationClass
,
2430 SeTokenInformationClass
,
2431 RTL_NUMBER_OF(SeTokenInformationClass
),
2433 TokenInformationLength
,
2435 if (!NT_SUCCESS(Status
))
2437 /* Invalid buffers */
2438 DPRINT("NtSetInformationToken() failed, Status: 0x%x\n", Status
);
2442 if (TokenInformationClass
== TokenSessionId
)
2444 NeededAccess
|= TOKEN_ADJUST_SESSIONID
;
2447 Status
= ObReferenceObjectByHandle(TokenHandle
,
2453 if (NT_SUCCESS(Status
))
2455 switch (TokenInformationClass
)
2459 if (TokenInformationLength
>= sizeof(TOKEN_OWNER
))
2461 PTOKEN_OWNER to
= (PTOKEN_OWNER
)TokenInformation
;
2462 PSID InputSid
= NULL
, CapturedSid
;
2463 ULONG DefaultOwnerIndex
;
2467 InputSid
= to
->Owner
;
2469 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2471 Status
= _SEH2_GetExceptionCode();
2472 _SEH2_YIELD(goto Cleanup
);
2476 Status
= SepCaptureSid(InputSid
,
2481 if (NT_SUCCESS(Status
))
2483 /* Lock the token */
2484 SepAcquireTokenLockExclusive(Token
);
2486 /* Find the owner amongst the existing token user and groups */
2487 Status
= SepFindPrimaryGroupAndDefaultOwner(Token
,
2491 &DefaultOwnerIndex
);
2492 if (NT_SUCCESS(Status
))
2495 Token
->DefaultOwnerIndex
= DefaultOwnerIndex
;
2496 ExAllocateLocallyUniqueId(&Token
->ModifiedId
);
2499 /* Unlock the token */
2500 SepReleaseTokenLock(Token
);
2502 SepReleaseSid(CapturedSid
,
2509 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2514 case TokenPrimaryGroup
:
2516 if (TokenInformationLength
>= sizeof(TOKEN_PRIMARY_GROUP
))
2518 PTOKEN_PRIMARY_GROUP tpg
= (PTOKEN_PRIMARY_GROUP
)TokenInformation
;
2519 PSID InputSid
= NULL
, CapturedSid
;
2520 ULONG PrimaryGroupIndex
;
2524 InputSid
= tpg
->PrimaryGroup
;
2526 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2528 Status
= _SEH2_GetExceptionCode();
2529 _SEH2_YIELD(goto Cleanup
);
2533 Status
= SepCaptureSid(InputSid
,
2538 if (NT_SUCCESS(Status
))
2540 /* Lock the token */
2541 SepAcquireTokenLockExclusive(Token
);
2543 /* Find the primary group amongst the existing token user and groups */
2544 Status
= SepFindPrimaryGroupAndDefaultOwner(Token
,
2549 if (NT_SUCCESS(Status
))
2552 Token
->PrimaryGroup
= Token
->UserAndGroups
[PrimaryGroupIndex
].Sid
;
2553 ExAllocateLocallyUniqueId(&Token
->ModifiedId
);
2556 /* Unlock the token */
2557 SepReleaseTokenLock(Token
);
2559 SepReleaseSid(CapturedSid
,
2566 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2571 case TokenDefaultDacl
:
2573 if (TokenInformationLength
>= sizeof(TOKEN_DEFAULT_DACL
))
2575 PTOKEN_DEFAULT_DACL tdd
= (PTOKEN_DEFAULT_DACL
)TokenInformation
;
2576 PACL InputAcl
= NULL
;
2580 InputAcl
= tdd
->DefaultDacl
;
2582 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2584 Status
= _SEH2_GetExceptionCode();
2585 _SEH2_YIELD(goto Cleanup
);
2589 if (InputAcl
!= NULL
)
2593 /* Capture and copy the dacl */
2594 Status
= SepCaptureAcl(InputAcl
,
2599 if (NT_SUCCESS(Status
))
2601 ULONG DynamicLength
;
2603 /* Lock the token */
2604 SepAcquireTokenLockExclusive(Token
);
2607 // NOTE: So far our dynamic area only contains
2608 // the default dacl, so this makes the following
2609 // code pretty simple. The day where it stores
2610 // other data, the code will require adaptations.
2613 DynamicLength
= Token
->DynamicAvailable
;
2614 // Add here any other data length present in the dynamic area...
2615 if (Token
->DefaultDacl
)
2616 DynamicLength
+= Token
->DefaultDacl
->AclSize
;
2618 /* Reallocate the dynamic area if it is too small */
2619 Status
= STATUS_SUCCESS
;
2620 if ((DynamicLength
< CapturedAcl
->AclSize
) ||
2621 (Token
->DynamicPart
== NULL
))
2623 PVOID NewDynamicPart
;
2625 NewDynamicPart
= ExAllocatePoolWithTag(PagedPool
,
2626 CapturedAcl
->AclSize
,
2628 if (NewDynamicPart
== NULL
)
2630 Status
= STATUS_INSUFFICIENT_RESOURCES
;
2634 if (Token
->DynamicPart
!= NULL
)
2636 // RtlCopyMemory(NewDynamicPart, Token->DynamicPart, DynamicLength);
2637 ExFreePoolWithTag(Token
->DynamicPart
, TAG_TOKEN_DYNAMIC
);
2639 Token
->DynamicPart
= NewDynamicPart
;
2640 Token
->DynamicAvailable
= 0;
2645 Token
->DynamicAvailable
= DynamicLength
- CapturedAcl
->AclSize
;
2648 if (NT_SUCCESS(Status
))
2650 /* Set the new dacl */
2651 Token
->DefaultDacl
= (PVOID
)Token
->DynamicPart
;
2652 RtlCopyMemory(Token
->DefaultDacl
,
2654 CapturedAcl
->AclSize
);
2656 ExAllocateLocallyUniqueId(&Token
->ModifiedId
);
2659 /* Unlock the token */
2660 SepReleaseTokenLock(Token
);
2662 ExFreePoolWithTag(CapturedAcl
, TAG_ACL
);
2667 /* Lock the token */
2668 SepAcquireTokenLockExclusive(Token
);
2670 /* Clear the default dacl if present */
2671 if (Token
->DefaultDacl
!= NULL
)
2673 Token
->DynamicAvailable
+= Token
->DefaultDacl
->AclSize
;
2674 RtlZeroMemory(Token
->DefaultDacl
, Token
->DefaultDacl
->AclSize
);
2675 Token
->DefaultDacl
= NULL
;
2677 ExAllocateLocallyUniqueId(&Token
->ModifiedId
);
2680 /* Unlock the token */
2681 SepReleaseTokenLock(Token
);
2686 Status
= STATUS_INFO_LENGTH_MISMATCH
;
2691 case TokenSessionId
:
2693 ULONG SessionId
= 0;
2697 /* Buffer size was already verified, no need to check here again */
2698 SessionId
= *(PULONG
)TokenInformation
;
2700 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2702 Status
= _SEH2_GetExceptionCode();
2703 _SEH2_YIELD(goto Cleanup
);
2707 /* Check for TCB privilege */
2708 if (!SeSinglePrivilegeCheck(SeTcbPrivilege
, PreviousMode
))
2710 Status
= STATUS_PRIVILEGE_NOT_HELD
;
2714 /* Lock the token */
2715 SepAcquireTokenLockExclusive(Token
);
2717 Token
->SessionId
= SessionId
;
2718 ExAllocateLocallyUniqueId(&Token
->ModifiedId
);
2720 /* Unlock the token */
2721 SepReleaseTokenLock(Token
);
2726 case TokenSessionReference
:
2728 ULONG SessionReference
;
2732 /* Buffer size was already verified, no need to check here again */
2733 SessionReference
= *(PULONG
)TokenInformation
;
2735 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2737 Status
= _SEH2_GetExceptionCode();
2738 _SEH2_YIELD(goto Cleanup
);
2742 /* Check for TCB privilege */
2743 if (!SeSinglePrivilegeCheck(SeTcbPrivilege
, PreviousMode
))
2745 Status
= STATUS_PRIVILEGE_NOT_HELD
;
2749 /* Check if it is 0 */
2750 if (SessionReference
== 0)
2752 ULONG OldTokenFlags
;
2754 /* Lock the token */
2755 SepAcquireTokenLockExclusive(Token
);
2757 /* Atomically set the flag in the token */
2758 OldTokenFlags
= RtlInterlockedSetBits(&Token
->TokenFlags
,
2759 TOKEN_SESSION_NOT_REFERENCED
);
2761 * If the flag was already set, do not dereference again
2762 * the logon session. Use SessionReference as an indicator
2763 * to know whether to really dereference the session.
2765 if (OldTokenFlags
== Token
->TokenFlags
)
2766 SessionReference
= ULONG_MAX
;
2768 /* Unlock the token */
2769 SepReleaseTokenLock(Token
);
2772 /* Dereference the logon session if needed */
2773 if (SessionReference
== 0)
2774 SepRmDereferenceLogonSession(&Token
->AuthenticationId
);
2779 case TokenAuditPolicy
:
2781 PTOKEN_AUDIT_POLICY_INFORMATION PolicyInformation
=
2782 (PTOKEN_AUDIT_POLICY_INFORMATION
)TokenInformation
;
2783 SEP_AUDIT_POLICY AuditPolicy
;
2788 ProbeForRead(PolicyInformation
,
2789 FIELD_OFFSET(TOKEN_AUDIT_POLICY_INFORMATION
,
2790 Policies
[PolicyInformation
->PolicyCount
]),
2793 /* Loop all policies in the structure */
2794 for (i
= 0; i
< PolicyInformation
->PolicyCount
; i
++)
2796 /* Set the corresponding bits in the packed structure */
2797 switch (PolicyInformation
->Policies
[i
].Category
)
2799 case AuditCategorySystem
:
2800 AuditPolicy
.PolicyElements
.System
= PolicyInformation
->Policies
[i
].Value
;
2803 case AuditCategoryLogon
:
2804 AuditPolicy
.PolicyElements
.Logon
= PolicyInformation
->Policies
[i
].Value
;
2807 case AuditCategoryObjectAccess
:
2808 AuditPolicy
.PolicyElements
.ObjectAccess
= PolicyInformation
->Policies
[i
].Value
;
2811 case AuditCategoryPrivilegeUse
:
2812 AuditPolicy
.PolicyElements
.PrivilegeUse
= PolicyInformation
->Policies
[i
].Value
;
2815 case AuditCategoryDetailedTracking
:
2816 AuditPolicy
.PolicyElements
.DetailedTracking
= PolicyInformation
->Policies
[i
].Value
;
2819 case AuditCategoryPolicyChange
:
2820 AuditPolicy
.PolicyElements
.PolicyChange
= PolicyInformation
->Policies
[i
].Value
;
2823 case AuditCategoryAccountManagement
:
2824 AuditPolicy
.PolicyElements
.AccountManagement
= PolicyInformation
->Policies
[i
].Value
;
2827 case AuditCategoryDirectoryServiceAccess
:
2828 AuditPolicy
.PolicyElements
.DirectoryServiceAccess
= PolicyInformation
->Policies
[i
].Value
;
2831 case AuditCategoryAccountLogon
:
2832 AuditPolicy
.PolicyElements
.AccountLogon
= PolicyInformation
->Policies
[i
].Value
;
2837 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2839 Status
= _SEH2_GetExceptionCode();
2840 _SEH2_YIELD(goto Cleanup
);
2844 /* Check for TCB privilege */
2845 if (!SeSinglePrivilegeCheck(SeTcbPrivilege
, PreviousMode
))
2847 Status
= STATUS_PRIVILEGE_NOT_HELD
;
2851 /* Lock the token */
2852 SepAcquireTokenLockExclusive(Token
);
2854 /* Set the new audit policy */
2855 Token
->AuditPolicy
= AuditPolicy
;
2856 ExAllocateLocallyUniqueId(&Token
->ModifiedId
);
2858 /* Unlock the token */
2859 SepReleaseTokenLock(Token
);
2866 TOKEN_ORIGIN TokenOrigin
;
2870 /* Copy the token origin */
2871 TokenOrigin
= *(PTOKEN_ORIGIN
)TokenInformation
;
2873 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2875 Status
= _SEH2_GetExceptionCode();
2876 _SEH2_YIELD(goto Cleanup
);
2880 /* Check for TCB privilege */
2881 if (!SeSinglePrivilegeCheck(SeTcbPrivilege
, PreviousMode
))
2883 Status
= STATUS_PRIVILEGE_NOT_HELD
;
2887 /* Lock the token */
2888 SepAcquireTokenLockExclusive(Token
);
2890 /* Check if there is no token origin set yet */
2891 if (RtlIsZeroLuid(&Token
->OriginatingLogonSession
))
2893 /* Set the token origin */
2894 Token
->OriginatingLogonSession
=
2895 TokenOrigin
.OriginatingLogonSession
;
2897 ExAllocateLocallyUniqueId(&Token
->ModifiedId
);
2900 /* Unlock the token */
2901 SepReleaseTokenLock(Token
);
2908 DPRINT1("Invalid TokenInformationClass: 0x%lx\n",
2909 TokenInformationClass
);
2910 Status
= STATUS_INVALID_INFO_CLASS
;
2915 ObDereferenceObject(Token
);
2918 if (!NT_SUCCESS(Status
))
2920 DPRINT1("NtSetInformationToken failed with Status 0x%lx\n", Status
);
2930 * NOTE: Some sources claim 4th param is ImpersonationLevel, but on W2K
2931 * this is certainly NOT true, although I can't say for sure that EffectiveOnly
2932 * is correct either. -Gunnar
2933 * This is true. EffectiveOnly overrides SQOS.EffectiveOnly. - IAI
2934 * NOTE for readers: http://hex.pp.ua/nt/NtDuplicateToken.php is therefore
2935 * wrong in that regard, while MSDN documentation is correct.
2937 _Must_inspect_result_
2942 _In_ HANDLE ExistingTokenHandle
,
2943 _In_ ACCESS_MASK DesiredAccess
,
2944 _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes
,
2945 _In_ BOOLEAN EffectiveOnly
,
2946 _In_ TOKEN_TYPE TokenType
,
2947 _Out_ PHANDLE NewTokenHandle
)
2949 KPROCESSOR_MODE PreviousMode
;
2953 PSECURITY_QUALITY_OF_SERVICE CapturedSecurityQualityOfService
;
2955 OBJECT_HANDLE_INFORMATION HandleInformation
;
2960 if (TokenType
!= TokenImpersonation
&&
2961 TokenType
!= TokenPrimary
)
2963 return STATUS_INVALID_PARAMETER
;
2966 PreviousMode
= KeGetPreviousMode();
2968 if (PreviousMode
!= KernelMode
)
2972 ProbeForWriteHandle(NewTokenHandle
);
2974 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2976 /* Return the exception code */
2977 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2982 Status
= SepCaptureSecurityQualityOfService(ObjectAttributes
,
2986 &CapturedSecurityQualityOfService
,
2988 if (!NT_SUCCESS(Status
))
2990 DPRINT1("NtDuplicateToken() failed to capture QoS! Status: 0x%x\n", Status
);
2994 Status
= ObReferenceObjectByHandle(ExistingTokenHandle
,
2999 &HandleInformation
);
3000 if (!NT_SUCCESS(Status
))
3002 DPRINT1("Failed to reference token (Status 0x%lx)\n", Status
);
3003 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService
,
3010 * Fail, if the original token is an impersonation token and the caller
3011 * tries to raise the impersonation level of the new token above the
3012 * impersonation level of the original token.
3014 if (Token
->TokenType
== TokenImpersonation
)
3017 CapturedSecurityQualityOfService
->ImpersonationLevel
>Token
->ImpersonationLevel
)
3019 ObDereferenceObject(Token
);
3020 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService
,
3023 return STATUS_BAD_IMPERSONATION_LEVEL
;
3028 * Fail, if a primary token is to be created from an impersonation token
3029 * and and the impersonation level of the impersonation token is below SecurityImpersonation.
3031 if (Token
->TokenType
== TokenImpersonation
&&
3032 TokenType
== TokenPrimary
&&
3033 Token
->ImpersonationLevel
< SecurityImpersonation
)
3035 ObDereferenceObject(Token
);
3036 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService
,
3039 return STATUS_BAD_IMPERSONATION_LEVEL
;
3042 Status
= SepDuplicateToken(Token
,
3046 (QoSPresent
? CapturedSecurityQualityOfService
->ImpersonationLevel
: SecurityAnonymous
),
3050 ObDereferenceObject(Token
);
3052 if (NT_SUCCESS(Status
))
3054 Status
= ObInsertObject(NewToken
,
3056 (DesiredAccess
? DesiredAccess
: HandleInformation
.GrantedAccess
),
3060 if (NT_SUCCESS(Status
))
3064 *NewTokenHandle
= hToken
;
3066 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3068 Status
= _SEH2_GetExceptionCode();
3074 /* Free the captured structure */
3075 SepReleaseSecurityQualityOfService(CapturedSecurityQualityOfService
,
3083 NtAdjustGroupsToken(IN HANDLE TokenHandle
,
3084 IN BOOLEAN ResetToDefault
,
3085 IN PTOKEN_GROUPS NewState
,
3086 IN ULONG BufferLength
,
3087 OUT PTOKEN_GROUPS PreviousState OPTIONAL
,
3088 OUT PULONG ReturnLength
)
3091 return STATUS_NOT_IMPLEMENTED
;
3097 SepAdjustPrivileges(
3098 _Inout_ PTOKEN Token
,
3099 _In_ BOOLEAN DisableAllPrivileges
,
3100 _In_opt_ PLUID_AND_ATTRIBUTES NewState
,
3101 _In_ ULONG NewStateCount
,
3102 _Out_opt_ PTOKEN_PRIVILEGES PreviousState
,
3103 _In_ BOOLEAN ApplyChanges
,
3104 _Out_ PULONG ChangedPrivileges
,
3105 _Out_ PBOOLEAN ChangesMade
)
3107 ULONG i
, j
, PrivilegeCount
, ChangeCount
, NewAttributes
;
3109 /* Count the found privileges and those that need to be changed */
3112 *ChangesMade
= FALSE
;
3114 /* Loop all privileges in the token */
3115 for (i
= 0; i
< Token
->PrivilegeCount
; i
++)
3117 /* Shall all of them be disabled? */
3118 if (DisableAllPrivileges
)
3120 /* The new attributes are the old ones, but disabled */
3121 NewAttributes
= Token
->Privileges
[i
].Attributes
& ~SE_PRIVILEGE_ENABLED
;
3125 /* Otherwise loop all provided privileges */
3126 for (j
= 0; j
< NewStateCount
; j
++)
3128 /* Check if this is the LUID we are looking for */
3129 if (RtlEqualLuid(&Token
->Privileges
[i
].Luid
, &NewState
[j
].Luid
))
3131 DPRINT("Found privilege\n");
3133 /* Copy SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_REMOVED */
3134 NewAttributes
= NewState
[j
].Attributes
;
3135 NewAttributes
&= (SE_PRIVILEGE_ENABLED
| SE_PRIVILEGE_REMOVED
);
3136 NewAttributes
|= Token
->Privileges
[i
].Attributes
& ~SE_PRIVILEGE_ENABLED
;
3143 /* Check if we didn't find the privilege */
3144 if (j
== NewStateCount
)
3146 /* Continue with the token's next privilege */
3151 /* We found a privilege, count it */
3154 /* Does the privilege need to be changed? */
3155 if (Token
->Privileges
[i
].Attributes
!= NewAttributes
)
3157 /* Does the caller want the old privileges? */
3158 if (PreviousState
!= NULL
)
3160 /* Copy the old privilege */
3161 PreviousState
->Privileges
[ChangeCount
] = Token
->Privileges
[i
];
3164 /* Does the caller want to apply the changes? */
3167 /* Shall we remove the privilege? */
3168 if (NewAttributes
& SE_PRIVILEGE_REMOVED
)
3170 /* Set the token as disabled and update flags for it */
3171 Token
->Privileges
[i
].Attributes
&= ~SE_PRIVILEGE_ENABLED
;
3172 SepUpdateSinglePrivilegeFlagToken(Token
, i
);
3174 /* Remove the privilege */
3175 SepRemovePrivilegeToken(Token
, i
);
3177 *ChangesMade
= TRUE
;
3179 /* Fix the running index and continue with next one */
3184 /* Set the new attributes and update flags */
3185 Token
->Privileges
[i
].Attributes
= NewAttributes
;
3186 SepUpdateSinglePrivilegeFlagToken(Token
, i
);
3187 *ChangesMade
= TRUE
;
3190 /* Increment the change count */
3195 /* Set the number of saved privileges */
3196 if (PreviousState
!= NULL
)
3197 PreviousState
->PrivilegeCount
= ChangeCount
;
3199 /* Return the number of changed privileges */
3200 *ChangedPrivileges
= ChangeCount
;
3202 /* Check if we missed some */
3203 if (!DisableAllPrivileges
&& (PrivilegeCount
< NewStateCount
))
3205 return STATUS_NOT_ALL_ASSIGNED
;
3208 return STATUS_SUCCESS
;
3215 _Must_inspect_result_
3219 NtAdjustPrivilegesToken(
3220 _In_ HANDLE TokenHandle
,
3221 _In_ BOOLEAN DisableAllPrivileges
,
3222 _In_opt_ PTOKEN_PRIVILEGES NewState
,
3223 _In_ ULONG BufferLength
,
3224 _Out_writes_bytes_to_opt_(BufferLength
,*ReturnLength
)
3225 PTOKEN_PRIVILEGES PreviousState
,
3226 _When_(PreviousState
!=NULL
, _Out_
) PULONG ReturnLength
)
3229 KPROCESSOR_MODE PreviousMode
;
3231 PLUID_AND_ATTRIBUTES CapturedPrivileges
= NULL
;
3232 ULONG CapturedCount
= 0;
3233 ULONG CapturedLength
= 0;
3234 ULONG NewStateSize
= 0;
3236 ULONG RequiredLength
;
3237 BOOLEAN ChangesMade
= FALSE
;
3241 DPRINT("NtAdjustPrivilegesToken() called\n");
3243 /* Fail, if we do not disable all privileges but NewState is NULL */
3244 if (DisableAllPrivileges
== FALSE
&& NewState
== NULL
)
3245 return STATUS_INVALID_PARAMETER
;
3247 PreviousMode
= KeGetPreviousMode();
3248 if (PreviousMode
!= KernelMode
)
3252 /* Probe NewState */
3253 if (DisableAllPrivileges
== FALSE
)
3255 /* First probe the header */
3256 ProbeForRead(NewState
, sizeof(TOKEN_PRIVILEGES
), sizeof(ULONG
));
3258 CapturedCount
= NewState
->PrivilegeCount
;
3259 NewStateSize
= FIELD_OFFSET(TOKEN_PRIVILEGES
, Privileges
[CapturedCount
]);
3261 ProbeForRead(NewState
, NewStateSize
, sizeof(ULONG
));
3264 /* Probe PreviousState and ReturnLength */
3265 if (PreviousState
!= NULL
)
3267 ProbeForWrite(PreviousState
, BufferLength
, sizeof(ULONG
));
3268 ProbeForWrite(ReturnLength
, sizeof(ULONG
), sizeof(ULONG
));
3271 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3273 /* Return the exception code */
3274 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3280 /* This is kernel mode, we trust the caller */
3281 if (DisableAllPrivileges
== FALSE
)
3282 CapturedCount
= NewState
->PrivilegeCount
;
3285 /* Do we need to capture the new state? */
3286 if (DisableAllPrivileges
== FALSE
)
3290 /* Capture the new state array of privileges */
3291 Status
= SeCaptureLuidAndAttributesArray(NewState
->Privileges
,
3298 &CapturedPrivileges
,
3301 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3303 /* Return the exception code */
3304 Status
= _SEH2_GetExceptionCode();
3308 if (!NT_SUCCESS(Status
))
3312 /* Reference the token */
3313 Status
= ObReferenceObjectByHandle(TokenHandle
,
3314 TOKEN_ADJUST_PRIVILEGES
| (PreviousState
!= NULL
? TOKEN_QUERY
: 0),
3319 if (!NT_SUCCESS(Status
))
3321 DPRINT1("Failed to reference token (Status 0x%lx)\n", Status
);
3323 /* Release the captured privileges */
3324 if (CapturedPrivileges
!= NULL
)
3326 SeReleaseLuidAndAttributesArray(CapturedPrivileges
,
3334 /* Lock the token */
3335 SepAcquireTokenLockExclusive(Token
);
3337 /* Count the privileges that need to be changed, do not apply them yet */
3338 Status
= SepAdjustPrivileges(Token
,
3339 DisableAllPrivileges
,
3347 /* Check if the caller asked for the previous state */
3348 if (PreviousState
!= NULL
)
3350 /* Calculate the required length */
3351 RequiredLength
= FIELD_OFFSET(TOKEN_PRIVILEGES
, Privileges
[ChangeCount
]);
3353 /* Try to return the required buffer length */
3356 *ReturnLength
= RequiredLength
;
3358 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3360 /* Do cleanup and return the exception code */
3361 Status
= _SEH2_GetExceptionCode();
3362 _SEH2_YIELD(goto Cleanup
);
3366 /* Fail, if the buffer length is smaller than the required length */
3367 if (BufferLength
< RequiredLength
)
3369 Status
= STATUS_BUFFER_TOO_SMALL
;
3374 /* Now enter SEH, since we might return the old privileges */
3377 /* This time apply the changes */
3378 Status
= SepAdjustPrivileges(Token
,
3379 DisableAllPrivileges
,
3387 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3389 /* Do cleanup and return the exception code */
3390 Status
= _SEH2_GetExceptionCode();
3391 ChangesMade
= TRUE
; // Force write.
3392 _SEH2_YIELD(goto Cleanup
);
3397 /* Touch the token if we made changes */
3399 ExAllocateLocallyUniqueId(&Token
->ModifiedId
);
3401 /* Unlock and dereference the token */
3402 SepReleaseTokenLock(Token
);
3403 ObDereferenceObject(Token
);
3405 /* Release the captured privileges */
3406 if (CapturedPrivileges
!= NULL
)
3408 SeReleaseLuidAndAttributesArray(CapturedPrivileges
,
3413 DPRINT ("NtAdjustPrivilegesToken() done\n");
3421 _Out_ PHANDLE TokenHandle
,
3422 _In_ ACCESS_MASK DesiredAccess
,
3423 _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes
,
3424 _In_ TOKEN_TYPE TokenType
,
3425 _In_ PLUID AuthenticationId
,
3426 _In_ PLARGE_INTEGER ExpirationTime
,
3427 _In_ PTOKEN_USER TokenUser
,
3428 _In_ PTOKEN_GROUPS TokenGroups
,
3429 _In_ PTOKEN_PRIVILEGES TokenPrivileges
,
3430 _In_opt_ PTOKEN_OWNER TokenOwner
,
3431 _In_ PTOKEN_PRIMARY_GROUP TokenPrimaryGroup
,
3432 _In_opt_ PTOKEN_DEFAULT_DACL TokenDefaultDacl
,
3433 _In_ PTOKEN_SOURCE TokenSource
)
3436 KPROCESSOR_MODE PreviousMode
;
3437 ULONG PrivilegeCount
, GroupCount
;
3438 PSID OwnerSid
, PrimaryGroupSid
;
3440 LARGE_INTEGER LocalExpirationTime
= {{0, 0}};
3441 LUID LocalAuthenticationId
;
3442 TOKEN_SOURCE LocalTokenSource
;
3443 SECURITY_QUALITY_OF_SERVICE LocalSecurityQos
;
3444 PLUID_AND_ATTRIBUTES CapturedPrivileges
= NULL
;
3445 PSID_AND_ATTRIBUTES CapturedUser
= NULL
;
3446 PSID_AND_ATTRIBUTES CapturedGroups
= NULL
;
3447 PSID CapturedOwnerSid
= NULL
;
3448 PSID CapturedPrimaryGroupSid
= NULL
;
3449 PACL CapturedDefaultDacl
= NULL
;
3450 ULONG PrivilegesLength
, UserLength
, GroupsLength
;
3455 PreviousMode
= ExGetPreviousMode();
3457 if (PreviousMode
!= KernelMode
)
3461 ProbeForWriteHandle(TokenHandle
);
3463 if (ObjectAttributes
!= NULL
)
3465 ProbeForRead(ObjectAttributes
,
3466 sizeof(OBJECT_ATTRIBUTES
),
3468 LocalSecurityQos
= *(SECURITY_QUALITY_OF_SERVICE
*)ObjectAttributes
->SecurityQualityOfService
;
3471 ProbeForRead(AuthenticationId
,
3474 LocalAuthenticationId
= *AuthenticationId
;
3476 LocalExpirationTime
= ProbeForReadLargeInteger(ExpirationTime
);
3478 ProbeForRead(TokenUser
,
3482 ProbeForRead(TokenGroups
,
3483 sizeof(TOKEN_GROUPS
),
3485 GroupCount
= TokenGroups
->GroupCount
;
3487 ProbeForRead(TokenPrivileges
,
3488 sizeof(TOKEN_PRIVILEGES
),
3490 PrivilegeCount
= TokenPrivileges
->PrivilegeCount
;
3492 if (TokenOwner
!= NULL
)
3494 ProbeForRead(TokenOwner
,
3495 sizeof(TOKEN_OWNER
),
3497 OwnerSid
= TokenOwner
->Owner
;
3504 ProbeForRead(TokenPrimaryGroup
,
3505 sizeof(TOKEN_PRIMARY_GROUP
),
3507 PrimaryGroupSid
= TokenPrimaryGroup
->PrimaryGroup
;
3509 if (TokenDefaultDacl
!= NULL
)
3511 ProbeForRead(TokenDefaultDacl
,
3512 sizeof(TOKEN_DEFAULT_DACL
),
3514 DefaultDacl
= TokenDefaultDacl
->DefaultDacl
;
3521 ProbeForRead(TokenSource
,
3522 sizeof(TOKEN_SOURCE
),
3524 LocalTokenSource
= *TokenSource
;
3526 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3528 /* Return the exception code */
3529 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3535 if (ObjectAttributes
!= NULL
)
3536 LocalSecurityQos
= *(SECURITY_QUALITY_OF_SERVICE
*)ObjectAttributes
->SecurityQualityOfService
;
3537 LocalAuthenticationId
= *AuthenticationId
;
3538 LocalExpirationTime
= *ExpirationTime
;
3539 GroupCount
= TokenGroups
->GroupCount
;
3540 PrivilegeCount
= TokenPrivileges
->PrivilegeCount
;
3541 OwnerSid
= TokenOwner
? TokenOwner
->Owner
: NULL
;
3542 PrimaryGroupSid
= TokenPrimaryGroup
->PrimaryGroup
;
3543 DefaultDacl
= TokenDefaultDacl
? TokenDefaultDacl
->DefaultDacl
: NULL
;
3544 LocalTokenSource
= *TokenSource
;
3547 /* Check token type */
3548 if ((TokenType
< TokenPrimary
) ||
3549 (TokenType
> TokenImpersonation
))
3551 return STATUS_BAD_TOKEN_TYPE
;
3554 /* Check for token creation privilege */
3555 if (!SeSinglePrivilegeCheck(SeCreateTokenPrivilege
, PreviousMode
))
3557 return STATUS_PRIVILEGE_NOT_HELD
;
3560 /* Capture the user SID and attributes */
3561 Status
= SeCaptureSidAndAttributesArray(&TokenUser
->User
,
3570 if (!NT_SUCCESS(Status
))
3575 /* Capture the groups SID and attributes array */
3576 Status
= SeCaptureSidAndAttributesArray(&TokenGroups
->Groups
[0],
3585 if (!NT_SUCCESS(Status
))
3590 /* Capture privileges */
3591 Status
= SeCaptureLuidAndAttributesArray(&TokenPrivileges
->Privileges
[0],
3598 &CapturedPrivileges
,
3600 if (!NT_SUCCESS(Status
))
3605 /* Capture the token owner SID */
3606 if (TokenOwner
!= NULL
)
3608 Status
= SepCaptureSid(OwnerSid
,
3613 if (!NT_SUCCESS(Status
))
3619 /* Capture the token primary group SID */
3620 Status
= SepCaptureSid(PrimaryGroupSid
,
3624 &CapturedPrimaryGroupSid
);
3625 if (!NT_SUCCESS(Status
))
3630 /* Capture DefaultDacl */
3631 if (DefaultDacl
!= NULL
)
3633 Status
= SepCaptureAcl(DefaultDacl
,
3637 &CapturedDefaultDacl
);
3638 if (!NT_SUCCESS(Status
))
3644 /* Call the internal function */
3645 Status
= SepCreateToken(&hToken
,
3650 LocalSecurityQos
.ImpersonationLevel
,
3651 &LocalAuthenticationId
,
3652 &LocalExpirationTime
,
3656 0, // FIXME: Should capture
3660 CapturedPrimaryGroupSid
,
3661 CapturedDefaultDacl
,
3664 if (NT_SUCCESS(Status
))
3668 *TokenHandle
= hToken
;
3670 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3672 Status
= _SEH2_GetExceptionCode();
3679 /* Release what we captured */
3680 SeReleaseSidAndAttributesArray(CapturedUser
, PreviousMode
, FALSE
);
3681 SeReleaseSidAndAttributesArray(CapturedGroups
, PreviousMode
, FALSE
);
3682 SeReleaseLuidAndAttributesArray(CapturedPrivileges
, PreviousMode
, FALSE
);
3683 SepReleaseSid(CapturedOwnerSid
, PreviousMode
, FALSE
);
3684 SepReleaseSid(CapturedPrimaryGroupSid
, PreviousMode
, FALSE
);
3685 SepReleaseAcl(CapturedDefaultDacl
, PreviousMode
, FALSE
);
3695 NtOpenThreadTokenEx(IN HANDLE ThreadHandle
,
3696 IN ACCESS_MASK DesiredAccess
,
3697 IN BOOLEAN OpenAsSelf
,
3698 IN ULONG HandleAttributes
,
3699 OUT PHANDLE TokenHandle
)
3701 PETHREAD Thread
, NewThread
;
3703 PTOKEN Token
, NewToken
= NULL
, PrimaryToken
;
3704 BOOLEAN CopyOnOpen
, EffectiveOnly
;
3705 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
;
3706 SE_IMPERSONATION_STATE ImpersonationState
;
3707 OBJECT_ATTRIBUTES ObjectAttributes
;
3708 SECURITY_DESCRIPTOR SecurityDescriptor
;
3710 KPROCESSOR_MODE PreviousMode
;
3712 BOOLEAN RestoreImpersonation
= FALSE
;
3716 PreviousMode
= ExGetPreviousMode();
3718 if (PreviousMode
!= KernelMode
)
3722 ProbeForWriteHandle(TokenHandle
);
3724 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3726 /* Return the exception code */
3727 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3732 /* Validate object attributes */
3733 HandleAttributes
= ObpValidateAttributes(HandleAttributes
, PreviousMode
);
3736 * At first open the thread token for information access and verify
3737 * that the token associated with thread is valid.
3740 Status
= ObReferenceObjectByHandle(ThreadHandle
, THREAD_QUERY_INFORMATION
,
3741 PsThreadType
, PreviousMode
, (PVOID
*)&Thread
,
3743 if (!NT_SUCCESS(Status
))
3748 Token
= PsReferenceImpersonationToken(Thread
, &CopyOnOpen
, &EffectiveOnly
,
3749 &ImpersonationLevel
);
3752 ObDereferenceObject(Thread
);
3753 return STATUS_NO_TOKEN
;
3756 if (ImpersonationLevel
== SecurityAnonymous
)
3758 PsDereferenceImpersonationToken(Token
);
3759 ObDereferenceObject(Thread
);
3760 return STATUS_CANT_OPEN_ANONYMOUS
;
3764 * Revert to self if OpenAsSelf is specified.
3769 RestoreImpersonation
= PsDisableImpersonation(PsGetCurrentThread(),
3770 &ImpersonationState
);
3775 Status
= ObReferenceObjectByHandle(ThreadHandle
, THREAD_ALL_ACCESS
,
3776 PsThreadType
, KernelMode
,
3777 (PVOID
*)&NewThread
, NULL
);
3778 if (NT_SUCCESS(Status
))
3780 PrimaryToken
= PsReferencePrimaryToken(NewThread
->ThreadsProcess
);
3782 Status
= SepCreateImpersonationTokenDacl(Token
, PrimaryToken
, &Dacl
);
3784 ObFastDereferenceObject(&NewThread
->ThreadsProcess
->Token
, PrimaryToken
);
3786 if (NT_SUCCESS(Status
))
3790 RtlCreateSecurityDescriptor(&SecurityDescriptor
,
3791 SECURITY_DESCRIPTOR_REVISION
);
3792 RtlSetDaclSecurityDescriptor(&SecurityDescriptor
, TRUE
, Dacl
,
3796 InitializeObjectAttributes(&ObjectAttributes
, NULL
, HandleAttributes
,
3797 NULL
, Dacl
? &SecurityDescriptor
: NULL
);
3799 Status
= SepDuplicateToken(Token
, &ObjectAttributes
, EffectiveOnly
,
3800 TokenImpersonation
, ImpersonationLevel
,
3801 KernelMode
, &NewToken
);
3802 if (NT_SUCCESS(Status
))
3804 ObReferenceObject(NewToken
);
3805 Status
= ObInsertObject(NewToken
, NULL
, DesiredAccess
, 0, NULL
,
3813 Status
= ObOpenObjectByPointer(Token
, HandleAttributes
,
3814 NULL
, DesiredAccess
, SeTokenObjectType
,
3815 PreviousMode
, &hToken
);
3818 if (Dacl
) ExFreePoolWithTag(Dacl
, TAG_ACL
);
3820 if (RestoreImpersonation
)
3822 PsRestoreImpersonation(PsGetCurrentThread(), &ImpersonationState
);
3825 ObDereferenceObject(Token
);
3827 if (NT_SUCCESS(Status
) && CopyOnOpen
)
3829 PsImpersonateClient(Thread
, NewToken
, FALSE
, EffectiveOnly
, ImpersonationLevel
);
3832 if (NewToken
) ObDereferenceObject(NewToken
);
3834 if (CopyOnOpen
&& NewThread
) ObDereferenceObject(NewThread
);
3836 ObDereferenceObject(Thread
);
3838 if (NT_SUCCESS(Status
))
3842 *TokenHandle
= hToken
;
3844 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3846 Status
= _SEH2_GetExceptionCode();
3858 NtOpenThreadToken(IN HANDLE ThreadHandle
,
3859 IN ACCESS_MASK DesiredAccess
,
3860 IN BOOLEAN OpenAsSelf
,
3861 OUT PHANDLE TokenHandle
)
3863 return NtOpenThreadTokenEx(ThreadHandle
, DesiredAccess
, OpenAsSelf
, 0,
3872 NtCompareTokens(IN HANDLE FirstTokenHandle
,
3873 IN HANDLE SecondTokenHandle
,
3876 KPROCESSOR_MODE PreviousMode
;
3877 PTOKEN FirstToken
, SecondToken
;
3883 PreviousMode
= ExGetPreviousMode();
3885 if (PreviousMode
!= KernelMode
)
3889 ProbeForWriteBoolean(Equal
);
3891 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
3893 /* Return the exception code */
3894 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3899 Status
= ObReferenceObjectByHandle(FirstTokenHandle
,
3903 (PVOID
*)&FirstToken
,
3905 if (!NT_SUCCESS(Status
))
3908 Status
= ObReferenceObjectByHandle(SecondTokenHandle
,
3912 (PVOID
*)&SecondToken
,
3914 if (!NT_SUCCESS(Status
))
3916 ObDereferenceObject(FirstToken
);
3920 if (FirstToken
!= SecondToken
)
3922 Status
= SepCompareTokens(FirstToken
,
3931 ObDereferenceObject(SecondToken
);
3932 ObDereferenceObject(FirstToken
);
3934 if (NT_SUCCESS(Status
))
3940 _SEH2_EXCEPT(ExSystemExceptionFilter())
3942 Status
= _SEH2_GetExceptionCode();
3952 NtFilterToken(IN HANDLE ExistingTokenHandle
,
3954 IN PTOKEN_GROUPS SidsToDisable OPTIONAL
,
3955 IN PTOKEN_PRIVILEGES PrivilegesToDelete OPTIONAL
,
3956 IN PTOKEN_GROUPS RestrictedSids OPTIONAL
,
3957 OUT PHANDLE NewTokenHandle
)
3960 return STATUS_NOT_IMPLEMENTED
;
3968 NtImpersonateAnonymousToken(IN HANDLE Thread
)
3971 return STATUS_NOT_IMPLEMENTED
;