#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;
return STATUS_SUCCESS;
}
+static
+VOID
+SepUpdateSinglePrivilegeFlagToken(
+ _Inout_ PTOKEN Token,
+ _In_ ULONG Index)
+{
+ ULONG TokenFlag;
+ ASSERT(Index < Token->PrivilegeCount);
+
+ /* The high part of all values we are interested in is 0 */
+ if (Token->Privileges[Index].Luid.HighPart != 0)
+ {
+ return;
+ }
+
+ /* Check for certain privileges to update flags */
+ if (Token->Privileges[Index].Luid.LowPart == SE_CHANGE_NOTIFY_PRIVILEGE)
+ {
+ TokenFlag = TOKEN_HAS_TRAVERSE_PRIVILEGE;
+ }
+ else if (Token->Privileges[Index].Luid.LowPart == SE_BACKUP_PRIVILEGE)
+ {
+ TokenFlag = TOKEN_HAS_BACKUP_PRIVILEGE;
+ }
+ else if (Token->Privileges[Index].Luid.LowPart == SE_RESTORE_PRIVILEGE)
+ {
+ TokenFlag = TOKEN_HAS_RESTORE_PRIVILEGE;
+ }
+ else if (Token->Privileges[Index].Luid.LowPart == SE_IMPERSONATE_PRIVILEGE)
+ {
+ TokenFlag = TOKEN_HAS_IMPERSONATE_PRIVILEGE;
+ }
+ else
+ {
+ /* Nothing to do */
+ return;
+ }
+
+ /* Check if the specified privilege is enabled */
+ if (Token->Privileges[Index].Attributes & SE_PRIVILEGE_ENABLED)
+ {
+ /* It is enabled, so set the flag */
+ Token->TokenFlags |= TokenFlag;
+ }
+ else
+ {
+ /* Is is disabled, so remove the flag */
+ Token->TokenFlags &= ~TokenFlag;
+ }
+}
+
+static
+VOID
+SepUpdatePrivilegeFlagsToken(
+ _Inout_ PTOKEN Token)
+{
+ ULONG i;
+
+ /* Loop all privileges */
+ for (i = 0; i < Token->PrivilegeCount; i++)
+ {
+ /* Updates the flags dor this privilege */
+ SepUpdateSinglePrivilegeFlagToken(Token, i);
+ }
+}
+
+static
+VOID
+SepRemovePrivilegeToken(
+ _Inout_ PTOKEN Token,
+ _In_ ULONG Index)
+{
+ ULONG MoveCount;
+ ASSERT(Index < Token->PrivilegeCount);
+
+ /* Calculate the number of trailing privileges */
+ MoveCount = Token->PrivilegeCount - Index - 1;
+ if (MoveCount != 0)
+ {
+ /* Move them one location ahead */
+ RtlMoveMemory(&Token->Privileges[Index],
+ &Token->Privileges[Index + 1],
+ MoveCount * sizeof(LUID_AND_ATTRIBUTES));
+ }
+
+ /* Update privilege count */
+ Token->PrivilegeCount--;
+}
+
VOID
NTAPI
SepFreeProxyData(PVOID ProxyData)
PAGED_CODE();
- if (NewToken->TokenType != TokenPrimary) return(STATUS_BAD_TOKEN_TYPE);
- if (NewToken->TokenInUse) return(STATUS_TOKEN_ALREADY_IN_USE);
+ if (NewToken->TokenType != TokenPrimary) return STATUS_BAD_TOKEN_TYPE;
+ 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
if (Token->DefaultOwnerIndex == Token->UserAndGroupCount)
{
- return(STATUS_INVALID_OWNER);
+ return STATUS_INVALID_OWNER;
}
if (Token->PrimaryGroup == 0)
{
- return(STATUS_INVALID_PRIMARY_GROUP);
+ return STATUS_INVALID_PRIMARY_GROUP;
}
return STATUS_SUCCESS;
ULONG uLength;
ULONG i;
PVOID EndMem;
- PTOKEN AccessToken = NULL;
+ PTOKEN AccessToken;
NTSTATUS Status;
PAGED_CODE();
/* 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;
+ /* Copy and reference the logon session */
+ RtlCopyLuid(&AccessToken->AuthenticationId, &Token->AuthenticationId);
+ SepRmReferenceLogonSession(&AccessToken->AuthenticationId);
+
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;
done:
if (!NT_SUCCESS(Status))
{
- if (AccessToken)
- {
- if (AccessToken->UserAndGroups)
- ExFreePoolWithTag(AccessToken->UserAndGroups, TAG_TOKEN_USERS);
-
- if (AccessToken->Privileges)
- ExFreePoolWithTag(AccessToken->Privileges, TAG_TOKEN_PRIVILAGES);
-
- if (AccessToken->DefaultDacl)
- ExFreePoolWithTag(AccessToken->DefaultDacl, TAG_TOKEN_ACL);
-
- ObDereferenceObject(AccessToken);
- }
+ /* Dereference the token, the delete procedure will clean up */
+ ObDereferenceObject(AccessToken);
}
return 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++)
{
}
}
- /* Loop all privileges */
- for (i = 0; i < PrivilegeCount; i++)
- {
- /* For optimization, check for change notify and impersonate rights */
- if (((RtlEqualLuid(&Privileges[i].Luid, &SeChangeNotifyPrivilege)) &&
- (Privileges[i].Attributes & SE_PRIVILEGE_ENABLED)))
- {
- /* Remember token has traverse */
- TokenFlags |= TOKEN_HAS_TRAVERSE_PRIVILEGE;
- }
- }
-
- 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,
(PVOID*)&AccessToken);
if (!NT_SUCCESS(Status))
{
- DPRINT1("ObCreateObject() failed (Status %lx)\n");
+ DPRINT1("ObCreateObject() failed (Status %lx)\n", Status);
return Status;
}
TokenSource->SourceName,
sizeof(TokenSource->SourceName));
- RtlCopyLuid(&AccessToken->TokenId, &TokenId);
+ /* Copy and reference the logon session */
RtlCopyLuid(&AccessToken->AuthenticationId, AuthenticationId);
+ SepRmReferenceLogonSession(&AccessToken->AuthenticationId);
+
+ RtlCopyLuid(&AccessToken->TokenId, &TokenId);
AccessToken->ExpirationTime = *ExpirationTime;
RtlCopyLuid(&AccessToken->ModifiedId, &ModifiedId);
for (i = 0; i < GroupCount; i++)
uLength += RtlLengthSid(Groups[i].Sid);
+ // FIXME: should use the object itself
AccessToken->UserAndGroups = ExAllocatePoolWithTag(PagedPool,
uLength,
TAG_TOKEN_USERS);
if (!NT_SUCCESS(Status))
goto done;
+ // FIXME: should use the object itself
uLength = PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
+ if (uLength == 0) uLength = sizeof(PVOID);
AccessToken->Privileges = ExAllocatePoolWithTag(PagedPool,
uLength,
TAG_TOKEN_PRIVILAGES);
if (!NT_SUCCESS(Status))
goto done;
- AccessToken->DefaultDacl = ExAllocatePoolWithTag(PagedPool,
- DefaultDacl->AclSize,
- TAG_TOKEN_ACL);
- if (AccessToken->DefaultDacl == NULL)
+ /* Update privilege flags */
+ SepUpdatePrivilegeFlagsToken(AccessToken);
+
+ if (DefaultDacl != NULL)
{
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto done;
- }
+ // FIXME: should use the object itself
+ AccessToken->DefaultDacl = ExAllocatePoolWithTag(PagedPool,
+ DefaultDacl->AclSize,
+ TAG_TOKEN_ACL);
+ if (AccessToken->DefaultDacl == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto done;
+ }
- RtlCopyMemory(AccessToken->DefaultDacl,
- DefaultDacl,
- DefaultDacl->AclSize);
+ RtlCopyMemory(AccessToken->DefaultDacl,
+ DefaultDacl,
+ DefaultDacl->AclSize);
+ }
+ else
+ {
+ AccessToken->DefaultDacl = NULL;
+ }
if (!SystemToken)
{
done:
if (!NT_SUCCESS(Status))
{
- if (AccessToken)
- {
- if (AccessToken->UserAndGroups)
- ExFreePoolWithTag(AccessToken->UserAndGroups, TAG_TOKEN_USERS);
-
- if (AccessToken->Privileges)
- ExFreePoolWithTag(AccessToken->Privileges, TAG_TOKEN_PRIVILAGES);
-
- if (AccessToken->DefaultDacl)
- ExFreePoolWithTag(AccessToken->DefaultDacl, TAG_TOKEN_ACL);
-
- ObDereferenceObject(AccessToken);
- }
+ /* Dereference the token, the delete procedure will clean up */
+ ObDereferenceObject(AccessToken);
}
return Status;
}
/*
- * @unimplemented
+ * @implemented
+ *
+ * NOTE: SeQueryInformationToken is just NtQueryInformationToken without all
+ * the bells and whistles needed for user-mode buffer access protection.
*/
NTSTATUS
NTAPI
-SeQueryInformationToken(IN PACCESS_TOKEN Token,
+SeQueryInformationToken(IN PACCESS_TOKEN AccessToken,
IN TOKEN_INFORMATION_CLASS TokenInformationClass,
OUT PVOID *TokenInformation)
{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
-}
-
-/*
- * @implemented
- */
-NTSTATUS
-NTAPI
-SeQuerySessionIdToken(IN PACCESS_TOKEN Token,
- IN PULONG pSessionId)
-{
- *pSessionId = ((PTOKEN)Token)->SessionId;
- return STATUS_SUCCESS;
-}
+ NTSTATUS Status;
+ PTOKEN Token = (PTOKEN)AccessToken;
+ ULONG RequiredLength;
+ union
+ {
+ PSID PSid;
+ ULONG Ulong;
+ } Unused;
-/*
- * @implemented
- */
-NTSTATUS
-NTAPI
-SeQueryAuthenticationIdToken(IN PACCESS_TOKEN Token,
- OUT PLUID LogonId)
-{
PAGED_CODE();
- *LogonId = ((PTOKEN)Token)->AuthenticationId;
+ if (TokenInformationClass >= MaxTokenInfoClass)
+ {
+ DPRINT1("SeQueryInformationToken(%d) invalid information class\n", TokenInformationClass);
+ return STATUS_INVALID_INFO_CLASS;
+ }
- return STATUS_SUCCESS;
-}
+ switch (TokenInformationClass)
+ {
+ case TokenUser:
+ {
+ PTOKEN_USER tu;
+ DPRINT("SeQueryInformationToken(TokenUser)\n");
+ RequiredLength = sizeof(TOKEN_USER) +
+ RtlLengthSid(Token->UserAndGroups[0].Sid);
-/*
- * @implemented
- */
-SECURITY_IMPERSONATION_LEVEL
-NTAPI
-SeTokenImpersonationLevel(IN PACCESS_TOKEN Token)
-{
- PAGED_CODE();
+ /* Allocate the output buffer */
+ tu = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
+ if (tu == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
- return ((PTOKEN)Token)->ImpersonationLevel;
-}
+ Status = RtlCopySidAndAttributesArray(1,
+ &Token->UserAndGroups[0],
+ RequiredLength - sizeof(TOKEN_USER),
+ &tu->User,
+ (PSID)(tu + 1),
+ &Unused.PSid,
+ &Unused.Ulong);
+
+ /* Return the structure */
+ *TokenInformation = tu;
+ Status = STATUS_SUCCESS;
+ break;
+ }
+ case TokenGroups:
+ {
+ PTOKEN_GROUPS tg;
+ ULONG SidLen;
+ PSID Sid;
-/*
- * @implemented
- */
-TOKEN_TYPE NTAPI
-SeTokenType(IN PACCESS_TOKEN Token)
-{
- PAGED_CODE();
+ DPRINT("SeQueryInformationToken(TokenGroups)\n");
+ RequiredLength = sizeof(tg->GroupCount) +
+ RtlLengthSidAndAttributes(Token->UserAndGroupCount - 1, &Token->UserAndGroups[1]);
- return ((PTOKEN)Token)->TokenType;
-}
+ SidLen = RequiredLength - sizeof(tg->GroupCount) -
+ ((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES));
+ /* Allocate the output buffer */
+ tg = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
+ if (tg == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
-/*
- * @implemented
- */
-BOOLEAN
-NTAPI
-SeTokenIsAdmin(IN PACCESS_TOKEN Token)
-{
- PAGED_CODE();
+ Sid = (PSID)((ULONG_PTR)tg + sizeof(tg->GroupCount) +
+ ((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES)));
+
+ tg->GroupCount = Token->UserAndGroupCount - 1;
+ Status = RtlCopySidAndAttributesArray(Token->UserAndGroupCount - 1,
+ &Token->UserAndGroups[1],
+ SidLen,
+ &tg->Groups[0],
+ Sid,
+ &Unused.PSid,
+ &Unused.Ulong);
+
+ /* Return the structure */
+ *TokenInformation = tg;
+ Status = STATUS_SUCCESS;
+ break;
+ }
- return (((PTOKEN)Token)->TokenFlags & TOKEN_WRITE_RESTRICTED) != 0;
-}
+ case TokenPrivileges:
+ {
+ PTOKEN_PRIVILEGES tp;
-/*
- * @implemented
- */
-BOOLEAN
-NTAPI
-SeTokenIsRestricted(IN PACCESS_TOKEN Token)
-{
- PAGED_CODE();
+ DPRINT("SeQueryInformationToken(TokenPrivileges)\n");
+ RequiredLength = sizeof(tp->PrivilegeCount) +
+ (Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
- return (((PTOKEN)Token)->TokenFlags & TOKEN_IS_RESTRICTED) != 0;
-}
+ /* Allocate the output buffer */
+ tp = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
+ if (tp == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
-/*
- * @implemented
- */
-BOOLEAN
-NTAPI
-SeTokenIsWriteRestricted(IN PACCESS_TOKEN Token)
-{
- PAGED_CODE();
+ tp->PrivilegeCount = Token->PrivilegeCount;
+ RtlCopyLuidAndAttributesArray(Token->PrivilegeCount,
+ Token->Privileges,
+ &tp->Privileges[0]);
- return (((PTOKEN)Token)->TokenFlags & TOKEN_HAS_RESTORE_PRIVILEGE) != 0;
-}
+ /* Return the structure */
+ *TokenInformation = tp;
+ Status = STATUS_SUCCESS;
+ break;
+ }
-/* SYSTEM CALLS ***************************************************************/
+ case TokenOwner:
+ {
+ PTOKEN_OWNER to;
+ ULONG SidLen;
-/*
- * @implemented
- */
-NTSTATUS NTAPI
-NtQueryInformationToken(IN HANDLE TokenHandle,
- IN TOKEN_INFORMATION_CLASS TokenInformationClass,
- OUT PVOID TokenInformation,
- IN ULONG TokenInformationLength,
- OUT PULONG ReturnLength)
-{
- union
- {
- PVOID Ptr;
- ULONG Ulong;
- } Unused;
- PTOKEN Token;
- ULONG RequiredLength;
- KPROCESSOR_MODE PreviousMode;
- NTSTATUS Status = STATUS_SUCCESS;
+ DPRINT("SeQueryInformationToken(TokenOwner)\n");
+ SidLen = RtlLengthSid(Token->UserAndGroups[Token->DefaultOwnerIndex].Sid);
+ RequiredLength = sizeof(TOKEN_OWNER) + SidLen;
- PAGED_CODE();
+ /* Allocate the output buffer */
+ to = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
+ if (to == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
- PreviousMode = ExGetPreviousMode();
+ to->Owner = (PSID)(to + 1);
+ Status = RtlCopySid(SidLen,
+ to->Owner,
+ Token->UserAndGroups[Token->DefaultOwnerIndex].Sid);
- /* Check buffers and class validity */
- Status = DefaultQueryInfoBufferCheck(TokenInformationClass,
- SeTokenInformationClass,
- sizeof(SeTokenInformationClass) / sizeof(SeTokenInformationClass[0]),
- TokenInformation,
+ /* Return the structure */
+ *TokenInformation = to;
+ Status = STATUS_SUCCESS;
+ break;
+ }
+
+ case TokenPrimaryGroup:
+ {
+ PTOKEN_PRIMARY_GROUP tpg;
+ ULONG SidLen;
+
+ DPRINT("SeQueryInformationToken(TokenPrimaryGroup)\n");
+ SidLen = RtlLengthSid(Token->PrimaryGroup);
+ RequiredLength = sizeof(TOKEN_PRIMARY_GROUP) + SidLen;
+
+ /* Allocate the output buffer */
+ tpg = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
+ if (tpg == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ tpg->PrimaryGroup = (PSID)(tpg + 1);
+ Status = RtlCopySid(SidLen,
+ tpg->PrimaryGroup,
+ Token->PrimaryGroup);
+
+ /* Return the structure */
+ *TokenInformation = tpg;
+ Status = STATUS_SUCCESS;
+ break;
+ }
+
+ case TokenDefaultDacl:
+ {
+ PTOKEN_DEFAULT_DACL tdd;
+
+ DPRINT("SeQueryInformationToken(TokenDefaultDacl)\n");
+ RequiredLength = sizeof(TOKEN_DEFAULT_DACL);
+
+ if (Token->DefaultDacl != NULL)
+ RequiredLength += Token->DefaultDacl->AclSize;
+
+ /* Allocate the output buffer */
+ tdd = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
+ if (tdd == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ if (Token->DefaultDacl != NULL)
+ {
+ tdd->DefaultDacl = (PACL)(tdd + 1);
+ RtlCopyMemory(tdd->DefaultDacl,
+ Token->DefaultDacl,
+ Token->DefaultDacl->AclSize);
+ }
+ else
+ {
+ tdd->DefaultDacl = NULL;
+ }
+
+ /* Return the structure */
+ *TokenInformation = tdd;
+ Status = STATUS_SUCCESS;
+ break;
+ }
+
+ case TokenSource:
+ {
+ PTOKEN_SOURCE ts;
+
+ DPRINT("SeQueryInformationToken(TokenSource)\n");
+ RequiredLength = sizeof(TOKEN_SOURCE);
+
+ /* Allocate the output buffer */
+ ts = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
+ if (ts == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ *ts = Token->TokenSource;
+
+ /* Return the structure */
+ *TokenInformation = ts;
+ Status = STATUS_SUCCESS;
+ break;
+ }
+
+ case TokenType:
+ {
+ PTOKEN_TYPE tt;
+
+ DPRINT("SeQueryInformationToken(TokenType)\n");
+ RequiredLength = sizeof(TOKEN_TYPE);
+
+ /* Allocate the output buffer */
+ tt = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
+ if (tt == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ *tt = Token->TokenType;
+
+ /* Return the structure */
+ *TokenInformation = tt;
+ Status = STATUS_SUCCESS;
+ break;
+ }
+
+ case TokenImpersonationLevel:
+ {
+ PSECURITY_IMPERSONATION_LEVEL sil;
+
+ DPRINT("SeQueryInformationToken(TokenImpersonationLevel)\n");
+ RequiredLength = sizeof(SECURITY_IMPERSONATION_LEVEL);
+
+ /* Fail if the token is not an impersonation token */
+ if (Token->TokenType != TokenImpersonation)
+ {
+ Status = STATUS_INVALID_INFO_CLASS;
+ break;
+ }
+
+ /* Allocate the output buffer */
+ sil = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
+ if (sil == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ *sil = Token->ImpersonationLevel;
+
+ /* Return the structure */
+ *TokenInformation = sil;
+ Status = STATUS_SUCCESS;
+ break;
+ }
+
+ case TokenStatistics:
+ {
+ PTOKEN_STATISTICS ts;
+
+ DPRINT("SeQueryInformationToken(TokenStatistics)\n");
+ RequiredLength = sizeof(TOKEN_STATISTICS);
+
+ /* Allocate the output buffer */
+ ts = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
+ if (ts == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ ts->TokenId = Token->TokenId;
+ ts->AuthenticationId = Token->AuthenticationId;
+ ts->ExpirationTime = Token->ExpirationTime;
+ ts->TokenType = Token->TokenType;
+ ts->ImpersonationLevel = Token->ImpersonationLevel;
+ ts->DynamicCharged = Token->DynamicCharged;
+ ts->DynamicAvailable = Token->DynamicAvailable;
+ ts->GroupCount = Token->UserAndGroupCount - 1;
+ ts->PrivilegeCount = Token->PrivilegeCount;
+ ts->ModifiedId = Token->ModifiedId;
+
+ /* Return the structure */
+ *TokenInformation = ts;
+ Status = STATUS_SUCCESS;
+ break;
+ }
+
+/*
+ * The following 4 cases are only implemented in NtQueryInformationToken
+ */
+#if 0
+
+ case TokenOrigin:
+ {
+ PTOKEN_ORIGIN to;
+
+ DPRINT("SeQueryInformationToken(TokenOrigin)\n");
+ RequiredLength = sizeof(TOKEN_ORIGIN);
+
+ /* Allocate the output buffer */
+ to = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
+ if (to == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ RtlCopyLuid(&to->OriginatingLogonSession,
+ &Token->AuthenticationId);
+
+ /* Return the structure */
+ *TokenInformation = to;
+ Status = STATUS_SUCCESS;
+ break;
+ }
+
+ case TokenGroupsAndPrivileges:
+ DPRINT1("SeQueryInformationToken(TokenGroupsAndPrivileges) not implemented\n");
+ Status = STATUS_NOT_IMPLEMENTED;
+ break;
+
+ case TokenRestrictedSids:
+ {
+ PTOKEN_GROUPS tg = (PTOKEN_GROUPS)TokenInformation;
+ ULONG SidLen;
+ PSID Sid;
+
+ DPRINT("SeQueryInformationToken(TokenRestrictedSids)\n");
+ RequiredLength = sizeof(tg->GroupCount) +
+ RtlLengthSidAndAttributes(Token->RestrictedSidCount, Token->RestrictedSids);
+
+ SidLen = RequiredLength - sizeof(tg->GroupCount) -
+ (Token->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES));
+
+ /* Allocate the output buffer */
+ tg = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE);
+ if (tg == NULL)
+ {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ break;
+ }
+
+ Sid = (PSID)((ULONG_PTR)tg + sizeof(tg->GroupCount) +
+ (Token->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES)));
+
+ tg->GroupCount = Token->RestrictedSidCount;
+ Status = RtlCopySidAndAttributesArray(Token->RestrictedSidCount,
+ Token->RestrictedSids,
+ SidLen,
+ &tg->Groups[0],
+ Sid,
+ &Unused.PSid,
+ &Unused.Ulong);
+
+ /* Return the structure */
+ *TokenInformation = tg;
+ Status = STATUS_SUCCESS;
+ break;
+ }
+
+ case TokenSandBoxInert:
+ DPRINT1("SeQueryInformationToken(TokenSandboxInert) not implemented\n");
+ Status = STATUS_NOT_IMPLEMENTED;
+ break;
+
+#endif
+
+ case TokenSessionId:
+ {
+ DPRINT("SeQueryInformationToken(TokenSessionId)\n");
+
+ Status = SeQuerySessionIdToken(Token, (PULONG)TokenInformation);
+
+ // Status = STATUS_SUCCESS;
+ break;
+ }
+
+ default:
+ DPRINT1("SeQueryInformationToken(%d) invalid information class\n", TokenInformationClass);
+ Status = STATUS_INVALID_INFO_CLASS;
+ break;
+ }
+
+ return Status;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+SeQuerySessionIdToken(IN PACCESS_TOKEN Token,
+ IN PULONG pSessionId)
+{
+ *pSessionId = ((PTOKEN)Token)->SessionId;
+ return STATUS_SUCCESS;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+SeQueryAuthenticationIdToken(IN PACCESS_TOKEN Token,
+ OUT PLUID LogonId)
+{
+ PAGED_CODE();
+
+ *LogonId = ((PTOKEN)Token)->AuthenticationId;
+
+ return STATUS_SUCCESS;
+}
+
+
+/*
+ * @implemented
+ */
+SECURITY_IMPERSONATION_LEVEL
+NTAPI
+SeTokenImpersonationLevel(IN PACCESS_TOKEN Token)
+{
+ PAGED_CODE();
+
+ return ((PTOKEN)Token)->ImpersonationLevel;
+}
+
+
+/*
+ * @implemented
+ */
+TOKEN_TYPE NTAPI
+SeTokenType(IN PACCESS_TOKEN Token)
+{
+ PAGED_CODE();
+
+ return ((PTOKEN)Token)->TokenType;
+}
+
+
+/*
+ * @implemented
+ */
+BOOLEAN
+NTAPI
+SeTokenIsAdmin(IN PACCESS_TOKEN Token)
+{
+ PAGED_CODE();
+
+ return (((PTOKEN)Token)->TokenFlags & TOKEN_WRITE_RESTRICTED) != 0;
+}
+
+/*
+ * @implemented
+ */
+BOOLEAN
+NTAPI
+SeTokenIsRestricted(IN PACCESS_TOKEN Token)
+{
+ PAGED_CODE();
+
+ return (((PTOKEN)Token)->TokenFlags & TOKEN_IS_RESTRICTED) != 0;
+}
+
+/*
+ * @implemented
+ */
+BOOLEAN
+NTAPI
+SeTokenIsWriteRestricted(IN PACCESS_TOKEN Token)
+{
+ PAGED_CODE();
+
+ return (((PTOKEN)Token)->TokenFlags & TOKEN_HAS_RESTORE_PRIVILEGE) != 0;
+}
+
+/* SYSTEM CALLS ***************************************************************/
+
+/*
+ * @implemented
+ */
+NTSTATUS NTAPI
+NtQueryInformationToken(IN HANDLE TokenHandle,
+ IN TOKEN_INFORMATION_CLASS TokenInformationClass,
+ OUT PVOID TokenInformation,
+ IN ULONG TokenInformationLength,
+ OUT PULONG ReturnLength)
+{
+ NTSTATUS Status;
+ KPROCESSOR_MODE PreviousMode;
+ PTOKEN Token;
+ ULONG RequiredLength;
+ union
+ {
+ PSID PSid;
+ ULONG Ulong;
+ } Unused;
+
+ PAGED_CODE();
+
+ PreviousMode = ExGetPreviousMode();
+
+ /* Check buffers and class validity */
+ Status = DefaultQueryInfoBufferCheck(TokenInformationClass,
+ SeTokenInformationClass,
+ RTL_NUMBER_OF(SeTokenInformationClass),
+ TokenInformation,
TokenInformationLength,
ReturnLength,
NULL,
DPRINT("NtQueryInformationToken(TokenUser)\n");
RequiredLength = sizeof(TOKEN_USER) +
- RtlLengthSid(Token->UserAndGroups[0].Sid);
+ RtlLengthSid(Token->UserAndGroups[0].Sid);
_SEH2_TRY
{
RequiredLength - sizeof(TOKEN_USER),
&tu->User,
(PSID)(tu + 1),
- &Unused.Ptr,
+ &Unused.PSid,
&Unused.Ulong);
}
else
DPRINT("NtQueryInformationToken(TokenGroups)\n");
RequiredLength = sizeof(tg->GroupCount) +
- RtlLengthSidAndAttributes(Token->UserAndGroupCount - 1, &Token->UserAndGroups[1]);
+ RtlLengthSidAndAttributes(Token->UserAndGroupCount - 1, &Token->UserAndGroups[1]);
_SEH2_TRY
{
if (TokenInformationLength >= RequiredLength)
{
ULONG SidLen = RequiredLength - sizeof(tg->GroupCount) -
- ((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES));
- PSID_AND_ATTRIBUTES Sid = (PSID_AND_ATTRIBUTES)((ULONG_PTR)TokenInformation + sizeof(tg->GroupCount) +
- ((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES)));
+ ((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES));
+ PSID Sid = (PSID_AND_ATTRIBUTES)((ULONG_PTR)tg + sizeof(tg->GroupCount) +
+ ((Token->UserAndGroupCount - 1) * sizeof(SID_AND_ATTRIBUTES)));
tg->GroupCount = Token->UserAndGroupCount - 1;
Status = RtlCopySidAndAttributesArray(Token->UserAndGroupCount - 1,
&Token->UserAndGroups[1],
SidLen,
&tg->Groups[0],
- (PSID)Sid,
- &Unused.Ptr,
+ Sid,
+ &Unused.PSid,
&Unused.Ulong);
}
else
DPRINT("NtQueryInformationToken(TokenPrivileges)\n");
RequiredLength = sizeof(tp->PrivilegeCount) +
- (Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
+ (Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES));
_SEH2_TRY
{
case TokenOwner:
{
- ULONG SidLen;
PTOKEN_OWNER to = (PTOKEN_OWNER)TokenInformation;
+ ULONG SidLen;
DPRINT("NtQueryInformationToken(TokenOwner)\n");
SidLen = RtlLengthSid(Token->UserAndGroups[Token->DefaultOwnerIndex].Sid);
case TokenPrimaryGroup:
{
- ULONG SidLen;
PTOKEN_PRIMARY_GROUP tpg = (PTOKEN_PRIMARY_GROUP)TokenInformation;
+ ULONG SidLen;
DPRINT("NtQueryInformationToken(TokenPrimaryGroup)\n");
SidLen = RtlLengthSid(Token->PrimaryGroup);
RequiredLength = sizeof(TOKEN_DEFAULT_DACL);
if (Token->DefaultDacl != NULL)
- {
RequiredLength += Token->DefaultDacl->AclSize;
- }
_SEH2_TRY
{
if (TokenInformationLength >= RequiredLength)
{
ULONG SidLen = RequiredLength - sizeof(tg->GroupCount) -
- (Token->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES));
- PSID_AND_ATTRIBUTES Sid = (PSID_AND_ATTRIBUTES)((ULONG_PTR)TokenInformation + sizeof(tg->GroupCount) +
- (Token->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES)));
+ (Token->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES));
+ PSID Sid = (PSID)((ULONG_PTR)tg + sizeof(tg->GroupCount) +
+ (Token->RestrictedSidCount * sizeof(SID_AND_ATTRIBUTES)));
tg->GroupCount = Token->RestrictedSidCount;
Status = RtlCopySidAndAttributesArray(Token->RestrictedSidCount,
Token->RestrictedSids,
SidLen,
&tg->Groups[0],
- (PSID)Sid,
- &Unused.Ptr,
+ Sid,
+ &Unused.PSid,
&Unused.Ulong);
}
else
DPRINT("NtQueryInformationToken(TokenSessionId)\n");
- Status = SeQuerySessionIdToken(Token,
- &SessionId);
-
+ Status = SeQuerySessionIdToken(Token, &SessionId);
if (NT_SUCCESS(Status))
{
_SEH2_TRY
{
- /* buffer size was already verified, no need to check here again */
+ /* Buffer size was already verified, no need to check here again */
*(PULONG)TokenInformation = SessionId;
if (ReturnLength != NULL)
NTSTATUS NTAPI
NtSetInformationToken(IN HANDLE TokenHandle,
IN TOKEN_INFORMATION_CLASS TokenInformationClass,
- OUT PVOID TokenInformation,
+ IN PVOID TokenInformation,
IN ULONG TokenInformationLength)
{
PTOKEN Token;
Status = DefaultSetInfoBufferCheck(TokenInformationClass,
SeTokenInformationClass,
- sizeof(SeTokenInformationClass) / sizeof(SeTokenInformationClass[0]),
+ RTL_NUMBER_OF(SeTokenInformationClass),
TokenInformation,
TokenInformationLength,
PreviousMode);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
- _SEH2_YIELD(return _SEH2_GetExceptionCode());
+ Status = _SEH2_GetExceptionCode();
+ _SEH2_YIELD(goto Cleanup);
}
_SEH2_END;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
- _SEH2_YIELD(return _SEH2_GetExceptionCode());
+ Status = _SEH2_GetExceptionCode();
+ _SEH2_YIELD(goto Cleanup);
}
_SEH2_END;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
- _SEH2_YIELD(return _SEH2_GetExceptionCode());
+ Status = _SEH2_GetExceptionCode();
+ _SEH2_YIELD(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();
+ _SEH2_YIELD(goto Cleanup);
}
_SEH2_END;
break;
}
- default:
+ case TokenSessionReference:
{
- Status = STATUS_NOT_IMPLEMENTED;
- break;
- }
- }
-
- ObDereferenceObject(Token);
- }
-
- return Status;
-}
+ 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();
+ _SEH2_YIELD(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();
+ _SEH2_YIELD(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();
+ _SEH2_YIELD(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:
+ {
+ 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;
+}
/*
* @implemented
*
* NOTE: Some sources claim 4th param is ImpersonationLevel, but on W2K
- * this is certainly NOT true, thou i can't say for sure that EffectiveOnly
+ * this is certainly NOT true, although I can't say for sure that EffectiveOnly
* is correct either. -Gunnar
* This is true. EffectiveOnly overrides SQOS.EffectiveOnly. - IAI
+ * NOTE for readers: http://hex.pp.ua/nt/NtDuplicateToken.php is therefore
+ * wrong in that regard.
*/
NTSTATUS NTAPI
NtDuplicateToken(IN HANDLE ExistingTokenHandle,
IN ACCESS_MASK DesiredAccess,
- IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
+ IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
IN BOOLEAN EffectiveOnly,
IN TOKEN_TYPE TokenType,
OUT PHANDLE NewTokenHandle)
OUT PULONG ReturnLength)
{
UNIMPLEMENTED;
- return(STATUS_NOT_IMPLEMENTED);
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+
+static
+ULONG
+SepAdjustPrivileges(
+ _Inout_ PTOKEN Token,
+ _In_ BOOLEAN DisableAllPrivileges,
+ _In_opt_ PLUID_AND_ATTRIBUTES NewState,
+ _In_ ULONG NewStateCount,
+ _Out_opt_ PTOKEN_PRIVILEGES PreviousState,
+ _In_ BOOLEAN ApplyChanges,
+ _Out_ PULONG ChangedPrivileges)
+{
+ ULONG i, j, PrivilegeCount, ChangeCount, NewAttributes;
+
+ /* Count the found privileges and those that need to be changed */
+ PrivilegeCount = 0;
+ ChangeCount = 0;
+
+ /* Loop all privileges in the token */
+ for (i = 0; i < Token->PrivilegeCount; i++)
+ {
+ /* Shall all of them be disabled? */
+ if (DisableAllPrivileges)
+ {
+ /* The new attributes are the old ones, but disabled */
+ NewAttributes = Token->Privileges[i].Attributes & ~SE_PRIVILEGE_ENABLED;
+ }
+ else
+ {
+ /* Otherwise loop all provided privileges */
+ for (j = 0; j < NewStateCount; j++)
+ {
+ /* Check if this is the LUID we are looking for */
+ if (RtlEqualLuid(&Token->Privileges[i].Luid, &NewState[j].Luid))
+ {
+ DPRINT("Found privilege\n");
+
+ /* Copy SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_REMOVED */
+ NewAttributes = NewState[j].Attributes;
+ NewAttributes &= (SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_REMOVED);
+ NewAttributes |= Token->Privileges[i].Attributes & ~SE_PRIVILEGE_ENABLED;
+
+ /* Stop looking */
+ break;
+ }
+ }
+
+ /* Check if we didn't find the privilege */
+ if (j == NewStateCount)
+ {
+ /* Continue with the token's next privilege */
+ continue;
+ }
+ }
+
+ /* We found a privilege, count it */
+ PrivilegeCount++;
+
+ /* Does the privilege need to be changed? */
+ if (Token->Privileges[i].Attributes != NewAttributes)
+ {
+ /* Does the caller want the old privileges? */
+ if (PreviousState != NULL)
+ {
+ /* Copy the old privilege */
+ PreviousState->Privileges[ChangeCount] = Token->Privileges[i];
+ }
+
+ /* Does the caller want to apply the changes? */
+ if (ApplyChanges)
+ {
+ /* Shall we remove the privilege? */
+ if (NewAttributes & SE_PRIVILEGE_REMOVED)
+ {
+ /* Set the token as disabled and update flags for it */
+ Token->Privileges[i].Attributes &= ~SE_PRIVILEGE_ENABLED;
+ SepUpdateSinglePrivilegeFlagToken(Token, i);
+
+ /* Remove the privilege */
+ SepRemovePrivilegeToken(Token, i);
+
+ /* Fix the running index */
+ i--;
+
+ /* Continue with next */
+ continue;
+ }
+
+ /* Set the new attributes and update flags */
+ Token->Privileges[i].Attributes = NewAttributes;
+ SepUpdateSinglePrivilegeFlagToken(Token, i);
+ }
+
+ /* Increment the change count */
+ ChangeCount++;
+ }
+ }
+
+ /* Set the number of saved privileges */
+ if (PreviousState != NULL)
+ PreviousState->PrivilegeCount = ChangeCount;
+
+ /* Return the number of changed privileges */
+ *ChangedPrivileges = ChangeCount;
+
+ /* Check if we missed some */
+ if (!DisableAllPrivileges && (PrivilegeCount < NewStateCount))
+ {
+ return STATUS_NOT_ALL_ASSIGNED;
+ }
+
+ return STATUS_SUCCESS;
}
+
/*
* @implemented
*/
-NTSTATUS NTAPI
-NtAdjustPrivilegesToken(IN HANDLE TokenHandle,
- IN BOOLEAN DisableAllPrivileges,
- IN PTOKEN_PRIVILEGES NewState,
- IN ULONG BufferLength,
- OUT PTOKEN_PRIVILEGES PreviousState OPTIONAL,
- OUT PULONG ReturnLength OPTIONAL)
+_Must_inspect_result_
+__kernel_entry
+NTSTATUS
+NTAPI
+NtAdjustPrivilegesToken(
+ _In_ HANDLE TokenHandle,
+ _In_ BOOLEAN DisableAllPrivileges,
+ _In_opt_ PTOKEN_PRIVILEGES NewState,
+ _In_ ULONG BufferLength,
+ _Out_writes_bytes_to_opt_(BufferLength,*ReturnLength)
+ PTOKEN_PRIVILEGES PreviousState,
+ _When_(PreviousState!=NULL, _Out_) PULONG ReturnLength)
{
PLUID_AND_ATTRIBUTES CapturedPrivileges = NULL;
KPROCESSOR_MODE PreviousMode;
ULONG CapturedLength = 0;
ULONG NewStateSize = 0;
ULONG ChangeCount;
+ ULONG RequiredLength;
PTOKEN Token;
- ULONG i;
- ULONG j;
NTSTATUS Status;
-
PAGED_CODE();
- DPRINT ("NtAdjustPrivilegesToken() called\n");
+ DPRINT("NtAdjustPrivilegesToken() called\n");
/* Fail, if we do not disable all privileges but NewState is NULL */
if (DisableAllPrivileges == FALSE && NewState == NULL)
/* Probe NewState */
if (DisableAllPrivileges == FALSE)
{
- ProbeForRead(NewState,
- sizeof(TOKEN_PRIVILEGES),
- sizeof(ULONG));
+ /* First probe the header */
+ ProbeForRead(NewState, sizeof(TOKEN_PRIVILEGES), sizeof(ULONG));
CapturedCount = NewState->PrivilegeCount;
- NewStateSize = (ULONG)sizeof(TOKEN_PRIVILEGES) +
- ((CapturedCount - ANYSIZE_ARRAY) * (ULONG)sizeof(LUID_AND_ATTRIBUTES));
+ NewStateSize = FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges[CapturedCount]);
- ProbeForRead(NewState,
- NewStateSize,
- sizeof(ULONG));
+ ProbeForRead(NewState, NewStateSize, sizeof(ULONG));
}
/* Probe PreviousState and ReturnLength */
if (PreviousState != NULL)
{
- ProbeForWrite(PreviousState,
- BufferLength,
- sizeof(ULONG));
-
- ProbeForWrite(ReturnLength,
- sizeof(ULONG),
- sizeof(ULONG));
+ ProbeForWrite(PreviousState, BufferLength, sizeof(ULONG));
+ ProbeForWrite(ReturnLength, sizeof(ULONG), sizeof(ULONG));
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
}
else
{
+ /* This is kernel mode, we trust the caller */
if (DisableAllPrivileges == FALSE)
CapturedCount = NewState->PrivilegeCount;
}
+ /* Do we need to capture the new state? */
if (DisableAllPrivileges == FALSE)
{
_SEH2_TRY
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Return the exception code */
- _SEH2_YIELD(return _SEH2_GetExceptionCode());
+ Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
NULL);
if (!NT_SUCCESS(Status))
{
- DPRINT1 ("Failed to reference token (Status %lx)\n", Status);
+ DPRINT1("Failed to reference token (Status %lx)\n", Status);
/* Release the captured privileges */
if (CapturedPrivileges != NULL)
return Status;
}
- /* Count the privileges that need to be changed */
- ChangeCount = 0;
- for (i = 0; i < Token->PrivilegeCount; i++)
- {
- if (DisableAllPrivileges)
- {
- if (Token->Privileges[i].Attributes & SE_PRIVILEGE_ENABLED)
- {
- DPRINT("Privilege enabled\n");
+ /* Lock the token */
+ ExEnterCriticalRegionAndAcquireResourceExclusive(Token->TokenLock);
- ChangeCount++;
- }
- }
- else
- {
- for (j = 0; j < CapturedCount; j++)
- {
- if (Token->Privileges[i].Luid.LowPart == CapturedPrivileges[j].Luid.LowPart &&
- Token->Privileges[i].Luid.HighPart == CapturedPrivileges[j].Luid.HighPart)
- {
- DPRINT("Found privilege\n");
-
- if ((Token->Privileges[i].Attributes & SE_PRIVILEGE_ENABLED) !=
- (CapturedPrivileges[j].Attributes & SE_PRIVILEGE_ENABLED))
- {
- DPRINT("Attributes differ\n");
- DPRINT("Current attributes %lx New attributes %lx\n",
- Token->Privileges[i].Attributes,
- CapturedPrivileges[j].Attributes);
+ /* Count the privileges that need to be changed, do not apply them yet */
+ Status = SepAdjustPrivileges(Token,
+ DisableAllPrivileges,
+ CapturedPrivileges,
+ CapturedCount,
+ NULL,
+ FALSE,
+ &ChangeCount);
- ChangeCount++;
- }
- }
- }
- }
- }
-
- /*
- * Return the required buffer size and
- * check if the available buffer is large enough
- */
+ /* Check if the caller asked for the previous state */
if (PreviousState != NULL)
{
- ULONG RequiredLength = (ULONG)sizeof(TOKEN_PRIVILEGES) +
- ((ChangeCount - ANYSIZE_ARRAY) * (ULONG)sizeof(LUID_AND_ATTRIBUTES));
+ /* Calculate the required length */
+ RequiredLength = FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges[ChangeCount]);
/* Try to return the required buffer length */
_SEH2_TRY
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
- /* Dereference the token */
- ObDereferenceObject(Token);
-
- /* Release the captured privileges */
- if (CapturedPrivileges != NULL)
- SeReleaseLuidAndAttributesArray(CapturedPrivileges,
- PreviousMode,
- TRUE);
-
- /* Return the exception code */
- _SEH2_YIELD(return _SEH2_GetExceptionCode());
+ /* Do cleanup and return the exception code */
+ Status = _SEH2_GetExceptionCode();
+ _SEH2_YIELD(goto Cleanup);
}
_SEH2_END;
/* Fail, if the buffer length is smaller than the required length */
if (BufferLength < RequiredLength)
{
- /* Dereference the token */
- ObDereferenceObject(Token);
-
- /* Release the captured privileges */
- if (CapturedPrivileges != NULL)
- SeReleaseLuidAndAttributesArray(CapturedPrivileges,
- PreviousMode,
- TRUE);
-
- return STATUS_BUFFER_TOO_SMALL;
+ Status = STATUS_BUFFER_TOO_SMALL;
+ goto Cleanup;
}
}
- /* Change the privilege attributes */
- ChangeCount = 0;
+ /* Now enter SEH, since we might return the old privileges */
_SEH2_TRY
{
- for (i = 0; i < Token->PrivilegeCount; i++)
- {
- if (DisableAllPrivileges == TRUE)
- {
- if (Token->Privileges[i].Attributes & SE_PRIVILEGE_ENABLED)
- {
- DPRINT("Privilege enabled\n");
-
- /* Save the current privilege */
- if (PreviousState != NULL)
- {
- PreviousState->Privileges[ChangeCount].Luid = Token->Privileges[i].Luid;
- PreviousState->Privileges[ChangeCount].Attributes = Token->Privileges[i].Attributes;
- }
-
- /* Disable the current privlege */
- Token->Privileges[i].Attributes &= ~SE_PRIVILEGE_ENABLED;
-
- ChangeCount++;
- }
- }
- else
- {
- for (j = 0; j < CapturedCount; j++)
- {
- if (Token->Privileges[i].Luid.LowPart == CapturedPrivileges[j].Luid.LowPart &&
- Token->Privileges[i].Luid.HighPart == CapturedPrivileges[j].Luid.HighPart)
- {
- DPRINT("Found privilege\n");
-
- /* Check whether the attributes differ */
- if ((Token->Privileges[i].Attributes & SE_PRIVILEGE_ENABLED) !=
- (CapturedPrivileges[j].Attributes & SE_PRIVILEGE_ENABLED))
- {
- DPRINT("Attributes differ\n");
- DPRINT("Current attributes %lx New attributes %lx\n",
- Token->Privileges[i].Attributes,
- CapturedPrivileges[j].Attributes);
-
- /* Save the current privilege */
- if (PreviousState != NULL)
- {
- PreviousState->Privileges[ChangeCount].Luid = Token->Privileges[i].Luid;
- PreviousState->Privileges[ChangeCount].Attributes = Token->Privileges[i].Attributes;
- }
-
- /* Update the current privlege */
- Token->Privileges[i].Attributes &= ~SE_PRIVILEGE_ENABLED;
- Token->Privileges[i].Attributes |=
- (CapturedPrivileges[j].Attributes & SE_PRIVILEGE_ENABLED);
- DPRINT("New attributes %lx\n",
- Token->Privileges[i].Attributes);
-
- ChangeCount++;
- }
- }
- }
- }
- }
-
- /* Set the number of saved privileges */
- if (PreviousState != NULL)
- PreviousState->PrivilegeCount = ChangeCount;
+ /* This time apply the changes */
+ Status = SepAdjustPrivileges(Token,
+ DisableAllPrivileges,
+ CapturedPrivileges,
+ CapturedCount,
+ PreviousState,
+ TRUE,
+ &ChangeCount);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
- /* Dereference the token */
- ObDereferenceObject(Token);
-
- /* Release the captured privileges */
- if (CapturedPrivileges != NULL)
- SeReleaseLuidAndAttributesArray(CapturedPrivileges,
- PreviousMode,
- TRUE);
-
- /* Return the exception code */
- _SEH2_YIELD(return _SEH2_GetExceptionCode());
+ /* Do cleanup and return the exception code */
+ Status = _SEH2_GetExceptionCode();
+ _SEH2_YIELD(goto Cleanup);
}
_SEH2_END;
- /* Set the status */
- Status = (ChangeCount < CapturedCount) ? STATUS_NOT_ALL_ASSIGNED : STATUS_SUCCESS;
-
- /* Dereference the token */
- ObDereferenceObject (Token);
+Cleanup:
+ /* Unlock and dereference the token */
+ ExReleaseResourceAndLeaveCriticalRegion(Token->TokenLock);
+ ObDereferenceObject(Token);
/* Release the captured privileges */
if (CapturedPrivileges != NULL)
TRUE);
DPRINT ("NtAdjustPrivilegesToken() done\n");
-
return Status;
}
NTSTATUS
NTAPI
-NtCreateToken(OUT PHANDLE TokenHandle,
- IN ACCESS_MASK DesiredAccess,
- IN POBJECT_ATTRIBUTES ObjectAttributes,
- IN TOKEN_TYPE TokenType,
- IN PLUID AuthenticationId,
- IN PLARGE_INTEGER ExpirationTime,
- IN PTOKEN_USER TokenUser,
- IN PTOKEN_GROUPS TokenGroups,
- IN PTOKEN_PRIVILEGES TokenPrivileges,
- IN PTOKEN_OWNER TokenOwner,
- IN PTOKEN_PRIMARY_GROUP TokenPrimaryGroup,
- IN PTOKEN_DEFAULT_DACL TokenDefaultDacl,
- IN PTOKEN_SOURCE TokenSource)
+NtCreateToken(
+ _Out_ PHANDLE TokenHandle,
+ _In_ ACCESS_MASK DesiredAccess,
+ _In_opt_ POBJECT_ATTRIBUTES ObjectAttributes,
+ _In_ TOKEN_TYPE TokenType,
+ _In_ PLUID AuthenticationId,
+ _In_ PLARGE_INTEGER ExpirationTime,
+ _In_ PTOKEN_USER TokenUser,
+ _In_ PTOKEN_GROUPS TokenGroups,
+ _In_ PTOKEN_PRIVILEGES TokenPrivileges,
+ _In_opt_ PTOKEN_OWNER TokenOwner,
+ _In_ PTOKEN_PRIMARY_GROUP TokenPrimaryGroup,
+ _In_opt_ PTOKEN_DEFAULT_DACL TokenDefaultDacl,
+ _In_ PTOKEN_SOURCE TokenSource)
{
HANDLE hToken;
KPROCESSOR_MODE PreviousMode;
- ULONG nTokenPrivileges = 0;
+ ULONG PrivilegeCount, GroupCount;
+ PSID OwnerSid, PrimaryGroupSid;
+ PACL DefaultDacl;
LARGE_INTEGER LocalExpirationTime = {{0, 0}};
+ LUID LocalAuthenticationId;
+ TOKEN_SOURCE LocalTokenSource;
+ SECURITY_QUALITY_OF_SERVICE LocalSecurityQos;
+ PLUID_AND_ATTRIBUTES CapturedPrivileges = NULL;
+ PSID_AND_ATTRIBUTES CapturedUser = NULL;
+ PSID_AND_ATTRIBUTES CapturedGroups = NULL;
+ PSID CapturedOwnerSid = NULL;
+ PSID CapturedPrimaryGroupSid = NULL;
+ PACL CapturedDefaultDacl = NULL;
+ ULONG PrivilegesLength, UserLength, GroupsLength;
NTSTATUS Status;
PAGED_CODE();
_SEH2_TRY
{
ProbeForWriteHandle(TokenHandle);
+
+ if (ObjectAttributes != NULL)
+ {
+ ProbeForRead(ObjectAttributes,
+ sizeof(OBJECT_ATTRIBUTES),
+ sizeof(ULONG));
+ LocalSecurityQos = *(SECURITY_QUALITY_OF_SERVICE*)ObjectAttributes->SecurityQualityOfService;
+ }
+
ProbeForRead(AuthenticationId,
sizeof(LUID),
sizeof(ULONG));
+ LocalAuthenticationId = *AuthenticationId;
+
LocalExpirationTime = ProbeForReadLargeInteger(ExpirationTime);
+
ProbeForRead(TokenUser,
sizeof(TOKEN_USER),
sizeof(ULONG));
+
ProbeForRead(TokenGroups,
sizeof(TOKEN_GROUPS),
sizeof(ULONG));
+ GroupCount = TokenGroups->GroupCount;
+
ProbeForRead(TokenPrivileges,
sizeof(TOKEN_PRIVILEGES),
sizeof(ULONG));
- ProbeForRead(TokenOwner,
- sizeof(TOKEN_OWNER),
- sizeof(ULONG));
+ PrivilegeCount = TokenPrivileges->PrivilegeCount;
+
+ if (TokenOwner != NULL)
+ {
+ ProbeForRead(TokenOwner,
+ sizeof(TOKEN_OWNER),
+ sizeof(ULONG));
+ OwnerSid = TokenOwner->Owner;
+ }
+ else
+ {
+ OwnerSid = NULL;
+ }
+
ProbeForRead(TokenPrimaryGroup,
sizeof(TOKEN_PRIMARY_GROUP),
sizeof(ULONG));
- ProbeForRead(TokenDefaultDacl,
- sizeof(TOKEN_DEFAULT_DACL),
- sizeof(ULONG));
+ PrimaryGroupSid = TokenPrimaryGroup->PrimaryGroup;
+
+ if (TokenDefaultDacl != NULL)
+ {
+ ProbeForRead(TokenDefaultDacl,
+ sizeof(TOKEN_DEFAULT_DACL),
+ sizeof(ULONG));
+ DefaultDacl = TokenDefaultDacl->DefaultDacl;
+ }
+ else
+ {
+ DefaultDacl = NULL;
+ }
+
ProbeForRead(TokenSource,
sizeof(TOKEN_SOURCE),
sizeof(ULONG));
- nTokenPrivileges = TokenPrivileges->PrivilegeCount;
+ LocalTokenSource = *TokenSource;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
}
else
{
- nTokenPrivileges = TokenPrivileges->PrivilegeCount;
+ if (ObjectAttributes != NULL)
+ LocalSecurityQos = *(SECURITY_QUALITY_OF_SERVICE*)ObjectAttributes->SecurityQualityOfService;
+ LocalAuthenticationId = *AuthenticationId;
LocalExpirationTime = *ExpirationTime;
+ GroupCount = TokenGroups->GroupCount;
+ PrivilegeCount = TokenPrivileges->PrivilegeCount;
+ OwnerSid = TokenOwner ? TokenOwner->Owner : NULL;
+ PrimaryGroupSid = TokenPrimaryGroup->PrimaryGroup;
+ DefaultDacl = TokenDefaultDacl ? TokenDefaultDacl->DefaultDacl : NULL;
+ LocalTokenSource = *TokenSource;
+ }
+
+ /* Check token type */
+ if ((TokenType < TokenPrimary) ||
+ (TokenType > TokenImpersonation))
+ {
+ return STATUS_BAD_TOKEN_TYPE;
+ }
+
+ /* Capture the user SID and attributes */
+ Status = SeCaptureSidAndAttributesArray(&TokenUser->User,
+ 1,
+ PreviousMode,
+ NULL,
+ 0,
+ PagedPool,
+ FALSE,
+ &CapturedUser,
+ &UserLength);
+ if (!NT_SUCCESS(Status))
+ {
+ goto Cleanup;
+ }
+
+ /* Capture the groups SID and attributes array */
+ Status = SeCaptureSidAndAttributesArray(&TokenGroups->Groups[0],
+ GroupCount,
+ PreviousMode,
+ NULL,
+ 0,
+ PagedPool,
+ FALSE,
+ &CapturedGroups,
+ &GroupsLength);
+ if (!NT_SUCCESS(Status))
+ {
+ goto Cleanup;
+ }
+
+ /* Capture privileges */
+ Status = SeCaptureLuidAndAttributesArray(&TokenPrivileges->Privileges[0],
+ PrivilegeCount,
+ PreviousMode,
+ NULL,
+ 0,
+ PagedPool,
+ FALSE,
+ &CapturedPrivileges,
+ &PrivilegesLength);
+ if (!NT_SUCCESS(Status))
+ {
+ goto Cleanup;
}
+ /* Capture the token owner SID */
+ if (TokenOwner != NULL)
+ {
+ Status = SepCaptureSid(OwnerSid,
+ PreviousMode,
+ PagedPool,
+ FALSE,
+ &CapturedOwnerSid);
+ if (!NT_SUCCESS(Status))
+ {
+ goto Cleanup;
+ }
+ }
+
+ /* Capture the token primary group SID */
+ Status = SepCaptureSid(PrimaryGroupSid,
+ PreviousMode,
+ PagedPool,
+ FALSE,
+ &CapturedPrimaryGroupSid);
+ if (!NT_SUCCESS(Status))
+ {
+ goto Cleanup;
+ }
+
+ /* Capture DefaultDacl */
+ if (DefaultDacl != NULL)
+ {
+ Status = SepCaptureAcl(DefaultDacl,
+ PreviousMode,
+ NonPagedPool,
+ FALSE,
+ &CapturedDefaultDacl);
+ if (!NT_SUCCESS(Status))
+ {
+ goto Cleanup;
+ }
+ }
+
+ /* Call the internal function */
Status = SepCreateToken(&hToken,
PreviousMode,
DesiredAccess,
ObjectAttributes,
TokenType,
- ((PSECURITY_QUALITY_OF_SERVICE)(ObjectAttributes->SecurityQualityOfService))->ImpersonationLevel,
- AuthenticationId,
+ LocalSecurityQos.ImpersonationLevel,
+ &LocalAuthenticationId,
&LocalExpirationTime,
- &TokenUser->User,
- TokenGroups->GroupCount,
- TokenGroups->Groups,
+ CapturedUser,
+ GroupCount,
+ CapturedGroups,
0, // FIXME: Should capture
- nTokenPrivileges,
- TokenPrivileges->Privileges,
- TokenOwner->Owner,
- TokenPrimaryGroup->PrimaryGroup,
- TokenDefaultDacl->DefaultDacl,
- TokenSource,
+ PrivilegeCount,
+ CapturedPrivileges,
+ CapturedOwnerSid,
+ CapturedPrimaryGroupSid,
+ CapturedDefaultDacl,
+ &LocalTokenSource,
FALSE);
if (NT_SUCCESS(Status))
{
_SEH2_END;
}
+Cleanup:
+
+ /* Release what we captured */
+ SeReleaseSidAndAttributesArray(CapturedUser, PreviousMode, FALSE);
+ SeReleaseSidAndAttributesArray(CapturedGroups, PreviousMode, FALSE);
+ SeReleaseLuidAndAttributesArray(CapturedPrivileges, PreviousMode, FALSE);
+ SepReleaseSid(CapturedOwnerSid, PreviousMode, FALSE);
+ SepReleaseSid(CapturedPrimaryGroupSid, PreviousMode, FALSE);
+ SepReleaseAcl(CapturedDefaultDacl, PreviousMode, FALSE);
+
return Status;
}
PACL Dacl = NULL;
KPROCESSOR_MODE PreviousMode;
NTSTATUS Status;
+ BOOLEAN RestoreImpersonation = FALSE;
PAGED_CODE();
_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 (OpenAsSelf)
{
- PsDisableImpersonation(PsGetCurrentThread(), &ImpersonationState);
+ RestoreImpersonation = PsDisableImpersonation(PsGetCurrentThread(),
+ &ImpersonationState);
}
if (CopyOnOpen)
if (Dacl) ExFreePoolWithTag(Dacl, TAG_TOKEN_ACL);
- if (OpenAsSelf)
+ if (RestoreImpersonation)
{
PsRestoreImpersonation(PsGetCurrentThread(), &ImpersonationState);
}
if (CopyOnOpen && NewThread) ObDereferenceObject(NewThread);
+ ObDereferenceObject(Thread);
+
if (NT_SUCCESS(Status))
{
_SEH2_TRY