https://git.reactos.org/?p=reactos.git;a=commitdiff;h=18ddb6ba9248f1812b1822...
commit 18ddb6ba9248f1812b182277d28d6e86707cb91f Author: George Bișoc george.bisoc@reactos.org AuthorDate: Mon Apr 12 14:33:42 2021 +0200 Commit: George Bișoc george.bisoc@reactos.org CommitDate: Sun May 2 16:55:19 2021 +0200
[NTOS:SE] Implement SeTokenCanImpersonate routine
SeTokenCanImpersonate ensures whether the client impersonation can occur, and if not, the call signals this to the caller. --- ntoskrnl/include/internal/se.h | 7 +++ ntoskrnl/se/token.c | 98 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+)
diff --git a/ntoskrnl/include/internal/se.h b/ntoskrnl/include/internal/se.h index 727060af822..0a8561d397a 100644 --- a/ntoskrnl/include/internal/se.h +++ b/ntoskrnl/include/internal/se.h @@ -248,6 +248,13 @@ SepSidInTokenEx( IN BOOLEAN Restricted );
+BOOLEAN +NTAPI +SeTokenCanImpersonate( + _In_ PTOKEN ProcessToken, + _In_ PTOKEN TokenToImpersonate, + _In_ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel); + /* Functions */ BOOLEAN NTAPI diff --git a/ntoskrnl/se/token.c b/ntoskrnl/se/token.c index 1849a16c3a7..32842ebce99 100644 --- a/ntoskrnl/se/token.c +++ b/ntoskrnl/se/token.c @@ -2265,6 +2265,104 @@ SeTokenIsWriteRestricted(IN PACCESS_TOKEN Token) return (((PTOKEN)Token)->TokenFlags & SE_BACKUP_PRIVILEGES_CHECKED) != 0; }
+/** + * @brief + * Ensures that client impersonation can occur by checking if the token + * we're going to assign as the impersonation token can be actually impersonated + * in the first place. The routine is used primarily by PsImpersonateClient. + * + * @param[in] ProcessToken + * Token from a process. + * + * @param[in] TokenToImpersonate + * Token that we are going to impersonate. + * + * @param[in] ImpersonationLevel + * Security impersonation level grade. + * + * @return + * Returns TRUE if the conditions checked are met for token impersonation, + * FALSE otherwise. + */ +BOOLEAN +NTAPI +SeTokenCanImpersonate( + _In_ PTOKEN ProcessToken, + _In_ PTOKEN TokenToImpersonate, + _In_ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel) +{ + BOOLEAN CanImpersonate; + PAGED_CODE(); + + /* + * SecurityAnonymous and SecurityIdentification levels do not + * allow impersonation. If we get such levels from the call + * then something's seriously wrong. + */ + ASSERT(ImpersonationLevel != SecurityAnonymous || + ImpersonationLevel != SecurityIdentification); + + /* Time to lock our tokens */ + SepAcquireTokenLockShared(ProcessToken); + SepAcquireTokenLockShared(TokenToImpersonate); + + /* What kind of authentication ID does the token have? */ + if (RtlEqualLuid(&TokenToImpersonate->AuthenticationId, + &SeAnonymousAuthenticationId)) + { + /* + * OK, it looks like the token has an anonymous + * authentication. Is that token created by the system? + */ + if (TokenToImpersonate->TokenSource.SourceName != SeSystemTokenSource.SourceName && + !RtlEqualLuid(&TokenToImpersonate->TokenSource.SourceIdentifier, &SeSystemTokenSource.SourceIdentifier)) + { + /* It isn't, we can't impersonate regular tokens */ + DPRINT("SeTokenCanImpersonate(): Token has an anonymous authentication ID, can't impersonate!\n"); + CanImpersonate = FALSE; + goto Quit; + } + } + + /* Are the SID values from both tokens equal? */ + if (!RtlEqualSid(ProcessToken->UserAndGroups->Sid, + TokenToImpersonate->UserAndGroups->Sid)) + { + /* They aren't, bail out */ + DPRINT("SeTokenCanImpersonate(): Tokens SIDs are not equal!\n"); + CanImpersonate = FALSE; + goto Quit; + } + + /* + * Make sure the tokens aren't diverged in terms of + * restrictions, that is, one token is restricted + * but the other one isn't. + */ + if (SeTokenIsRestricted(ProcessToken) != + SeTokenIsRestricted(TokenToImpersonate)) + { + /* + * One token is restricted so we cannot + * continue further at this point, bail out. + */ + DPRINT("SeTokenCanImpersonate(): One token is restricted, can't continue!\n"); + CanImpersonate = FALSE; + goto Quit; + } + + /* If we've reached that far then we can impersonate! */ + DPRINT("SeTokenCanImpersonate(): We can impersonate.\n"); + CanImpersonate = TRUE; + +Quit: + /* We're done, unlock the tokens now */ + SepReleaseTokenLock(ProcessToken); + SepReleaseTokenLock(TokenToImpersonate); + + return CanImpersonate; +} + /* SYSTEM CALLS ***************************************************************/
/*