summaryrefslogtreecommitdiffstats
path: root/private/ntos/se/seclient.c
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/se/seclient.c
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/ntos/se/seclient.c')
-rw-r--r--private/ntos/se/seclient.c633
1 files changed, 633 insertions, 0 deletions
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
+ );
+
+}