From b8fd4d9a07a198b9809d56d55e01ce0014a49f9b Mon Sep 17 00:00:00 2001 From: antiduh Date: Tue, 1 Jul 2014 15:52:00 +0000 Subject: [PATCH] Added a helpful flag to ServerContext to indicate to consumers whether it can support impersonation. Added checks to throw exceptions if impersonation is attempted on a ServerContext that does not support impersonation. Also modified the disposal behavior so that if the ServerContext is disposed while impersonation is occurring, impersonation is explicitly reverted. Consumers wishing to perform long-term impersonation must hold valid references to both the context and impersonation handle. --- NSspi/Contexts/ServerContext.cs | 37 +++++++++++++++++++++++++++++---- NSspi/Credentials/Credential.cs | 4 ++++ 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/NSspi/Contexts/ServerContext.cs b/NSspi/Contexts/ServerContext.cs index 1b3b3b9..b3a2263 100644 --- a/NSspi/Contexts/ServerContext.cs +++ b/NSspi/Contexts/ServerContext.cs @@ -22,8 +22,18 @@ namespace NSspi.Contexts this.finalAttribs = ContextAttrib.Zero; this.impersonating = false; + + this.SupportsImpersonate = this.Credential.PackageInfo.Capabilities.HasFlag( SecPkgCapability.Impersonation ); } + /// + /// Whether or not the server can impersonate an authenticated client. + /// + /// + /// This depends on the security package that was used to create the server and client's credentials. + /// + public bool SupportsImpersonate { get; private set; } + public SecurityStatus AcceptToken( byte[] clientToken, out byte[] nextToken ) { SecureBuffer clientBuffer = new SecureBuffer( clientToken, BufferType.Token ); @@ -93,8 +103,6 @@ namespace NSspi.Contexts } this.Expiry = rawExpiry.ToDateTime(); - - InitProviderCapabilities(); } else if ( status == SecurityStatus.ContinueNeeded ) { @@ -113,7 +121,7 @@ namespace NSspi.Contexts public ImpersonationHandle ImpersonateClient() { - ImpersonationHandle handle = new ImpersonationHandle( this ); + ImpersonationHandle handle; SecurityStatus status = SecurityStatus.InternalError; bool gotRef = false; @@ -125,7 +133,14 @@ namespace NSspi.Contexts { throw new InvalidOperationException( "Cannot impersonate again while already impersonating." ); } + else if( this.SupportsImpersonate == false ) + { + throw new InvalidOperationException( + "The ServerContext is using a security package that does not support impersonation." + ); + } + handle = new ImpersonationHandle( this ); RuntimeHelpers.PrepareConstrainedRegions(); try { @@ -211,8 +226,22 @@ namespace NSspi.Contexts } } - private void InitProviderCapabilities() + protected override void Dispose( bool disposing ) { + // We were disposed while impersonating. This means that the consumer that is currently holding + // the impersonation handle allowed the context to be disposed or finalized while an impersonation handle + // was held. We have to revert impersonation to restore the thread's behavior, since once the context + // goes away, there's nothing left. + // + // When and if the impersonation handle is diposed/finalized, it'll see that the context has already been + // disposed, will assume that we already reverted, and so will do nothing. + + if( this.impersonating ) + { + RevertImpersonate(); + } + + base.Dispose( disposing ); } } } diff --git a/NSspi/Credentials/Credential.cs b/NSspi/Credentials/Credential.cs index 5976d42..b890940 100644 --- a/NSspi/Credentials/Credential.cs +++ b/NSspi/Credentials/Credential.cs @@ -28,6 +28,8 @@ namespace NSspi.Credentials this.securityPackage = package; this.expiry = DateTime.MinValue; + + this.PackageInfo = PackageSupport.GetPackageCapabilities( this.SecurityPackage ); } ~Credential() @@ -35,6 +37,8 @@ namespace NSspi.Credentials Dispose( false ); } + public SecPkgInfo PackageInfo { get; private set; } + public string SecurityPackage { get