Fixed Credential using a fixed-size 64-bit handle; it's always 2 pointers.

Reworked the Credential handle into a SafeCredentialHandle. We still use references to the raw handle, which is unsafe, but I will hopefully rework that soon.
This commit is contained in:
antiduh
2014-06-24 03:01:53 +00:00
parent 19f2e71e9c
commit fe14836949
7 changed files with 124 additions and 38 deletions

View File

@@ -25,8 +25,6 @@ namespace NSspi.Contexts
public SecurityStatus Init( byte[] serverToken, out byte[] outToken ) public SecurityStatus Init( byte[] serverToken, out byte[] outToken )
{ {
long credHandle = base.Credential.CredentialHandle;
long prevContextHandle = base.ContextHandle; long prevContextHandle = base.ContextHandle;
long newContextHandle = 0; long newContextHandle = 0;
@@ -62,7 +60,7 @@ namespace NSspi.Contexts
if ( prevContextHandle == 0 ) if ( prevContextHandle == 0 )
{ {
status = ContextNativeMethods.InitializeSecurityContext_1( status = ContextNativeMethods.InitializeSecurityContext_1(
ref credHandle, ref this.Credential.Handle.rawHandle,
IntPtr.Zero, IntPtr.Zero,
this.serverPrinc, this.serverPrinc,
this.requestedAttribs, this.requestedAttribs,
@@ -81,7 +79,7 @@ namespace NSspi.Contexts
using ( serverAdapter = new SecureBufferAdapter( serverBuffer ) ) using ( serverAdapter = new SecureBufferAdapter( serverBuffer ) )
{ {
status = ContextNativeMethods.InitializeSecurityContext_2( status = ContextNativeMethods.InitializeSecurityContext_2(
ref credHandle, ref this.Credential.Handle.rawHandle,
ref prevContextHandle, ref prevContextHandle,
this.serverPrinc, this.serverPrinc,
this.requestedAttribs, this.requestedAttribs,

View File

@@ -31,7 +31,7 @@ namespace NSspi.Contexts
SetLastError = true SetLastError = true
)] )]
public static extern SecurityStatus AcceptSecurityContext_1( public static extern SecurityStatus AcceptSecurityContext_1(
ref long credHandle, ref RawSspiHandle credHandle,
IntPtr oldContextHandle, IntPtr oldContextHandle,
IntPtr inputBuffer, IntPtr inputBuffer,
ContextAttrib requestedAttribs, ContextAttrib requestedAttribs,
@@ -51,7 +51,7 @@ namespace NSspi.Contexts
SetLastError = true SetLastError = true
)] )]
public static extern SecurityStatus AcceptSecurityContext_2( public static extern SecurityStatus AcceptSecurityContext_2(
ref long credHandle, ref RawSspiHandle credHandle,
ref long oldContextHandle, ref long oldContextHandle,
IntPtr inputBuffer, IntPtr inputBuffer,
ContextAttrib requestedAttribs, ContextAttrib requestedAttribs,
@@ -104,7 +104,7 @@ namespace NSspi.Contexts
SetLastError = true SetLastError = true
)] )]
public static extern SecurityStatus InitializeSecurityContext_1( public static extern SecurityStatus InitializeSecurityContext_1(
ref long credentialHandle, ref RawSspiHandle credentialHandle,
IntPtr zero, IntPtr zero,
string serverPrincipleName, string serverPrincipleName,
ContextAttrib requiredAttribs, ContextAttrib requiredAttribs,
@@ -126,7 +126,7 @@ namespace NSspi.Contexts
SetLastError = true SetLastError = true
)] )]
public static extern SecurityStatus InitializeSecurityContext_2( public static extern SecurityStatus InitializeSecurityContext_2(
ref long credentialHandle, ref RawSspiHandle credentialHandle,
ref long previousHandle, ref long previousHandle,
string serverPrincipleName, string serverPrincipleName,
ContextAttrib requiredAttribs, ContextAttrib requiredAttribs,

View File

@@ -24,7 +24,6 @@ namespace NSspi.Contexts
SecureBuffer clientBuffer = new SecureBuffer( clientToken, BufferType.Token ); SecureBuffer clientBuffer = new SecureBuffer( clientToken, BufferType.Token );
SecureBuffer outBuffer = new SecureBuffer( new byte[12288], BufferType.Token ); SecureBuffer outBuffer = new SecureBuffer( new byte[12288], BufferType.Token );
long credHandle = this.Credential.CredentialHandle;
long oldContextHandle = base.ContextHandle; long oldContextHandle = base.ContextHandle;
long newContextHandle = 0; long newContextHandle = 0;
@@ -42,7 +41,7 @@ namespace NSspi.Contexts
if ( oldContextHandle == 0 ) if ( oldContextHandle == 0 )
{ {
status = ContextNativeMethods.AcceptSecurityContext_1( status = ContextNativeMethods.AcceptSecurityContext_1(
ref credHandle, ref this.Credential.Handle.rawHandle,
IntPtr.Zero, IntPtr.Zero,
clientAdapter.Handle, clientAdapter.Handle,
requestedAttribs, requestedAttribs,
@@ -56,7 +55,7 @@ namespace NSspi.Contexts
else else
{ {
status = ContextNativeMethods.AcceptSecurityContext_2( status = ContextNativeMethods.AcceptSecurityContext_2(
ref credHandle, ref this.Credential.Handle.rawHandle,
ref oldContextHandle, ref oldContextHandle,
clientAdapter.Handle, clientAdapter.Handle,
requestedAttribs, requestedAttribs,

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.DirectoryServices.AccountManagement; using System.DirectoryServices.AccountManagement;
using System.Linq; using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
@@ -14,7 +15,7 @@ namespace NSspi
private SecurityPackage securityPackage; private SecurityPackage securityPackage;
private long credHandle; private SafeCredentialHandle safeCredHandle;
private long expiry; private long expiry;
public Credential(SecurityPackage package, CredentialType credentialType) public Credential(SecurityPackage package, CredentialType credentialType)
@@ -22,7 +23,6 @@ namespace NSspi
this.disposed = false; this.disposed = false;
this.securityPackage = package; this.securityPackage = package;
this.credHandle = 0;
this.expiry = 0; this.expiry = 0;
Init( package, credentialType ); Init( package, credentialType );
@@ -66,7 +66,19 @@ namespace NSspi
} }
// -- Invoke -- // -- Invoke --
SecurityStatus status = NativeMethods.AcquireCredentialsHandle(
SecurityStatus status = SecurityStatus.InternalError;
this.safeCredHandle = new SafeCredentialHandle();
// The finally clause is the actual constrained region. The VM pre-allocates any stack space,
// performs any allocations it needs to prepare methods for execution, and postpones any
// instances of the 'uncatchable' exceptions (ThreadAbort, StackOverflow, OutOfMemory).
RuntimeHelpers.PrepareConstrainedRegions();
try { }
finally
{
status = NativeMethods.AcquireCredentialsHandle(
null, null,
packageName, packageName,
use, use,
@@ -74,9 +86,10 @@ namespace NSspi
IntPtr.Zero, IntPtr.Zero,
IntPtr.Zero, IntPtr.Zero,
IntPtr.Zero, IntPtr.Zero,
ref this.credHandle, ref this.safeCredHandle.rawHandle,
ref this.expiry ref this.expiry
); );
}
if ( status != SecurityStatus.OK ) if ( status != SecurityStatus.OK )
{ {
@@ -112,7 +125,7 @@ namespace NSspi
string name = null; string name = null;
status = NativeMethods.QueryCredentialsAttribute_Name( status = NativeMethods.QueryCredentialsAttribute_Name(
ref this.credHandle, ref this.safeCredHandle.rawHandle,
CredentialQueryAttrib.Names, CredentialQueryAttrib.Names,
ref carrier ref carrier
); );
@@ -131,11 +144,11 @@ namespace NSspi
} }
} }
public long CredentialHandle public SafeCredentialHandle Handle
{ {
get get
{ {
return this.credHandle; return this.safeCredHandle;
} }
} }
@@ -149,16 +162,12 @@ namespace NSspi
{ {
if ( this.disposed == false ) if ( this.disposed == false )
{ {
SecurityStatus result; if ( disposing )
{
result = NativeMethods.FreeCredentialsHandle( ref this.credHandle ); this.safeCredHandle.Dispose();
}
this.disposed = true; this.disposed = true;
if ( disposing && result != SecurityStatus.OK )
{
throw new SSPIException( "Failed to release credentials handle", result );
}
} }
} }
} }

View File

@@ -72,6 +72,7 @@
<Compile Include="SecureBuffer\SecureBufferType.cs" /> <Compile Include="SecureBuffer\SecureBufferType.cs" />
<Compile Include="SecurityStatus.cs" /> <Compile Include="SecurityStatus.cs" />
<Compile Include="SSPIException.cs" /> <Compile Include="SSPIException.cs" />
<Compile Include="SspiHandle.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup /> <ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />

View File

@@ -58,7 +58,7 @@ namespace NSspi
IntPtr packageData, IntPtr packageData,
IntPtr getKeyFunc, IntPtr getKeyFunc,
IntPtr getKeyData, IntPtr getKeyData,
ref long credentialHandle, ref RawSspiHandle credentialHandle,
ref long expiry ref long expiry
); );
@@ -75,7 +75,7 @@ namespace NSspi
SetLastError = true SetLastError = true
)] )]
public static extern SecurityStatus FreeCredentialsHandle( public static extern SecurityStatus FreeCredentialsHandle(
ref long credentialHandle ref RawSspiHandle credentialHandle
); );
/* /*
@@ -118,7 +118,7 @@ namespace NSspi
SetLastError = true SetLastError = true
)] )]
public static extern SecurityStatus QueryCredentialsAttribute_Name( public static extern SecurityStatus QueryCredentialsAttribute_Name(
ref long credentialHandle, ref RawSspiHandle credentialHandle,
CredentialQueryAttrib attributeName, CredentialQueryAttrib attributeName,
ref QueryNameAttribCarrier name ref QueryNameAttribCarrier name
); );

79
SspiHandle.cs Normal file
View File

@@ -0,0 +1,79 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace NSspi
{
/// <summary>
/// Represents any SSPI handle created for credential handles, context handles, and security package
/// handles. Any SSPI handle is always the size of two native pointers.
/// </summary>
/// <remarks>
/// The documentation for SSPI handles can be found here:
/// http://msdn.microsoft.com/en-us/library/windows/desktop/aa380495(v=vs.85).aspx
///
/// This class is not reference safe - if used directly, or referenced directly, it may be leaked,
/// or subject to finalizer races, or any of the hundred of things SafeHandles were designed to fix.
/// Do not directly use this class - use only though SafeHandle wrapper objects. Any reference needed
/// to this handle for performing work (InitializeSecurityContext, eg), should be done through
/// a second class SafeSspiHandleReference so that reference counting is properly executed.
/// </remarks>
[StructLayout( LayoutKind.Sequential, Pack = 1 ) ]
public struct RawSspiHandle
{
private IntPtr lowPart;
private IntPtr highPart;
public bool IsZero()
{
return this.lowPart == IntPtr.Zero && this.highPart == IntPtr.Zero;
}
// This guy has to be executed in a CER.
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success)]
public void SetInvalid()
{
this.lowPart = IntPtr.Zero;
this.highPart = IntPtr.Zero;
}
}
public abstract class SafeSspiHandle : SafeHandle
{
internal RawSspiHandle rawHandle;
protected SafeSspiHandle()
: base( IntPtr.Zero, true )
{
this.rawHandle = new RawSspiHandle();
}
public override bool IsInvalid
{
get { return IsClosed || this.rawHandle.IsZero(); }
}
}
public class SafeCredentialHandle : SafeSspiHandle
{
public SafeCredentialHandle()
: base()
{ }
protected override bool ReleaseHandle()
{
SecurityStatus status = NativeMethods.FreeCredentialsHandle(
ref base.rawHandle
);
return status == SecurityStatus.OK;
}
}
}