X-Git-Url: https://git.reactos.org/?p=reactos.git;a=blobdiff_plain;f=ntoskrnl%2Fse%2Ftoken.c;h=46ab29b0f7c6ddfaac7a9c2e4aee66bb377bc3b2;hp=692cf301947d0b9c2c4b01a62a248be1f88a9d1c;hb=e49ef251b7a14d5a0261d0b5c3890c8abe03569d;hpb=64227df62485e7ca0e2e462e7497a1fdb0950205 diff --git a/ntoskrnl/se/token.c b/ntoskrnl/se/token.c index 692cf301947..46ab29b0f7c 100644 --- a/ntoskrnl/se/token.c +++ b/ntoskrnl/se/token.c @@ -108,6 +108,8 @@ SepCompareTokens(IN PTOKEN FirstToken, } /* 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; @@ -121,7 +123,7 @@ SepUpdateSinglePrivilegeFlagToken( _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) @@ -187,7 +189,7 @@ SepRemovePrivilegeToken( _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; @@ -230,8 +232,40 @@ SeExchangePrimaryToken(PEPROCESS Process, 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; @@ -260,6 +294,9 @@ SeDeassignPrimaryToken(PEPROCESS Process) /* Mark the Old Token as free */ OldToken->TokenInUse = 0; + + /* Dereference the Token */ + ObDereferenceObject(OldToken); } static ULONG @@ -311,12 +348,12 @@ SepFindPrimaryGroupAndDefaultOwner(PTOKEN Token, 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; @@ -336,7 +373,7 @@ SepDuplicateToken(PTOKEN Token, ULONG uLength; ULONG i; PVOID EndMem; - PTOKEN AccessToken = NULL; + PTOKEN AccessToken; NTSTATUS Status; PAGED_CODE(); @@ -359,25 +396,17 @@ SepDuplicateToken(PTOKEN Token, /* 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; @@ -460,19 +489,8 @@ SepDuplicateToken(PTOKEN Token, 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; @@ -537,13 +555,13 @@ SeIsTokenChild(IN PTOKEN Token, 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; @@ -586,6 +604,11 @@ SepDeleteToken(PVOID ObjectBody) { PTOKEN AccessToken = (PTOKEN)ObjectBody; + DPRINT("SepDeleteToken()\n"); + + /* Dereference the logon session */ + SepRmDereferenceLogonSession(&AccessToken->AuthenticationId); + if (AccessToken->UserAndGroups) ExFreePoolWithTag(AccessToken->UserAndGroups, TAG_TOKEN_USERS); @@ -676,6 +699,8 @@ SepCreateToken(OUT PHANDLE TokenHandle, NTSTATUS Status; ULONG TokenFlags = 0; + PAGED_CODE(); + /* Loop all groups */ for (i = 0; i < GroupCount; i++) { @@ -694,13 +719,8 @@ SepCreateToken(OUT PHANDLE TokenHandle, } } - 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, @@ -728,8 +748,11 @@ SepCreateToken(OUT PHANDLE TokenHandle, 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); @@ -871,11 +894,8 @@ SepCreateToken(OUT PHANDLE TokenHandle, done: if (!NT_SUCCESS(Status)) { - if (AccessToken) - { - /* Dereference the token, the delete procedure will clean up */ - ObDereferenceObject(AccessToken); - } + /* Dereference the token, the delete procedure will clean up */ + ObDereferenceObject(AccessToken); } return Status; @@ -1040,16 +1060,429 @@ SeFilterToken(IN PACCESS_TOKEN ExistingToken, } /* - * @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; + NTSTATUS Status; + PTOKEN Token = (PTOKEN)AccessToken; + ULONG RequiredLength; + union + { + PSID PSid; + ULONG Ulong; + } Unused; + + PAGED_CODE(); + + if (TokenInformationClass >= MaxTokenInfoClass) + { + DPRINT1("SeQueryInformationToken(%d) invalid information class\n", TokenInformationClass); + return STATUS_INVALID_INFO_CLASS; + } + + switch (TokenInformationClass) + { + case TokenUser: + { + PTOKEN_USER tu; + + DPRINT("SeQueryInformationToken(TokenUser)\n"); + RequiredLength = sizeof(TOKEN_USER) + + RtlLengthSid(Token->UserAndGroups[0].Sid); + + /* Allocate the output buffer */ + tu = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE); + if (tu == NULL) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + 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; + + DPRINT("SeQueryInformationToken(TokenGroups)\n"); + RequiredLength = sizeof(tg->GroupCount) + + RtlLengthSidAndAttributes(Token->UserAndGroupCount - 1, &Token->UserAndGroups[1]); + + 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; + } + + 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; + } + + case TokenPrivileges: + { + PTOKEN_PRIVILEGES tp; + + DPRINT("SeQueryInformationToken(TokenPrivileges)\n"); + RequiredLength = sizeof(tp->PrivilegeCount) + + (Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES)); + + /* Allocate the output buffer */ + tp = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE); + if (tp == NULL) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + tp->PrivilegeCount = Token->PrivilegeCount; + RtlCopyLuidAndAttributesArray(Token->PrivilegeCount, + Token->Privileges, + &tp->Privileges[0]); + + /* Return the structure */ + *TokenInformation = tp; + Status = STATUS_SUCCESS; + break; + } + + case TokenOwner: + { + PTOKEN_OWNER to; + ULONG SidLen; + + DPRINT("SeQueryInformationToken(TokenOwner)\n"); + SidLen = RtlLengthSid(Token->UserAndGroups[Token->DefaultOwnerIndex].Sid); + RequiredLength = sizeof(TOKEN_OWNER) + SidLen; + + /* Allocate the output buffer */ + to = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_SE); + if (to == NULL) + { + Status = STATUS_INSUFFICIENT_RESOURCES; + break; + } + + to->Owner = (PSID)(to + 1); + Status = RtlCopySid(SidLen, + to->Owner, + Token->UserAndGroups[Token->DefaultOwnerIndex].Sid); + + /* 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; } /* @@ -1153,15 +1586,15 @@ NtQueryInformationToken(IN HANDLE TokenHandle, IN ULONG TokenInformationLength, OUT PULONG ReturnLength) { + NTSTATUS Status; + KPROCESSOR_MODE PreviousMode; + PTOKEN Token; + ULONG RequiredLength; union { - PVOID Ptr; + PSID PSid; ULONG Ulong; } Unused; - PTOKEN Token; - ULONG RequiredLength; - KPROCESSOR_MODE PreviousMode; - NTSTATUS Status; PAGED_CODE(); @@ -1170,7 +1603,7 @@ NtQueryInformationToken(IN HANDLE TokenHandle, /* Check buffers and class validity */ Status = DefaultQueryInfoBufferCheck(TokenInformationClass, SeTokenInformationClass, - sizeof(SeTokenInformationClass) / sizeof(SeTokenInformationClass[0]), + RTL_NUMBER_OF(SeTokenInformationClass), TokenInformation, TokenInformationLength, ReturnLength, @@ -1198,7 +1631,7 @@ NtQueryInformationToken(IN HANDLE TokenHandle, DPRINT("NtQueryInformationToken(TokenUser)\n"); RequiredLength = sizeof(TOKEN_USER) + - RtlLengthSid(Token->UserAndGroups[0].Sid); + RtlLengthSid(Token->UserAndGroups[0].Sid); _SEH2_TRY { @@ -1209,7 +1642,7 @@ NtQueryInformationToken(IN HANDLE TokenHandle, RequiredLength - sizeof(TOKEN_USER), &tu->User, (PSID)(tu + 1), - &Unused.Ptr, + &Unused.PSid, &Unused.Ulong); } else @@ -1237,24 +1670,24 @@ NtQueryInformationToken(IN HANDLE TokenHandle, 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 @@ -1282,7 +1715,7 @@ NtQueryInformationToken(IN HANDLE TokenHandle, DPRINT("NtQueryInformationToken(TokenPrivileges)\n"); RequiredLength = sizeof(tp->PrivilegeCount) + - (Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES)); + (Token->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES)); _SEH2_TRY { @@ -1314,8 +1747,8 @@ NtQueryInformationToken(IN HANDLE TokenHandle, case TokenOwner: { - ULONG SidLen; PTOKEN_OWNER to = (PTOKEN_OWNER)TokenInformation; + ULONG SidLen; DPRINT("NtQueryInformationToken(TokenOwner)\n"); SidLen = RtlLengthSid(Token->UserAndGroups[Token->DefaultOwnerIndex].Sid); @@ -1351,8 +1784,8 @@ NtQueryInformationToken(IN HANDLE TokenHandle, case TokenPrimaryGroup: { - ULONG SidLen; PTOKEN_PRIMARY_GROUP tpg = (PTOKEN_PRIMARY_GROUP)TokenInformation; + ULONG SidLen; DPRINT("NtQueryInformationToken(TokenPrimaryGroup)\n"); SidLen = RtlLengthSid(Token->PrimaryGroup); @@ -1394,9 +1827,7 @@ NtQueryInformationToken(IN HANDLE TokenHandle, RequiredLength = sizeof(TOKEN_DEFAULT_DACL); if (Token->DefaultDacl != NULL) - { RequiredLength += Token->DefaultDacl->AclSize; - } _SEH2_TRY { @@ -1629,17 +2060,17 @@ NtQueryInformationToken(IN HANDLE TokenHandle, 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 @@ -1672,14 +2103,12 @@ NtQueryInformationToken(IN HANDLE TokenHandle, 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) @@ -1719,7 +2148,7 @@ NtQueryInformationToken(IN HANDLE TokenHandle, NTSTATUS NTAPI NtSetInformationToken(IN HANDLE TokenHandle, IN TOKEN_INFORMATION_CLASS TokenInformationClass, - OUT PVOID TokenInformation, + IN PVOID TokenInformation, IN ULONG TokenInformationLength) { PTOKEN Token; @@ -1733,7 +2162,7 @@ NtSetInformationToken(IN HANDLE TokenHandle, Status = DefaultSetInfoBufferCheck(TokenInformationClass, SeTokenInformationClass, - sizeof(SeTokenInformationClass) / sizeof(SeTokenInformationClass[0]), + RTL_NUMBER_OF(SeTokenInformationClass), TokenInformation, TokenInformationLength, PreviousMode); @@ -1773,7 +2202,7 @@ NtSetInformationToken(IN HANDLE TokenHandle, _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Status = _SEH2_GetExceptionCode(); - goto Cleanup; + _SEH2_YIELD(goto Cleanup); } _SEH2_END; @@ -1813,7 +2242,7 @@ NtSetInformationToken(IN HANDLE TokenHandle, _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Status = _SEH2_GetExceptionCode(); - goto Cleanup; + _SEH2_YIELD(goto Cleanup); } _SEH2_END; @@ -1853,7 +2282,7 @@ NtSetInformationToken(IN HANDLE TokenHandle, _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Status = _SEH2_GetExceptionCode(); - goto Cleanup; + _SEH2_YIELD(goto Cleanup); } _SEH2_END; @@ -1875,8 +2304,20 @@ NtSetInformationToken(IN HANDLE TokenHandle, 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 @@ -1908,7 +2349,7 @@ NtSetInformationToken(IN HANDLE TokenHandle, _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Status = _SEH2_GetExceptionCode(); - goto Cleanup; + _SEH2_YIELD(goto Cleanup); } _SEH2_END; @@ -1935,7 +2376,7 @@ NtSetInformationToken(IN HANDLE TokenHandle, _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Status = _SEH2_GetExceptionCode(); - goto Cleanup; + _SEH2_YIELD(goto Cleanup); } _SEH2_END; @@ -2019,7 +2460,7 @@ NtSetInformationToken(IN HANDLE TokenHandle, _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Status = _SEH2_GetExceptionCode(); - goto Cleanup; + _SEH2_YIELD(goto Cleanup); } _SEH2_END; @@ -2054,7 +2495,7 @@ NtSetInformationToken(IN HANDLE TokenHandle, _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Status = _SEH2_GetExceptionCode(); - goto Cleanup; + _SEH2_YIELD(goto Cleanup); } _SEH2_END; @@ -2108,14 +2549,16 @@ Cleanup: * @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) @@ -2259,7 +2702,7 @@ NtAdjustGroupsToken(IN HANDLE TokenHandle, OUT PULONG ReturnLength) { UNIMPLEMENTED; - return(STATUS_NOT_IMPLEMENTED); + return STATUS_NOT_IMPLEMENTED; } @@ -2522,7 +2965,7 @@ NtAdjustPrivilegesToken( { /* Do cleanup and return the exception code */ Status = _SEH2_GetExceptionCode(); - goto Cleanup; + _SEH2_YIELD(goto Cleanup); } _SEH2_END; @@ -2550,7 +2993,7 @@ NtAdjustPrivilegesToken( { /* Do cleanup and return the exception code */ Status = _SEH2_GetExceptionCode(); - goto Cleanup; + _SEH2_YIELD(goto Cleanup); } _SEH2_END; @@ -2680,7 +3123,7 @@ NtCreateToken( _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Return the exception code */ - return _SEH2_GetExceptionCode(); + _SEH2_YIELD(return _SEH2_GetExceptionCode()); } _SEH2_END; } @@ -2783,6 +3226,10 @@ NtCreateToken( NonPagedPool, FALSE, &CapturedDefaultDacl); + if (!NT_SUCCESS(Status)) + { + goto Cleanup; + } } /* Call the internal function */ @@ -2873,10 +3320,12 @@ NtOpenThreadTokenEx(IN HANDLE ThreadHandle, _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, @@ -2975,6 +3424,8 @@ NtOpenThreadTokenEx(IN HANDLE ThreadHandle, if (CopyOnOpen && NewThread) ObDereferenceObject(NewThread); + ObDereferenceObject(Thread); + if (NT_SUCCESS(Status)) { _SEH2_TRY