From e611b132f9b8abe35b362e5870b74bce94a1e58e Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 16 May 2020 20:51:50 -0700 Subject: initial commit --- private/ntos/se/seclient.c | 633 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 633 insertions(+) create mode 100644 private/ntos/se/seclient.c (limited to 'private/ntos/se/seclient.c') diff --git a/private/ntos/se/seclient.c b/private/ntos/se/seclient.c new file mode 100644 index 000000000..8f330cc9d --- /dev/null +++ b/private/ntos/se/seclient.c @@ -0,0 +1,633 @@ + +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + seclient.c + +Abstract: + + This module implements routines providing client impersonation to + communication session layers (such as LPC Ports). + + WARNING: The following notes apply to the use of these services: + + (1) No synchronization of operations to a security context block are + performed by these services. The caller of these services must + ensure that use of an individual security context block is + serialized to prevent simultaneous, incompatible updates. + + (2) Any or all of these services may create, open, or operate on a + token object. This may result in a mutex being acquired at + MUTEXT_LEVEL_SE_TOKEN level. The caller must ensure that no + mutexes are held at levels that conflict with this action. + + +Author: + + Jim Kelly (JimK) 1-August-1990 + +Environment: + + Kernel mode only. + +Revision History: + +--*/ + + +#include "sep.h" +#include "seopaque.h" + + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE,SeCreateClientSecurity) +#pragma alloc_text(PAGE,SeUpdateClientSecurity) +#pragma alloc_text(PAGE,SeImpersonateClient) +#endif + + +//////////////////////////////////////////////////////////////////////// +// // +// Routines // +// // +//////////////////////////////////////////////////////////////////////// + + +NTSTATUS +SeCreateClientSecurity ( + IN PETHREAD ClientThread, + IN PSECURITY_QUALITY_OF_SERVICE ClientSecurityQos, + IN BOOLEAN ServerIsRemote, + OUT PSECURITY_CLIENT_CONTEXT ClientContext + ) + +/*++ + +Routine Description: + + This service initializes a context block to represent a client's + security context. This may simply result in a reference to the + client's token, or may cause the client's token to be duplicated, + depending upon the security quality of service information specified. + + NOTE + + The code in this routine is optimized for DYNAMIC context + tracking. This is only mode in which direct access to a + caller's token is allowed, and the mode expected to be used + most often. STATIC context tracking always requires the + caller's token to be copied. + + +Arguments: + + ClientThread - Points to the client's thread. This is used to + locate the client's security context (token). + + ClientSecurityQos - Points to the security quality of service + parameters specified by the client for this communication + session. + + ServerIsRemote - Provides an indication as to whether the session + this context block is being used for is an inter-system + session or intra-system session. This is reconciled with the + impersonation level of the client thread's token (in case the + client has a client of his own that didn't specify delegation). + + ClientContext - Points to the client security context block to be + initialized. + + +Return Value: + + STATUS_SUCCESS - The service completed successfully. + + STATUS_BAD_IMPERSONATION_LEVEL - The client is currently + impersonating either an Anonymous or Identification level + token, which can not be passed on for use by another server. + This status may also be returned if the security context + block is for an inter-system communication session and the + client thread is impersonating a client of its own using + other than delegation impersonation level. + + +--*/ + +{ + NTSTATUS Status = STATUS_SUCCESS; + PACCESS_TOKEN Token; + TOKEN_TYPE TokenType; + BOOLEAN ThreadEffectiveOnly; + SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; + PACCESS_TOKEN DuplicateToken; + + PAGED_CODE(); + + // + // Gain access to the client thread's effective token + // + + Token = PsReferenceEffectiveToken( + ClientThread, + &TokenType, + &ThreadEffectiveOnly, + &ImpersonationLevel + ); + + + // + // Make sure the client is not trying to abuse use of a + // client of its own by attempting an invalid impersonation. + // Also set the ClientContext->DirectAccessEffectiveOnly flag + // appropriately if the impersonation is legitimate. The + // DirectAccessEffectiveOnly flag value will end up being ignored + // if STATIC mode is requested, but this is the most efficient + // place to calculate it, and we are optimizing for DYNAMIC mode. + // + + if (TokenType == TokenImpersonation) { + + if ( ClientSecurityQos->ImpersonationLevel > ImpersonationLevel) { + + PsDereferenceImpersonationToken( Token ); + return STATUS_BAD_IMPERSONATION_LEVEL; + + } + + + if ( SepBadImpersonationLevel(ImpersonationLevel,ServerIsRemote)) { + + PsDereferenceImpersonationToken( Token ); + return STATUS_BAD_IMPERSONATION_LEVEL; + + } else { + + // + // TokenType is TokenImpersonation and the impersonation is legit. + // Set the DirectAccessEffectiveOnly flag to be the minimum of + // the current thread value and the caller specified value. + // + + ClientContext->DirectAccessEffectiveOnly = + ( (ThreadEffectiveOnly || (ClientSecurityQos->EffectiveOnly)) ? + TRUE : FALSE ); + } + + } else { + + // + // TokenType is TokenPrimary. In this case, the client specified + // EffectiveOnly value is always used. + // + + ClientContext->DirectAccessEffectiveOnly = + ClientSecurityQos->EffectiveOnly; + } + + + + // + // Copy the token if necessary (i.e., static tracking requested) + // + + if (ClientSecurityQos->ContextTrackingMode == SECURITY_STATIC_TRACKING) { + + ClientContext->DirectlyAccessClientToken = FALSE; + + Status = SeCopyClientToken( + Token, + ClientSecurityQos->ImpersonationLevel, + KernelMode, + &DuplicateToken + ); + + + if ( NT_SUCCESS(Status) ) { + ObDeleteCapturedInsertInfo(DuplicateToken); + } + // + // No longer need the pointer to the client's token + // + + if (TokenType == TokenPrimary) { + PsDereferencePrimaryToken( Token ); + } else { + PsDereferenceImpersonationToken( Token ); + } + + Token = DuplicateToken; + + + // + // If there was an error, we're done. + // + if (!NT_SUCCESS(Status)) { + return Status; + } + + } else { + + ClientContext->DirectlyAccessClientToken = TRUE; + + if (ServerIsRemote) { + // + // Get a copy of the client token's control information + // so that we can tell if it changes in the future. + // + + SeGetTokenControlInformation( Token, + &ClientContext->ClientTokenControl + ); + + } + + } + + + + ClientContext->SecurityQos.Length = + (ULONG)sizeof(SECURITY_QUALITY_OF_SERVICE); + + ClientContext->SecurityQos.ImpersonationLevel = + ClientSecurityQos->ImpersonationLevel; + + ClientContext->SecurityQos.ContextTrackingMode = + ClientSecurityQos->ContextTrackingMode; + + ClientContext->SecurityQos.EffectiveOnly = + ClientSecurityQos->EffectiveOnly; + + ClientContext->ServerIsRemote = ServerIsRemote; + + ClientContext->ClientToken = Token; + + return STATUS_SUCCESS; + + + +} + + + +#if SAVE_FOR_PRODUCT_2 + + + + +NTSTATUS +SeUpdateClientSecurity( + IN PETHREAD ClientThread, + IN OUT PSECURITY_CLIENT_CONTEXT ClientContext, + OUT PBOOLEAN ChangesMade, + OUT PBOOLEAN NewToken + ) + +/*++ + +Routine Description: + + This service is used to update a client security context block + based upon the client's current security context and the security + quality of service parameters specified when the security block + was created. If the SecurityContextTracking specified when the + context block was created indicated static tracking, then no + change will be made to the context block. Otherwise, a change may + be made. + + + An indication of whether any changes were made is returned to the + caller. This may be used by communication session layers + providing remote communications to decide whether or not to send + an updated security context to the remote server's node. It may + also be used by a server session layer to decide whether or not to + inform a server that a previously obtained handle to a token no + longer represents the current security context. + + +Arguments: + + ClientThread - Points to the client's thread. This is used to + locate the security context to synchronize with. + + ClientContext - Points to client security context block to be + updated. + + ChangesMade - Receives an indication as to whether any changes to + the client's security context had been made since the last + time the security context block was synchronized. This will + always be FALSE if static security tracking is in effect. + + NewToken - Receives an indication as to whether the same token + is used to represent the client's current context, or whether + the context now points to a new token. If the client's token + is directly referenced, then this indicates the client changed + tokens (and the new one is now referenced). If the client's token + isn't directly referenced, then this indicates it was necessary + to delete one token and create another one. This will always be + FALSE if static security tracking is in effect. + + +Return Value: + + STATUS_SUCCESS - The service completed successfully. + + STATUS_BAD_IMPERSONATION_LEVEL - The client is currently + impersonating either an Anonymous or Identification level + token, which can not be passed on for use by another server. + This status may also be returned if the security context + block is for an inter-system communication session and the + client thread is impersonating a client of its own using + other than delegation impersonation level. + + +--*/ + +{ + NTSTATUS Status; + PACCESS_TOKEN Token; + TOKEN_TYPE TokenType; + BOOLEAN ThreadEffectiveOnly; + SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; + PACCESS_TOKEN DuplicateToken; + TOKEN_CONTROL TokenControl; + + PAGED_CODE(); + + if (ClientContext->SecurityQos.ContextTrackingMode == + SECURITY_STATIC_TRACKING) { + + (*NewToken) = FALSE; + (*ChangesMade) = FALSE; + return STATUS_SUCCESS; + + } + + + ////////////////////////////////////////////// + // // + // Optimize for the directly accessed token // + // // + ////////////////////////////////////////////// + + + + // + // Gain access to the client thread's effective token + // + + Token = PsReferenceEffectiveToken( + ClientThread, + &TokenType, + &ThreadEffectiveOnly, + &ImpersonationLevel + ); + + + + // + // See if the token is the same. + // + + + SeGetTokenControlInformation( Token, &TokenControl ); + + if ( SeSameToken( &TokenControl, + &ClientContext->ClientTokenControl) ) { + + (*NewToken = FALSE); + + + // + // Same token. + // Is it unmodified? + // + + if ( (TokenControl.ModifiedId.HighPart == + ClientContext->ClientTokenControl.ModifiedId.HighPart) && + (TokenControl.ModifiedId.LowPart == + ClientContext->ClientTokenControl.ModifiedId.LowPart) ) { + + // + // Yup. No changes necessary. + // + + if (TokenType == TokenPrimary) { + PsDereferencePrimaryToken( Token ); + } else { + PsDereferenceImpersonationToken( Token ); + } + + (*ChangesMade) = FALSE; + return STATUS_SUCCESS; + + } else { + + // + // Same token, but it has been modified. + // If we are directly accessing the token, then we can + // just indicate it has changed and return. Otherwise + // we have to actually update our copy of the token. + // + + (*ChangesMade) = TRUE; + if (ClientContext->DirectlyAccessClientToken) { + + if (TokenType == TokenPrimary) { + PsDereferencePrimaryToken( Token ); + } else { + PsDereferenceImpersonationToken( Token ); + } + + // + // Save the new modified count and whether or not + // the token is for effective use only + // + + ClientContext->ClientTokenControl.ModifiedId = + TokenControl.ModifiedId; + ClientContext->DirectAccessEffectiveOnly = + ( (ThreadEffectiveOnly || (ClientContext->SecurityQos.EffectiveOnly)) ? + TRUE : FALSE ); + + return STATUS_SUCCESS; + } else { + + // + // There is a possibility for a fair performance gain here + // by just updating the existing token to match its origin. + // However, it isn't clear that this case is ever really + // used, so the effort and complexity is avoided at this time. + // If it is found that this case is used, then this code + // can be added. + // + // Instead, we just fall through to the case of completely + // different tokens below. + // + } + } + } + + + // + // Not the same token, or the same token has changed. + // In either case, we're going to create a new copy of the token + // and dump the old copy. + // + // Make sure the current impersonation situation is legitimate. + // + + (*NewToken) = TRUE; + (*ChangesMade) = TRUE; + if (TokenType == TokenImpersonation) { + if ( SepBadImpersonationLevel(ImpersonationLevel, + ClientContext->ServerIsRemote)) { + + PsDereferenceImpersonationToken( Token ); + return STATUS_BAD_IMPERSONATION_LEVEL; + } + } + + + // + // Copy the token + // + + + + Status = SeCopyClientToken( + Token, + ClientContext->SecurityQos.ImpersonationLevel, + KernelMode, + &DuplicateToken + ); + + + // + // No longer need the pointer to the client's effective token + // + + if (TokenType == TokenPrimary) { + PsDereferencePrimaryToken( Token ); + } else { + PsDereferenceImpersonationToken( Token ); + } + + + + // + // If there was an error, we're done. + // + if (!NT_SUCCESS(Status)) { + return Status; + } + + + // + // Otherwise, replace the current token with the new one. + // + + Token = ClientContext->ClientToken; + ClientContext->ClientToken = DuplicateToken; + ClientContext->DirectlyAccessClientToken = FALSE; + + if (SeTokenType( Token ) == TokenPrimary) { + PsDereferencePrimaryToken( Token ); + } else { + PsDereferenceImpersonationToken( Token ); + } + + + // + // Get a copy of the current token's control information + // so that we can tell if it changes in the future. + // + + SeGetTokenControlInformation( DuplicateToken, + &ClientContext->ClientTokenControl + ); + + + return STATUS_SUCCESS; + +} + + +#endif + + + + +VOID +SeImpersonateClient( + IN PSECURITY_CLIENT_CONTEXT ClientContext, + IN PETHREAD ServerThread OPTIONAL + ) +/*++ + +Routine Description: + + This service is used to cause the calling thread to impersonate a + client. The client security context in ClientContext is assumed to + be up to date. + + +Arguments: + + ClientContext - Points to client security context block. + + ServerThread - (Optional) Specifies the thread which is to be made to + impersonate the client. If not specified, the calling thread is + used. + + +Return Value: + + None. + + +--*/ + + +{ + + BOOLEAN EffectiveValueToUse; + PETHREAD Thread; + + PAGED_CODE(); + + if (ClientContext->DirectlyAccessClientToken) { + EffectiveValueToUse = ClientContext->DirectAccessEffectiveOnly; + } else { + EffectiveValueToUse = ClientContext->SecurityQos.EffectiveOnly; + } + + + + // + // if a ServerThread wasn't specified, then default to the current + // thread. + // + + if (!ARGUMENT_PRESENT(ServerThread)) { + Thread = PsGetCurrentThread(); + } else { + Thread = ServerThread; + } + + + + // + // Assign the context to the calling thread + // + + PsImpersonateClient( Thread, + ClientContext->ClientToken, + TRUE, + EffectiveValueToUse, + ClientContext->SecurityQos.ImpersonationLevel + ); + +} -- cgit v1.2.3