diff --git a/Contexts/ClientContext.cs b/Contexts/ClientContext.cs
index c4270c2..437052d 100644
--- a/Contexts/ClientContext.cs
+++ b/Contexts/ClientContext.cs
@@ -25,8 +25,6 @@ namespace NSspi.Contexts
public SecurityStatus Init( byte[] serverToken, out byte[] outToken )
{
- long credHandle = base.Credential.CredentialHandle;
-
long prevContextHandle = base.ContextHandle;
long newContextHandle = 0;
@@ -62,7 +60,7 @@ namespace NSspi.Contexts
if ( prevContextHandle == 0 )
{
status = ContextNativeMethods.InitializeSecurityContext_1(
- ref credHandle,
+ ref this.Credential.Handle.rawHandle,
IntPtr.Zero,
this.serverPrinc,
this.requestedAttribs,
@@ -81,7 +79,7 @@ namespace NSspi.Contexts
using ( serverAdapter = new SecureBufferAdapter( serverBuffer ) )
{
status = ContextNativeMethods.InitializeSecurityContext_2(
- ref credHandle,
+ ref this.Credential.Handle.rawHandle,
ref prevContextHandle,
this.serverPrinc,
this.requestedAttribs,
diff --git a/Contexts/ContextNativeMethods.cs b/Contexts/ContextNativeMethods.cs
index bf9bb93..9b5b86d 100644
--- a/Contexts/ContextNativeMethods.cs
+++ b/Contexts/ContextNativeMethods.cs
@@ -31,7 +31,7 @@ namespace NSspi.Contexts
SetLastError = true
)]
public static extern SecurityStatus AcceptSecurityContext_1(
- ref long credHandle,
+ ref RawSspiHandle credHandle,
IntPtr oldContextHandle,
IntPtr inputBuffer,
ContextAttrib requestedAttribs,
@@ -51,7 +51,7 @@ namespace NSspi.Contexts
SetLastError = true
)]
public static extern SecurityStatus AcceptSecurityContext_2(
- ref long credHandle,
+ ref RawSspiHandle credHandle,
ref long oldContextHandle,
IntPtr inputBuffer,
ContextAttrib requestedAttribs,
@@ -104,7 +104,7 @@ namespace NSspi.Contexts
SetLastError = true
)]
public static extern SecurityStatus InitializeSecurityContext_1(
- ref long credentialHandle,
+ ref RawSspiHandle credentialHandle,
IntPtr zero,
string serverPrincipleName,
ContextAttrib requiredAttribs,
@@ -126,7 +126,7 @@ namespace NSspi.Contexts
SetLastError = true
)]
public static extern SecurityStatus InitializeSecurityContext_2(
- ref long credentialHandle,
+ ref RawSspiHandle credentialHandle,
ref long previousHandle,
string serverPrincipleName,
ContextAttrib requiredAttribs,
diff --git a/Contexts/ServerContext.cs b/Contexts/ServerContext.cs
index e3108c9..3cf0847 100644
--- a/Contexts/ServerContext.cs
+++ b/Contexts/ServerContext.cs
@@ -24,7 +24,6 @@ namespace NSspi.Contexts
SecureBuffer clientBuffer = new SecureBuffer( clientToken, BufferType.Token );
SecureBuffer outBuffer = new SecureBuffer( new byte[12288], BufferType.Token );
- long credHandle = this.Credential.CredentialHandle;
long oldContextHandle = base.ContextHandle;
long newContextHandle = 0;
@@ -42,7 +41,7 @@ namespace NSspi.Contexts
if ( oldContextHandle == 0 )
{
status = ContextNativeMethods.AcceptSecurityContext_1(
- ref credHandle,
+ ref this.Credential.Handle.rawHandle,
IntPtr.Zero,
clientAdapter.Handle,
requestedAttribs,
@@ -56,7 +55,7 @@ namespace NSspi.Contexts
else
{
status = ContextNativeMethods.AcceptSecurityContext_2(
- ref credHandle,
+ ref this.Credential.Handle.rawHandle,
ref oldContextHandle,
clientAdapter.Handle,
requestedAttribs,
diff --git a/Credentials/Credential.cs b/Credentials/Credential.cs
index eb3e042..67f847b 100644
--- a/Credentials/Credential.cs
+++ b/Credentials/Credential.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.DirectoryServices.AccountManagement;
using System.Linq;
+using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
@@ -14,7 +15,7 @@ namespace NSspi
private SecurityPackage securityPackage;
- private long credHandle;
+ private SafeCredentialHandle safeCredHandle;
private long expiry;
public Credential(SecurityPackage package, CredentialType credentialType)
@@ -22,7 +23,6 @@ namespace NSspi
this.disposed = false;
this.securityPackage = package;
- this.credHandle = 0;
this.expiry = 0;
Init( package, credentialType );
@@ -66,17 +66,30 @@ namespace NSspi
}
// -- Invoke --
- SecurityStatus status = NativeMethods.AcquireCredentialsHandle(
- null,
- packageName,
- use,
- IntPtr.Zero,
- IntPtr.Zero,
- IntPtr.Zero,
- IntPtr.Zero,
- ref this.credHandle,
- ref this.expiry
- );
+
+ 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,
+ packageName,
+ use,
+ IntPtr.Zero,
+ IntPtr.Zero,
+ IntPtr.Zero,
+ IntPtr.Zero,
+ ref this.safeCredHandle.rawHandle,
+ ref this.expiry
+ );
+ }
if ( status != SecurityStatus.OK )
{
@@ -112,7 +125,7 @@ namespace NSspi
string name = null;
status = NativeMethods.QueryCredentialsAttribute_Name(
- ref this.credHandle,
+ ref this.safeCredHandle.rawHandle,
CredentialQueryAttrib.Names,
ref carrier
);
@@ -131,11 +144,11 @@ namespace NSspi
}
}
- public long CredentialHandle
+ public SafeCredentialHandle Handle
{
get
{
- return this.credHandle;
+ return this.safeCredHandle;
}
}
@@ -149,16 +162,12 @@ namespace NSspi
{
if ( this.disposed == false )
{
- SecurityStatus result;
-
- result = NativeMethods.FreeCredentialsHandle( ref this.credHandle );
+ if ( disposing )
+ {
+ this.safeCredHandle.Dispose();
+ }
this.disposed = true;
-
- if ( disposing && result != SecurityStatus.OK )
- {
- throw new SSPIException( "Failed to release credentials handle", result );
- }
}
}
}
diff --git a/NSspi.csproj b/NSspi.csproj
index a089124..ffb953d 100644
--- a/NSspi.csproj
+++ b/NSspi.csproj
@@ -72,6 +72,7 @@
+
diff --git a/NativeMethods.cs b/NativeMethods.cs
index 64b7f4e..438bb21 100644
--- a/NativeMethods.cs
+++ b/NativeMethods.cs
@@ -58,7 +58,7 @@ namespace NSspi
IntPtr packageData,
IntPtr getKeyFunc,
IntPtr getKeyData,
- ref long credentialHandle,
+ ref RawSspiHandle credentialHandle,
ref long expiry
);
@@ -75,7 +75,7 @@ namespace NSspi
SetLastError = true
)]
public static extern SecurityStatus FreeCredentialsHandle(
- ref long credentialHandle
+ ref RawSspiHandle credentialHandle
);
/*
@@ -118,7 +118,7 @@ namespace NSspi
SetLastError = true
)]
public static extern SecurityStatus QueryCredentialsAttribute_Name(
- ref long credentialHandle,
+ ref RawSspiHandle credentialHandle,
CredentialQueryAttrib attributeName,
ref QueryNameAttribCarrier name
);
diff --git a/SspiHandle.cs b/SspiHandle.cs
new file mode 100644
index 0000000..ed5601a
--- /dev/null
+++ b/SspiHandle.cs
@@ -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
+{
+ ///
+ /// 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.
+ ///
+ ///
+ /// 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.
+ ///
+ [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;
+ }
+ }
+
+}