#pragma alloc_text(INIT, SepInitializeTokenImplementation)
#endif
+#include <ntlsa.h>
+
+typedef struct _TOKEN_AUDIT_POLICY_INFORMATION
+{
+ ULONG PolicyCount;
+ struct
+ {
+ ULONG Category;
+ UCHAR Value;
+ } Policies[1];
+} TOKEN_AUDIT_POLICY_INFORMATION, *PTOKEN_AUDIT_POLICY_INFORMATION;
+
/* GLOBALS ********************************************************************/
POBJECT_TYPE SeTokenObjectType = NULL;
TOKEN_SOURCE SeSystemTokenSource = {"*SYSTEM*", {0}};
LUID SeSystemAuthenticationId = SYSTEM_LUID;
+LUID SeAnonymousAuthenticationId = ANONYMOUS_LOGON_LUID;
static GENERIC_MAPPING SepTokenMapping = {
TOKEN_READ,
ICI_SQ_SAME( 0, 0, 0),
/* TokenUser */
- ICI_SQ_SAME( sizeof(TOKEN_USER), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET | ICIF_SET_SIZE_VARIABLE ),
+ ICI_SQ_SAME( sizeof(TOKEN_USER), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET_SIZE_VARIABLE ),
/* TokenGroups */
- ICI_SQ_SAME( sizeof(TOKEN_GROUPS), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET | ICIF_SET_SIZE_VARIABLE ),
+ ICI_SQ_SAME( sizeof(TOKEN_GROUPS), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET_SIZE_VARIABLE ),
/* TokenPrivileges */
- ICI_SQ_SAME( sizeof(TOKEN_PRIVILEGES), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET | ICIF_SET_SIZE_VARIABLE ),
+ ICI_SQ_SAME( sizeof(TOKEN_PRIVILEGES), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET_SIZE_VARIABLE ),
/* TokenOwner */
ICI_SQ_SAME( sizeof(TOKEN_OWNER), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET | ICIF_SET_SIZE_VARIABLE ),
/* TokenPrimaryGroup */
/* TokenDefaultDacl */
ICI_SQ_SAME( sizeof(TOKEN_DEFAULT_DACL), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET | ICIF_SET_SIZE_VARIABLE ),
/* TokenSource */
- ICI_SQ_SAME( sizeof(TOKEN_SOURCE), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET | ICIF_SET_SIZE_VARIABLE ),
+ ICI_SQ_SAME( sizeof(TOKEN_SOURCE), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET_SIZE_VARIABLE ),
/* TokenType */
ICI_SQ_SAME( sizeof(TOKEN_TYPE), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE ),
/* TokenImpersonationLevel */
ICI_SQ_SAME( sizeof(SECURITY_IMPERSONATION_LEVEL), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE ),
/* TokenStatistics */
- ICI_SQ_SAME( sizeof(TOKEN_STATISTICS), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET | ICIF_SET_SIZE_VARIABLE ),
+ ICI_SQ_SAME( sizeof(TOKEN_STATISTICS), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE | ICIF_SET_SIZE_VARIABLE ),
/* TokenRestrictedSids */
ICI_SQ_SAME( sizeof(TOKEN_GROUPS), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE ),
/* TokenSessionId */
/* TokenGroupsAndPrivileges */
ICI_SQ_SAME( sizeof(TOKEN_GROUPS_AND_PRIVILEGES), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE ),
/* TokenSessionReference */
- ICI_SQ_SAME( /* FIXME */0, sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE ),
+ ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_SET | ICIF_QUERY_SIZE_VARIABLE ),
/* TokenSandBoxInert */
ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE ),
/* TokenAuditPolicy */
- ICI_SQ_SAME( /* FIXME */0, sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE ),
+ ICI_SQ_SAME( /* FIXME */0, sizeof(ULONG), ICIF_QUERY | ICIF_SET | ICIF_QUERY_SIZE_VARIABLE ),
/* TokenOrigin */
- ICI_SQ_SAME( sizeof(TOKEN_ORIGIN), sizeof(ULONG), ICIF_QUERY | ICIF_QUERY_SIZE_VARIABLE ),
+ ICI_SQ_SAME( sizeof(TOKEN_ORIGIN), sizeof(ULONG), ICIF_QUERY | ICIF_SET | ICIF_QUERY_SIZE_VARIABLE ),
};
/* FUNCTIONS *****************************************************************/
}
/* FIXME: Check if every privilege that is present in either token is also present in the other one */
+ DPRINT1("FIXME: Pretending tokens are equal!\n");
+ IsEqual = TRUE;
}
*Equal = IsEqual;
_In_ ULONG Index)
{
ULONG TokenFlag;
- NT_ASSERT(Index < Token->PrivilegeCount);
+ ASSERT(Index < Token->PrivilegeCount);
/* The high part of all values we are interested in is 0 */
if (Token->Privileges[Index].Luid.HighPart != 0)
_In_ ULONG Index)
{
ULONG MoveCount;
- NT_ASSERT(Index < Token->PrivilegeCount);
+ ASSERT(Index < Token->PrivilegeCount);
/* Calculate the number of trailing privileges */
MoveCount = Token->PrivilegeCount - Index - 1;
PAGED_CODE();
if (NewToken->TokenType != TokenPrimary) return(STATUS_BAD_TOKEN_TYPE);
- if (NewToken->TokenInUse) return(STATUS_TOKEN_ALREADY_IN_USE);
+ if (NewToken->TokenInUse)
+ {
+ BOOLEAN IsEqual;
+ NTSTATUS Status;
+
+ /* Maybe we're trying to set the same token */
+ OldToken = PsReferencePrimaryToken(Process);
+ if (OldToken == NewToken)
+ {
+ /* So it's a nop. */
+ *OldTokenP = OldToken;
+ return STATUS_SUCCESS;
+ }
+
+ Status = SepCompareTokens(OldToken, NewToken, &IsEqual);
+ if (!NT_SUCCESS(Status))
+ {
+ *OldTokenP = NULL;
+ PsDereferencePrimaryToken(OldToken);
+ return Status;
+ }
+
+ if (!IsEqual)
+ {
+ *OldTokenP = NULL;
+ PsDereferencePrimaryToken(OldToken);
+ return STATUS_TOKEN_ALREADY_IN_USE;
+ }
+ /* Silently return STATUS_SUCCESS but do not set the new token,
+ * as it's already in use elsewhere. */
+ *OldTokenP = OldToken;
+ return STATUS_SUCCESS;
+ }
/* Mark new token in use */
NewToken->TokenInUse = 1;
/* Mark the Old Token as free */
OldToken->TokenInUse = 0;
+
+ /* Dereference the Token */
+ ObDereferenceObject(OldToken);
}
static ULONG
/* Zero out the buffer */
RtlZeroMemory(AccessToken, sizeof(TOKEN));
- Status = ZwAllocateLocallyUniqueId(&AccessToken->TokenId);
- if (!NT_SUCCESS(Status))
- {
- ObDereferenceObject(AccessToken);
- return Status;
- }
-
- Status = ZwAllocateLocallyUniqueId(&AccessToken->ModifiedId);
- if (!NT_SUCCESS(Status))
- {
- ObDereferenceObject(AccessToken);
- return Status;
- }
+ ExAllocateLocallyUniqueId(&AccessToken->TokenId);
AccessToken->TokenLock = &SepTokenLock;
AccessToken->TokenType = TokenType;
AccessToken->ImpersonationLevel = Level;
RtlCopyLuid(&AccessToken->AuthenticationId, &Token->AuthenticationId);
+ RtlCopyLuid(&AccessToken->ModifiedId, &Token->ModifiedId);
AccessToken->TokenSource.SourceIdentifier.LowPart = Token->TokenSource.SourceIdentifier.LowPart;
AccessToken->TokenSource.SourceIdentifier.HighPart = Token->TokenSource.SourceIdentifier.HighPart;
*NewAccessToken = AccessToken;
+ /* Reference the logon session */
+ SepRmReferenceLogonSession(&AccessToken->AuthenticationId);
+
done:
if (!NT_SUCCESS(Status))
{
ProcessToken = PsReferencePrimaryToken(PsGetCurrentProcess());
/* Get the ID */
- ProcessLuid = ProcessToken->TokenId;
+ ProcessLuid = ProcessToken->AuthenticationId;
/* Dereference the token */
ObFastDereferenceObject(&PsGetCurrentProcess()->Token, ProcessToken);
/* Get our LUID */
- CallerLuid = Token->TokenId;
+ CallerLuid = Token->AuthenticationId;
/* Compare the LUIDs */
if (RtlEqualLuid(&CallerLuid, &ProcessLuid)) *IsChild = TRUE;
{
PTOKEN AccessToken = (PTOKEN)ObjectBody;
+ DPRINT("SepDeleteToken()\n");
+
+ /* Dereference the logon session */
+ SepRmDereferenceLogonSession(&AccessToken->AuthenticationId);
+
if (AccessToken->UserAndGroups)
ExFreePoolWithTag(AccessToken->UserAndGroups, TAG_TOKEN_USERS);
NTSTATUS Status;
ULONG TokenFlags = 0;
+ PAGED_CODE();
+
/* Loop all groups */
for (i = 0; i < GroupCount; i++)
{
}
}
- Status = ZwAllocateLocallyUniqueId(&TokenId);
- if (!NT_SUCCESS(Status))
- return Status;
-
- Status = ZwAllocateLocallyUniqueId(&ModifiedId);
- if (!NT_SUCCESS(Status))
- return Status;
+ ExAllocateLocallyUniqueId(&TokenId);
+ ExAllocateLocallyUniqueId(&ModifiedId);
Status = ObCreateObject(PreviousMode,
SeTokenObjectType,
*TokenHandle = (HANDLE)AccessToken;
}
+ /* Reference the logon session */
+ SepRmReferenceLogonSession(AuthenticationId);
+
done:
if (!NT_SUCCESS(Status))
{
IN TOKEN_INFORMATION_CLASS TokenInformationClass,
OUT PVOID *TokenInformation)
{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
+ NTSTATUS Status;
+ PSECURITY_IMPERSONATION_LEVEL SeImpersonationLvl;
+ PAGED_CODE();
+
+ if (TokenInformationClass >= MaxTokenInfoClass)
+ {
+ DPRINT1("SeQueryInformationToken(%d) invalid information class\n", TokenInformationClass);
+ return STATUS_INVALID_INFO_CLASS;
+ }
+
+ switch (TokenInformationClass)
+ {
+ case TokenImpersonationLevel:
+ /* It is mandatory to have an impersonation token */
+ if (((PTOKEN)Token)->TokenType != TokenImpersonation)
+ {
+ Status = STATUS_INVALID_INFO_CLASS;
+ break;
+ }
+
+ /* Allocate the output buffer */
+ SeImpersonationLvl = ExAllocatePoolWithTag(PagedPool, sizeof(SECURITY_IMPERSONATION_LEVEL), TAG_SE);
+ if (SeImpersonationLvl == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ /* Set impersonation level and return the structure */
+ *SeImpersonationLvl = ((PTOKEN)Token)->ImpersonationLevel;
+ *TokenInformation = SeImpersonationLvl;
+ Status = STATUS_SUCCESS;
+ break;
+
+ default:
+ UNIMPLEMENTED;
+ Status = STATUS_NOT_IMPLEMENTED;
+ break;
+ }
+
+ return Status;
}
/*
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
- _SEH2_YIELD(return _SEH2_GetExceptionCode());
+ Status = _SEH2_GetExceptionCode();
+ goto Cleanup;
}
_SEH2_END;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
- _SEH2_YIELD(return _SEH2_GetExceptionCode());
+ Status = _SEH2_GetExceptionCode();
+ goto Cleanup;
}
_SEH2_END;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
- _SEH2_YIELD(return _SEH2_GetExceptionCode());
+ Status = _SEH2_GetExceptionCode();
+ goto Cleanup;
}
_SEH2_END;
ExFreePoolWithTag(Token->DefaultDacl, TAG_TOKEN_ACL);
}
- /* Set the new dacl */
- Token->DefaultDacl = CapturedAcl;
+ Token->DefaultDacl = ExAllocatePoolWithTag(PagedPool,
+ CapturedAcl->AclSize,
+ TAG_TOKEN_ACL);
+ if (!Token->DefaultDacl)
+ {
+ ExFreePoolWithTag(CapturedAcl, TAG_ACL);
+ Status = STATUS_NO_MEMORY;
+ }
+ else
+ {
+ /* Set the new dacl */
+ RtlCopyMemory(Token->DefaultDacl, CapturedAcl, CapturedAcl->AclSize);
+ ExFreePoolWithTag(CapturedAcl, TAG_ACL);
+ }
}
}
else
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
- _SEH2_YIELD(return _SEH2_GetExceptionCode());
+ Status = _SEH2_GetExceptionCode();
+ goto Cleanup;
}
_SEH2_END;
break;
}
+ case TokenSessionReference:
+ {
+ ULONG SessionReference;
+
+ _SEH2_TRY
+ {
+ /* Buffer size was already verified, no need to check here again */
+ SessionReference = *(PULONG)TokenInformation;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ goto Cleanup;
+ }
+ _SEH2_END;
+
+ if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
+ {
+ Status = STATUS_PRIVILEGE_NOT_HELD;
+ goto Cleanup;
+ }
+
+ /* Check if it is 0 */
+ if (SessionReference == 0)
+ {
+ /* Atomically set the flag in the token */
+ RtlInterlockedSetBits(&Token->TokenFlags,
+ TOKEN_SESSION_NOT_REFERENCED);
+ }
+
+ break;
+
+ }
+
+
+ case TokenAuditPolicy:
+ {
+ PTOKEN_AUDIT_POLICY_INFORMATION PolicyInformation =
+ (PTOKEN_AUDIT_POLICY_INFORMATION)TokenInformation;
+ SEP_AUDIT_POLICY AuditPolicy;
+ ULONG i;
+
+ _SEH2_TRY
+ {
+ ProbeForRead(PolicyInformation,
+ FIELD_OFFSET(TOKEN_AUDIT_POLICY_INFORMATION,
+ Policies[PolicyInformation->PolicyCount]),
+ sizeof(ULONG));
+
+ /* Loop all policies in the structure */
+ for (i = 0; i < PolicyInformation->PolicyCount; i++)
+ {
+ /* Set the corresponding bits in the packed structure */
+ switch (PolicyInformation->Policies[i].Category)
+ {
+ case AuditCategorySystem:
+ AuditPolicy.PolicyElements.System = PolicyInformation->Policies[i].Value;
+ break;
+
+ case AuditCategoryLogon:
+ AuditPolicy.PolicyElements.Logon = PolicyInformation->Policies[i].Value;
+ break;
+
+ case AuditCategoryObjectAccess:
+ AuditPolicy.PolicyElements.ObjectAccess = PolicyInformation->Policies[i].Value;
+ break;
+
+ case AuditCategoryPrivilegeUse:
+ AuditPolicy.PolicyElements.PrivilegeUse = PolicyInformation->Policies[i].Value;
+ break;
+
+ case AuditCategoryDetailedTracking:
+ AuditPolicy.PolicyElements.DetailedTracking = PolicyInformation->Policies[i].Value;
+ break;
+
+ case AuditCategoryPolicyChange:
+ AuditPolicy.PolicyElements.PolicyChange = PolicyInformation->Policies[i].Value;
+ break;
+
+ case AuditCategoryAccountManagement:
+ AuditPolicy.PolicyElements.AccountManagement = PolicyInformation->Policies[i].Value;
+ break;
+
+ case AuditCategoryDirectoryServiceAccess:
+ AuditPolicy.PolicyElements.DirectoryServiceAccess = PolicyInformation->Policies[i].Value;
+ break;
+
+ case AuditCategoryAccountLogon:
+ AuditPolicy.PolicyElements.AccountLogon = PolicyInformation->Policies[i].Value;
+ break;
+ }
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ goto Cleanup;
+ }
+ _SEH2_END;
+
+ if (!SeSinglePrivilegeCheck(SeTcbPrivilege,
+ PreviousMode))
+ {
+ Status = STATUS_PRIVILEGE_NOT_HELD;
+ break;
+ }
+
+ /* Lock the token */
+ SepAcquireTokenLockExclusive(Token);
+
+ /* Set the new audit policy */
+ Token->AuditPolicy = AuditPolicy;
+
+ /* Unlock the token */
+ SepReleaseTokenLock(Token);
+
+ break;
+ }
+
+ case TokenOrigin:
+ {
+ TOKEN_ORIGIN TokenOrigin;
+
+ _SEH2_TRY
+ {
+ /* Copy the token origin */
+ TokenOrigin = *(PTOKEN_ORIGIN)TokenInformation;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ goto Cleanup;
+ }
+ _SEH2_END;
+
+ /* Check for TCB privilege */
+ if (!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
+ {
+ Status = STATUS_PRIVILEGE_NOT_HELD;
+ break;
+ }
+
+ /* Lock the token */
+ SepAcquireTokenLockExclusive(Token);
+
+ /* Check if there is no token origin set yet */
+ if ((Token->OriginatingLogonSession.LowPart == 0) &&
+ (Token->OriginatingLogonSession.HighPart == 0))
+ {
+ /* Set the token origin */
+ Token->OriginatingLogonSession =
+ TokenOrigin.OriginatingLogonSession;
+ }
+
+ /* Unlock the token */
+ SepReleaseTokenLock(Token);
+
+ break;
+ }
+
default:
{
- Status = STATUS_NOT_IMPLEMENTED;
+ DPRINT1("Invalid TokenInformationClass: 0x%lx\n",
+ TokenInformationClass);
+ Status = STATUS_INVALID_INFO_CLASS;
break;
}
}
-
+Cleanup:
ObDereferenceObject(Token);
}
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("NtSetInformationToken failed with Status 0x%lx\n", Status);
+ }
+
return Status;
}
NonPagedPool,
FALSE,
&CapturedDefaultDacl);
+ if (!NT_SUCCESS(Status))
+ {
+ goto Cleanup;
+ }
}
/* Call the internal function */
_SEH2_END;
}
+ /* Validate object attributes */
+ HandleAttributes = ObpValidateAttributes(HandleAttributes, PreviousMode);
+
/*
* At first open the thread token for information access and verify
- * that the token associated with thread is valid.
- */
+ * that the token associated with thread is valid. */
Status = ObReferenceObjectByHandle(ThreadHandle, THREAD_QUERY_INFORMATION,
PsThreadType, PreviousMode, (PVOID*)&Thread,
if (CopyOnOpen && NewThread) ObDereferenceObject(NewThread);
+ ObDereferenceObject(Thread);
+
if (NT_SUCCESS(Status))
{
_SEH2_TRY