Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4d79f1b5db | ||
|
|
aef74fe8aa | ||
|
|
37a7881d25 | ||
|
|
9350412fb6 | ||
|
|
6a5e6056a7 | ||
|
|
c6c0ac623e | ||
|
|
c07abdaa62 | ||
|
|
f2d4541bab | ||
|
|
0eb8ff49f2 | ||
|
|
3b189d2865 | ||
|
|
6ff68d8812 | ||
|
|
e631d77f01 | ||
|
|
4e629a71b2 | ||
|
|
8db4b6d8a5 |
@@ -1,6 +1,8 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 2012
|
# Visual Studio 14
|
||||||
|
VisualStudioVersion = 14.0.25420.1
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestClient", "TestClient\TestClient.csproj", "{E93FBF1A-5198-44D6-BDF0-880D17F2B81A}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestClient", "TestClient\TestClient.csproj", "{E93FBF1A-5198-44D6-BDF0-880D17F2B81A}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestProtocol", "TestProtocol\TestProtocol.csproj", "{9BFD94E1-D9FB-44D7-A6E7-8BAC2620E535}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestProtocol", "TestProtocol\TestProtocol.csproj", "{9BFD94E1-D9FB-44D7-A6E7-8BAC2620E535}"
|
||||||
|
|||||||
@@ -1,9 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi
|
namespace NSspi
|
||||||
{
|
{
|
||||||
@@ -37,8 +32,7 @@ namespace NSspi
|
|||||||
buffer[position + 0] = (byte)( value >> 24 );
|
buffer[position + 0] = (byte)( value >> 24 );
|
||||||
buffer[position + 1] = (byte)( value >> 16 );
|
buffer[position + 1] = (byte)( value >> 16 );
|
||||||
buffer[position + 2] = (byte)( value >> 8 );
|
buffer[position + 2] = (byte)( value >> 8 );
|
||||||
buffer[position + 3] = (byte)( value);
|
buffer[position + 3] = (byte)( value );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,9 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using NSspi.Buffers;
|
using NSspi.Buffers;
|
||||||
using NSspi.Credentials;
|
using NSspi.Credentials;
|
||||||
|
|
||||||
@@ -33,7 +28,7 @@ namespace NSspi.Contexts
|
|||||||
/// <param name="requestedAttribs">Requested attributes that describe the desired properties of the
|
/// <param name="requestedAttribs">Requested attributes that describe the desired properties of the
|
||||||
/// context once it is established. If a context cannot be established that satisfies the indicated
|
/// context once it is established. If a context cannot be established that satisfies the indicated
|
||||||
/// properties, the context initialization is aborted.</param>
|
/// properties, the context initialization is aborted.</param>
|
||||||
public ClientContext( ClientCredential cred, string serverPrinc, ContextAttrib requestedAttribs )
|
public ClientContext( Credential cred, string serverPrinc, ContextAttrib requestedAttribs )
|
||||||
: base( cred )
|
: base( cred )
|
||||||
{
|
{
|
||||||
this.serverPrinc = serverPrinc;
|
this.serverPrinc = serverPrinc;
|
||||||
@@ -90,12 +85,12 @@ namespace NSspi.Contexts
|
|||||||
// The security package tells us how big its biggest token will be. We'll allocate a buffer
|
// The security package tells us how big its biggest token will be. We'll allocate a buffer
|
||||||
// that size, and it'll tell us how much it used.
|
// that size, and it'll tell us how much it used.
|
||||||
outTokenBuffer = new SecureBuffer(
|
outTokenBuffer = new SecureBuffer(
|
||||||
new byte[ this.Credential.PackageInfo.MaxTokenLength ],
|
new byte[this.Credential.PackageInfo.MaxTokenLength],
|
||||||
BufferType.Token
|
BufferType.Token
|
||||||
);
|
);
|
||||||
|
|
||||||
serverBuffer = null;
|
serverBuffer = null;
|
||||||
if ( serverToken != null )
|
if( serverToken != null )
|
||||||
{
|
{
|
||||||
serverBuffer = new SecureBuffer( serverToken, BufferType.Token );
|
serverBuffer = new SecureBuffer( serverToken, BufferType.Token );
|
||||||
}
|
}
|
||||||
@@ -115,9 +110,9 @@ namespace NSspi.Contexts
|
|||||||
// Windows, 128 bits on 64-bit Windows.
|
// Windows, 128 bits on 64-bit Windows.
|
||||||
// - So in the end, on a 64-bit machine, we're passing a 64-bit value (the pointer to the struct) that
|
// - So in the end, on a 64-bit machine, we're passing a 64-bit value (the pointer to the struct) that
|
||||||
// points to 128 bits of memory (the struct itself) for where to write the handle numbers.
|
// points to 128 bits of memory (the struct itself) for where to write the handle numbers.
|
||||||
using ( outAdapter = new SecureBufferAdapter( outTokenBuffer ) )
|
using( outAdapter = new SecureBufferAdapter( outTokenBuffer ) )
|
||||||
{
|
{
|
||||||
if ( this.ContextHandle.IsInvalid )
|
if( this.ContextHandle.IsInvalid )
|
||||||
{
|
{
|
||||||
status = ContextNativeMethods.InitializeSecurityContext_1(
|
status = ContextNativeMethods.InitializeSecurityContext_1(
|
||||||
ref this.Credential.Handle.rawHandle,
|
ref this.Credential.Handle.rawHandle,
|
||||||
@@ -136,7 +131,7 @@ namespace NSspi.Contexts
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
using ( serverAdapter = new SecureBufferAdapter( serverBuffer ) )
|
using( serverAdapter = new SecureBufferAdapter( serverBuffer ) )
|
||||||
{
|
{
|
||||||
status = ContextNativeMethods.InitializeSecurityContext_2(
|
status = ContextNativeMethods.InitializeSecurityContext_2(
|
||||||
ref this.Credential.Handle.rawHandle,
|
ref this.Credential.Handle.rawHandle,
|
||||||
|
|||||||
@@ -1,12 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using NSspi.Buffers;
|
using NSspi.Buffers;
|
||||||
using NSspi.Contexts;
|
|
||||||
using NSspi.Credentials;
|
using NSspi.Credentials;
|
||||||
|
|
||||||
namespace NSspi.Contexts
|
namespace NSspi.Contexts
|
||||||
@@ -257,7 +252,7 @@ namespace NSspi.Contexts
|
|||||||
paddingLength = ByteWriter.ReadInt16_BE( input, position );
|
paddingLength = ByteWriter.ReadInt16_BE( input, position );
|
||||||
position += 2;
|
position += 2;
|
||||||
|
|
||||||
if ( trailerLength + dataLength + paddingLength + 2 + 4 + 2 > input.Length )
|
if( trailerLength + dataLength + paddingLength + 2 + 4 + 2 > input.Length )
|
||||||
{
|
{
|
||||||
throw new ArgumentException( "The buffer contains invalid data - the embedded length data does not add up." );
|
throw new ArgumentException( "The buffer contains invalid data - the embedded length data does not add up." );
|
||||||
}
|
}
|
||||||
@@ -296,8 +291,7 @@ namespace NSspi.Contexts
|
|||||||
}
|
}
|
||||||
// else there was no padding.
|
// else there was no padding.
|
||||||
|
|
||||||
|
using( adapter = new SecureBufferAdapter( new[] { trailerBuffer, dataBuffer, paddingBuffer } ) )
|
||||||
using( adapter = new SecureBufferAdapter( new [] { trailerBuffer, dataBuffer, paddingBuffer } ) )
|
|
||||||
{
|
{
|
||||||
status = ContextNativeMethods.SafeDecryptMessage(
|
status = ContextNativeMethods.SafeDecryptMessage(
|
||||||
this.ContextHandle,
|
this.ContextHandle,
|
||||||
@@ -348,7 +342,7 @@ namespace NSspi.Contexts
|
|||||||
|
|
||||||
Array.Copy( message, dataBuffer.Buffer, message.Length );
|
Array.Copy( message, dataBuffer.Buffer, message.Length );
|
||||||
|
|
||||||
using ( adapter = new SecureBufferAdapter( new[] { dataBuffer, signatureBuffer } ) )
|
using( adapter = new SecureBufferAdapter( new[] { dataBuffer, signatureBuffer } ) )
|
||||||
{
|
{
|
||||||
status = ContextNativeMethods.SafeMakeSignature(
|
status = ContextNativeMethods.SafeMakeSignature(
|
||||||
this.ContextHandle,
|
this.ContextHandle,
|
||||||
@@ -358,7 +352,7 @@ namespace NSspi.Contexts
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( status != SecurityStatus.OK )
|
if( status != SecurityStatus.OK )
|
||||||
{
|
{
|
||||||
throw new SSPIException( "Failed to create message signature.", status );
|
throw new SSPIException( "Failed to create message signature.", status );
|
||||||
}
|
}
|
||||||
@@ -389,6 +383,35 @@ namespace NSspi.Contexts
|
|||||||
return outMessage;
|
return outMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the Session Key from a context or null on failure.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Session keys are sometimes needed for other purposes or HMAC functions. This function
|
||||||
|
/// will run QueryAttribute to get the session key struct, and read and return the key from
|
||||||
|
/// that struct.
|
||||||
|
/// </remarks>
|
||||||
|
/// <returns>byte[] with the session key data or null on failure</returns>
|
||||||
|
public byte[] QuerySessionKey()
|
||||||
|
{
|
||||||
|
SecurityStatus status;
|
||||||
|
|
||||||
|
byte[] SessionKey = null;
|
||||||
|
|
||||||
|
status = ContextNativeMethods.SafeQueryContextAttribute(
|
||||||
|
this.ContextHandle,
|
||||||
|
ContextQueryAttrib.SessionKey,
|
||||||
|
ref SessionKey
|
||||||
|
);
|
||||||
|
|
||||||
|
if( status != SecurityStatus.OK )
|
||||||
|
{
|
||||||
|
throw new SSPIException( "Failed to query session key.", status );
|
||||||
|
}
|
||||||
|
|
||||||
|
return SessionKey;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Verifies the signature of a signed message
|
/// Verifies the signature of a signed message
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -415,7 +438,7 @@ namespace NSspi.Contexts
|
|||||||
|
|
||||||
sizes = QueryBufferSizes();
|
sizes = QueryBufferSizes();
|
||||||
|
|
||||||
if ( signedMessage.Length < 2 + 4 + sizes.MaxSignature )
|
if( signedMessage.Length < 2 + 4 + sizes.MaxSignature )
|
||||||
{
|
{
|
||||||
throw new ArgumentException( "Input message is too small to possibly fit a valid message" );
|
throw new ArgumentException( "Input message is too small to possibly fit a valid message" );
|
||||||
}
|
}
|
||||||
@@ -430,7 +453,7 @@ namespace NSspi.Contexts
|
|||||||
sigLen = ByteWriter.ReadInt16_BE( signedMessage, position );
|
sigLen = ByteWriter.ReadInt16_BE( signedMessage, position );
|
||||||
position += 2;
|
position += 2;
|
||||||
|
|
||||||
if ( messageLen + sigLen + 2 + 4 > signedMessage.Length )
|
if( messageLen + sigLen + 2 + 4 > signedMessage.Length )
|
||||||
{
|
{
|
||||||
throw new ArgumentException( "The buffer contains invalid data - the embedded length data does not add up." );
|
throw new ArgumentException( "The buffer contains invalid data - the embedded length data does not add up." );
|
||||||
}
|
}
|
||||||
@@ -443,7 +466,7 @@ namespace NSspi.Contexts
|
|||||||
Array.Copy( signedMessage, position, signatureBuffer.Buffer, 0, sigLen );
|
Array.Copy( signedMessage, position, signatureBuffer.Buffer, 0, sigLen );
|
||||||
position += sigLen;
|
position += sigLen;
|
||||||
|
|
||||||
using ( adapter = new SecureBufferAdapter( new[] { dataBuffer, signatureBuffer } ) )
|
using( adapter = new SecureBufferAdapter( new[] { dataBuffer, signatureBuffer } ) )
|
||||||
{
|
{
|
||||||
status = ContextNativeMethods.SafeVerifySignature(
|
status = ContextNativeMethods.SafeVerifySignature(
|
||||||
this.ContextHandle,
|
this.ContextHandle,
|
||||||
@@ -453,12 +476,12 @@ namespace NSspi.Contexts
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( status == SecurityStatus.OK )
|
if( status == SecurityStatus.OK )
|
||||||
{
|
{
|
||||||
origMessage = dataBuffer.Buffer;
|
origMessage = dataBuffer.Buffer;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if ( status == SecurityStatus.MessageAltered ||
|
else if( status == SecurityStatus.MessageAltered ||
|
||||||
status == SecurityStatus.OutOfSequence )
|
status == SecurityStatus.OutOfSequence )
|
||||||
{
|
{
|
||||||
origMessage = null;
|
origMessage = null;
|
||||||
@@ -485,9 +508,9 @@ namespace NSspi.Contexts
|
|||||||
{
|
{
|
||||||
this.ContextHandle.DangerousAddRef( ref gotRef );
|
this.ContextHandle.DangerousAddRef( ref gotRef );
|
||||||
}
|
}
|
||||||
catch ( Exception )
|
catch( Exception )
|
||||||
{
|
{
|
||||||
if ( gotRef )
|
if( gotRef )
|
||||||
{
|
{
|
||||||
this.ContextHandle.DangerousRelease();
|
this.ContextHandle.DangerousRelease();
|
||||||
gotRef = false;
|
gotRef = false;
|
||||||
@@ -497,7 +520,7 @@ namespace NSspi.Contexts
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
if ( gotRef )
|
if( gotRef )
|
||||||
{
|
{
|
||||||
status = ContextNativeMethods.QueryContextAttributes_Sizes(
|
status = ContextNativeMethods.QueryContextAttributes_Sizes(
|
||||||
ref this.ContextHandle.rawHandle,
|
ref this.ContextHandle.rawHandle,
|
||||||
@@ -521,7 +544,7 @@ namespace NSspi.Contexts
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="attrib">The string-valued attribute to query.</param>
|
/// <param name="attrib">The string-valued attribute to query.</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private string QueryContextString(ContextQueryAttrib attrib)
|
private string QueryContextString( ContextQueryAttrib attrib )
|
||||||
{
|
{
|
||||||
SecPkgContext_String stringAttrib;
|
SecPkgContext_String stringAttrib;
|
||||||
SecurityStatus status = SecurityStatus.InternalError;
|
SecurityStatus status = SecurityStatus.InternalError;
|
||||||
@@ -540,9 +563,9 @@ namespace NSspi.Contexts
|
|||||||
{
|
{
|
||||||
this.ContextHandle.DangerousAddRef( ref gotRef );
|
this.ContextHandle.DangerousAddRef( ref gotRef );
|
||||||
}
|
}
|
||||||
catch ( Exception )
|
catch( Exception )
|
||||||
{
|
{
|
||||||
if ( gotRef )
|
if( gotRef )
|
||||||
{
|
{
|
||||||
this.ContextHandle.DangerousRelease();
|
this.ContextHandle.DangerousRelease();
|
||||||
gotRef = false;
|
gotRef = false;
|
||||||
@@ -551,7 +574,7 @@ namespace NSspi.Contexts
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
if ( gotRef )
|
if( gotRef )
|
||||||
{
|
{
|
||||||
status = ContextNativeMethods.QueryContextAttributes_String(
|
status = ContextNativeMethods.QueryContextAttributes_String(
|
||||||
ref this.ContextHandle.rawHandle,
|
ref this.ContextHandle.rawHandle,
|
||||||
@@ -561,7 +584,7 @@ namespace NSspi.Contexts
|
|||||||
|
|
||||||
this.ContextHandle.DangerousRelease();
|
this.ContextHandle.DangerousRelease();
|
||||||
|
|
||||||
if ( status == SecurityStatus.OK )
|
if( status == SecurityStatus.OK )
|
||||||
{
|
{
|
||||||
result = Marshal.PtrToStringUni( stringAttrib.StringResult );
|
result = Marshal.PtrToStringUni( stringAttrib.StringResult );
|
||||||
ContextNativeMethods.FreeContextBuffer( stringAttrib.StringResult );
|
ContextNativeMethods.FreeContextBuffer( stringAttrib.StringResult );
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi.Contexts
|
namespace NSspi.Contexts
|
||||||
{
|
{
|
||||||
@@ -36,7 +32,6 @@ namespace NSspi.Contexts
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
MutualAuth = 0x00000002,
|
MutualAuth = 0x00000002,
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Detect replayed messages that have been encoded by using the EncryptMessage or MakeSignature
|
/// Detect replayed messages that have been encoded by using the EncryptMessage or MakeSignature
|
||||||
/// message support functionality.
|
/// message support functionality.
|
||||||
|
|||||||
@@ -1,13 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.ConstrainedExecution;
|
using System.Runtime.ConstrainedExecution;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using NSspi.Buffers;
|
using NSspi.Buffers;
|
||||||
using NSspi.Contexts;
|
|
||||||
|
|
||||||
namespace NSspi.Contexts
|
namespace NSspi.Contexts
|
||||||
{
|
{
|
||||||
@@ -45,7 +40,7 @@ namespace NSspi.Contexts
|
|||||||
);
|
);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
[DllImport( "Secur32.dll", EntryPoint = "AcceptSecurityContext",CharSet = CharSet.Unicode )]
|
[DllImport( "Secur32.dll", EntryPoint = "AcceptSecurityContext", CharSet = CharSet.Unicode )]
|
||||||
internal static extern SecurityStatus AcceptSecurityContext_1(
|
internal static extern SecurityStatus AcceptSecurityContext_1(
|
||||||
ref RawSspiHandle credHandle,
|
ref RawSspiHandle credHandle,
|
||||||
IntPtr oldContextHandle,
|
IntPtr oldContextHandle,
|
||||||
@@ -58,7 +53,6 @@ namespace NSspi.Contexts
|
|||||||
ref TimeStamp expiry
|
ref TimeStamp expiry
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
[DllImport( "Secur32.dll", EntryPoint = "AcceptSecurityContext", CharSet = CharSet.Unicode )]
|
[DllImport( "Secur32.dll", EntryPoint = "AcceptSecurityContext", CharSet = CharSet.Unicode )]
|
||||||
internal static extern SecurityStatus AcceptSecurityContext_2(
|
internal static extern SecurityStatus AcceptSecurityContext_2(
|
||||||
ref RawSspiHandle credHandle,
|
ref RawSspiHandle credHandle,
|
||||||
@@ -72,7 +66,6 @@ namespace NSspi.Contexts
|
|||||||
ref TimeStamp expiry
|
ref TimeStamp expiry
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
[DllImport( "Secur32.dll", EntryPoint = "InitializeSecurityContext", CharSet = CharSet.Unicode )]
|
[DllImport( "Secur32.dll", EntryPoint = "InitializeSecurityContext", CharSet = CharSet.Unicode )]
|
||||||
internal static extern SecurityStatus InitializeSecurityContext_1(
|
internal static extern SecurityStatus InitializeSecurityContext_1(
|
||||||
ref RawSspiHandle credentialHandle,
|
ref RawSspiHandle credentialHandle,
|
||||||
@@ -89,7 +82,6 @@ namespace NSspi.Contexts
|
|||||||
ref TimeStamp expiry
|
ref TimeStamp expiry
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
[DllImport( "Secur32.dll", EntryPoint = "InitializeSecurityContext", CharSet = CharSet.Unicode )]
|
[DllImport( "Secur32.dll", EntryPoint = "InitializeSecurityContext", CharSet = CharSet.Unicode )]
|
||||||
internal static extern SecurityStatus InitializeSecurityContext_2(
|
internal static extern SecurityStatus InitializeSecurityContext_2(
|
||||||
ref RawSspiHandle credentialHandle,
|
ref RawSspiHandle credentialHandle,
|
||||||
@@ -106,12 +98,11 @@ namespace NSspi.Contexts
|
|||||||
ref TimeStamp expiry
|
ref TimeStamp expiry
|
||||||
);
|
);
|
||||||
|
|
||||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success )]
|
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
||||||
[DllImport( "Secur32.dll", EntryPoint = "DeleteSecurityContext", CharSet = CharSet.Unicode )]
|
[DllImport( "Secur32.dll", EntryPoint = "DeleteSecurityContext", CharSet = CharSet.Unicode )]
|
||||||
internal static extern SecurityStatus DeleteSecurityContext( ref RawSspiHandle contextHandle );
|
internal static extern SecurityStatus DeleteSecurityContext( ref RawSspiHandle contextHandle );
|
||||||
|
|
||||||
|
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.MayFail )]
|
||||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail )]
|
|
||||||
[DllImport( "Secur32.dll", EntryPoint = "EncryptMessage", CharSet = CharSet.Unicode )]
|
[DllImport( "Secur32.dll", EntryPoint = "EncryptMessage", CharSet = CharSet.Unicode )]
|
||||||
internal static extern SecurityStatus EncryptMessage(
|
internal static extern SecurityStatus EncryptMessage(
|
||||||
ref RawSspiHandle contextHandle,
|
ref RawSspiHandle contextHandle,
|
||||||
@@ -155,7 +146,7 @@ namespace NSspi.Contexts
|
|||||||
ref SecPkgContext_Sizes sizes
|
ref SecPkgContext_Sizes sizes
|
||||||
);
|
);
|
||||||
|
|
||||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success)]
|
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
||||||
[DllImport( "Secur32.dll", EntryPoint = "QueryContextAttributes", CharSet = CharSet.Unicode )]
|
[DllImport( "Secur32.dll", EntryPoint = "QueryContextAttributes", CharSet = CharSet.Unicode )]
|
||||||
internal static extern SecurityStatus QueryContextAttributes_String(
|
internal static extern SecurityStatus QueryContextAttributes_String(
|
||||||
ref RawSspiHandle contextHandle,
|
ref RawSspiHandle contextHandle,
|
||||||
@@ -163,11 +154,18 @@ namespace NSspi.Contexts
|
|||||||
ref SecPkgContext_String names
|
ref SecPkgContext_String names
|
||||||
);
|
);
|
||||||
|
|
||||||
|
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
||||||
|
[DllImport( "Secur32.dll", EntryPoint = "QueryContextAttributes", CharSet = CharSet.Unicode )]
|
||||||
|
internal static extern SecurityStatus QueryContextAttributes(
|
||||||
|
ref RawSspiHandle contextHandle,
|
||||||
|
ContextQueryAttrib attrib,
|
||||||
|
IntPtr attribute
|
||||||
|
);
|
||||||
|
|
||||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
||||||
[DllImport( "Secur32.dll", EntryPoint = "FreeContextBuffer", CharSet = CharSet.Unicode )]
|
[DllImport( "Secur32.dll", EntryPoint = "FreeContextBuffer", CharSet = CharSet.Unicode )]
|
||||||
internal static extern SecurityStatus FreeContextBuffer( IntPtr handle );
|
internal static extern SecurityStatus FreeContextBuffer( IntPtr handle );
|
||||||
|
|
||||||
|
|
||||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
||||||
[DllImport( "Secur32.dll", EntryPoint = "ImpersonateSecurityContext", CharSet = CharSet.Unicode )]
|
[DllImport( "Secur32.dll", EntryPoint = "ImpersonateSecurityContext", CharSet = CharSet.Unicode )]
|
||||||
internal static extern SecurityStatus ImpersonateSecurityContext( ref RawSspiHandle contextHandle );
|
internal static extern SecurityStatus ImpersonateSecurityContext( ref RawSspiHandle contextHandle );
|
||||||
@@ -176,6 +174,72 @@ namespace NSspi.Contexts
|
|||||||
[DllImport( "Secur32.dll", EntryPoint = "RevertSecurityContext", CharSet = CharSet.Unicode )]
|
[DllImport( "Secur32.dll", EntryPoint = "RevertSecurityContext", CharSet = CharSet.Unicode )]
|
||||||
internal static extern SecurityStatus RevertSecurityContext( ref RawSspiHandle contextHandle );
|
internal static extern SecurityStatus RevertSecurityContext( ref RawSspiHandle contextHandle );
|
||||||
|
|
||||||
|
[StructLayout( LayoutKind.Sequential )]
|
||||||
|
private class KeyStruct
|
||||||
|
{
|
||||||
|
public int size;
|
||||||
|
public IntPtr data;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static SecurityStatus SafeQueryContextAttribute(
|
||||||
|
SafeContextHandle handle,
|
||||||
|
ContextQueryAttrib attribute,
|
||||||
|
ref byte[] buffer
|
||||||
|
)
|
||||||
|
{
|
||||||
|
bool gotRef = false;
|
||||||
|
|
||||||
|
SecurityStatus status = SecurityStatus.InternalError;
|
||||||
|
RuntimeHelpers.PrepareConstrainedRegions();
|
||||||
|
|
||||||
|
int pointerSize = System.Environment.Is64BitOperatingSystem ? 8 : 4; //NOTE: update this when 128 bit processors exist
|
||||||
|
IntPtr alloc_buffer = Marshal.AllocHGlobal( sizeof( uint ) + pointerSize ); //NOTE: this is at most 4 + sizeof(void*) bytes
|
||||||
|
//see struct SecPkgContext_SessionKey
|
||||||
|
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa380096(v=vs.85).aspx
|
||||||
|
try
|
||||||
|
{
|
||||||
|
handle.DangerousAddRef( ref gotRef );
|
||||||
|
}
|
||||||
|
catch( Exception )
|
||||||
|
{
|
||||||
|
if( gotRef )
|
||||||
|
{
|
||||||
|
handle.DangerousRelease();
|
||||||
|
gotRef = false;
|
||||||
|
buffer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if( gotRef )
|
||||||
|
{
|
||||||
|
status = ContextNativeMethods.QueryContextAttributes(
|
||||||
|
ref handle.rawHandle,
|
||||||
|
attribute,
|
||||||
|
alloc_buffer
|
||||||
|
);
|
||||||
|
if( status == SecurityStatus.OK )
|
||||||
|
{
|
||||||
|
KeyStruct key = new KeyStruct();
|
||||||
|
|
||||||
|
Marshal.PtrToStructure( alloc_buffer, key ); // fit to the proper size, read a byte[]
|
||||||
|
|
||||||
|
byte[] sizedBuffer = new byte[key.size];
|
||||||
|
|
||||||
|
for( int i = 0; i < key.size; i++ )
|
||||||
|
sizedBuffer[i] = Marshal.ReadByte( key.data, i );
|
||||||
|
|
||||||
|
buffer = sizedBuffer;
|
||||||
|
}
|
||||||
|
handle.DangerousRelease();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Marshal.FreeHGlobal( alloc_buffer );
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Safely invokes the native EncryptMessage function, making sure that handle ref counting is
|
/// Safely invokes the native EncryptMessage function, making sure that handle ref counting is
|
||||||
/// performed in a proper CER.
|
/// performed in a proper CER.
|
||||||
@@ -199,9 +263,9 @@ namespace NSspi.Contexts
|
|||||||
{
|
{
|
||||||
handle.DangerousAddRef( ref gotRef );
|
handle.DangerousAddRef( ref gotRef );
|
||||||
}
|
}
|
||||||
catch ( Exception )
|
catch( Exception )
|
||||||
{
|
{
|
||||||
if ( gotRef )
|
if( gotRef )
|
||||||
{
|
{
|
||||||
handle.DangerousRelease();
|
handle.DangerousRelease();
|
||||||
gotRef = false;
|
gotRef = false;
|
||||||
@@ -211,7 +275,7 @@ namespace NSspi.Contexts
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
if ( gotRef )
|
if( gotRef )
|
||||||
{
|
{
|
||||||
status = ContextNativeMethods.EncryptMessage(
|
status = ContextNativeMethods.EncryptMessage(
|
||||||
ref handle.rawHandle,
|
ref handle.rawHandle,
|
||||||
@@ -301,9 +365,9 @@ namespace NSspi.Contexts
|
|||||||
{
|
{
|
||||||
handle.DangerousAddRef( ref gotRef );
|
handle.DangerousAddRef( ref gotRef );
|
||||||
}
|
}
|
||||||
catch ( Exception )
|
catch( Exception )
|
||||||
{
|
{
|
||||||
if ( gotRef )
|
if( gotRef )
|
||||||
{
|
{
|
||||||
handle.DangerousRelease();
|
handle.DangerousRelease();
|
||||||
gotRef = false;
|
gotRef = false;
|
||||||
@@ -313,7 +377,7 @@ namespace NSspi.Contexts
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
if ( gotRef )
|
if( gotRef )
|
||||||
{
|
{
|
||||||
status = ContextNativeMethods.MakeSignature(
|
status = ContextNativeMethods.MakeSignature(
|
||||||
ref handle.rawHandle,
|
ref handle.rawHandle,
|
||||||
@@ -352,9 +416,9 @@ namespace NSspi.Contexts
|
|||||||
{
|
{
|
||||||
handle.DangerousAddRef( ref gotRef );
|
handle.DangerousAddRef( ref gotRef );
|
||||||
}
|
}
|
||||||
catch ( Exception )
|
catch( Exception )
|
||||||
{
|
{
|
||||||
if ( gotRef )
|
if( gotRef )
|
||||||
{
|
{
|
||||||
handle.DangerousRelease();
|
handle.DangerousRelease();
|
||||||
gotRef = false;
|
gotRef = false;
|
||||||
@@ -364,7 +428,7 @@ namespace NSspi.Contexts
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
if ( gotRef )
|
if( gotRef )
|
||||||
{
|
{
|
||||||
status = ContextNativeMethods.VerifySignature(
|
status = ContextNativeMethods.VerifySignature(
|
||||||
ref handle.rawHandle,
|
ref handle.rawHandle,
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi.Contexts
|
namespace NSspi.Contexts
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi.Contexts
|
namespace NSspi.Contexts
|
||||||
{
|
{
|
||||||
@@ -36,5 +32,15 @@ namespace NSspi.Contexts
|
|||||||
/// Results for a query of this type are stored in a Win32 SecPkgContext_Authority structure.
|
/// Results for a query of this type are stored in a Win32 SecPkgContext_Authority structure.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
Authority = 6,
|
Authority = 6,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queries the context for it's neogtiated SessionKey
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Results for a query of this type are stored in a Win32 SecPkgContext_SessionKey structure
|
||||||
|
/// </remarks>
|
||||||
|
SessionKey = 9,
|
||||||
|
|
||||||
|
AccessToken = 13, //not implemented yet but this would be cool
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi.Contexts
|
namespace NSspi.Contexts
|
||||||
{
|
{
|
||||||
@@ -27,7 +23,7 @@ namespace NSspi.Contexts
|
|||||||
/// Initializes a new instance of the ImpersonationHandle. Does not perform impersonation.
|
/// Initializes a new instance of the ImpersonationHandle. Does not perform impersonation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="server">The server context that is performing impersonation.</param>
|
/// <param name="server">The server context that is performing impersonation.</param>
|
||||||
internal ImpersonationHandle(ServerContext server)
|
internal ImpersonationHandle( ServerContext server )
|
||||||
{
|
{
|
||||||
this.server = server;
|
this.server = server;
|
||||||
this.disposed = false;
|
this.disposed = false;
|
||||||
@@ -54,6 +50,5 @@ namespace NSspi.Contexts
|
|||||||
this.server.RevertImpersonate();
|
this.server.RevertImpersonate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.ConstrainedExecution;
|
using System.Runtime.ConstrainedExecution;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi.Contexts
|
namespace NSspi.Contexts
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using NSspi.Buffers;
|
using NSspi.Buffers;
|
||||||
using NSspi.Credentials;
|
using NSspi.Credentials;
|
||||||
|
|
||||||
@@ -25,7 +21,7 @@ namespace NSspi.Contexts
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="cred"></param>
|
/// <param name="cred"></param>
|
||||||
/// <param name="requestedAttribs"></param>
|
/// <param name="requestedAttribs"></param>
|
||||||
public ServerContext(ServerCredential cred, ContextAttrib requestedAttribs) : base ( cred )
|
public ServerContext( Credential cred, ContextAttrib requestedAttribs ) : base( cred )
|
||||||
{
|
{
|
||||||
this.requestedAttribs = requestedAttribs;
|
this.requestedAttribs = requestedAttribs;
|
||||||
this.finalAttribs = ContextAttrib.Zero;
|
this.finalAttribs = ContextAttrib.Zero;
|
||||||
@@ -90,13 +86,13 @@ namespace NSspi.Contexts
|
|||||||
clientBuffer = new SecureBuffer( clientToken, BufferType.Token );
|
clientBuffer = new SecureBuffer( clientToken, BufferType.Token );
|
||||||
|
|
||||||
outBuffer = new SecureBuffer(
|
outBuffer = new SecureBuffer(
|
||||||
new byte[ this.Credential.PackageInfo.MaxTokenLength ],
|
new byte[this.Credential.PackageInfo.MaxTokenLength],
|
||||||
BufferType.Token
|
BufferType.Token
|
||||||
);
|
);
|
||||||
|
|
||||||
using ( clientAdapter = new SecureBufferAdapter( clientBuffer ) )
|
using( clientAdapter = new SecureBufferAdapter( clientBuffer ) )
|
||||||
{
|
{
|
||||||
using ( outAdapter = new SecureBufferAdapter( outBuffer ) )
|
using( outAdapter = new SecureBufferAdapter( outBuffer ) )
|
||||||
{
|
{
|
||||||
if( this.ContextHandle.IsInvalid )
|
if( this.ContextHandle.IsInvalid )
|
||||||
{
|
{
|
||||||
@@ -125,19 +121,17 @@ namespace NSspi.Contexts
|
|||||||
ref this.finalAttribs,
|
ref this.finalAttribs,
|
||||||
ref rawExpiry
|
ref rawExpiry
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( status == SecurityStatus.OK )
|
if( status == SecurityStatus.OK )
|
||||||
{
|
{
|
||||||
nextToken = null;
|
nextToken = null;
|
||||||
|
|
||||||
base.Initialize( rawExpiry.ToDateTime() );
|
base.Initialize( rawExpiry.ToDateTime() );
|
||||||
|
|
||||||
if ( outBuffer.Length != 0 )
|
if( outBuffer.Length != 0 )
|
||||||
{
|
{
|
||||||
nextToken = new byte[outBuffer.Length];
|
nextToken = new byte[outBuffer.Length];
|
||||||
Array.Copy( outBuffer.Buffer, nextToken, nextToken.Length );
|
Array.Copy( outBuffer.Buffer, nextToken, nextToken.Length );
|
||||||
@@ -147,7 +141,7 @@ namespace NSspi.Contexts
|
|||||||
nextToken = null;
|
nextToken = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ( status == SecurityStatus.ContinueNeeded )
|
else if( status == SecurityStatus.ContinueNeeded )
|
||||||
{
|
{
|
||||||
nextToken = new byte[outBuffer.Length];
|
nextToken = new byte[outBuffer.Length];
|
||||||
Array.Copy( outBuffer.Buffer, nextToken, nextToken.Length );
|
Array.Copy( outBuffer.Buffer, nextToken, nextToken.Length );
|
||||||
|
|||||||
55
NSspi/Credentials/AuthData.cs
Normal file
55
NSspi/Credentials/AuthData.cs
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace NSspi.Credentials
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides authentication data in native method calls.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Implements the 'SEC_WINNT_AUTH_IDENTITY' structure. See:
|
||||||
|
///
|
||||||
|
/// https://msdn.microsoft.com/en-us/library/windows/desktop/aa380131(v=vs.85).aspx
|
||||||
|
/// </remarks>
|
||||||
|
[StructLayout( LayoutKind.Sequential )]
|
||||||
|
internal struct NativeAuthData
|
||||||
|
{
|
||||||
|
public NativeAuthData( string domain, string username, string password, NativeAuthDataFlag flag )
|
||||||
|
{
|
||||||
|
this.Domain = domain;
|
||||||
|
this.DomainLength = domain.Length;
|
||||||
|
|
||||||
|
this.User = username;
|
||||||
|
this.UserLength = username.Length;
|
||||||
|
|
||||||
|
this.Password = password;
|
||||||
|
this.PasswordLength = password.Length;
|
||||||
|
|
||||||
|
this.Flags = flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MarshalAs( UnmanagedType.LPWStr )]
|
||||||
|
public string User;
|
||||||
|
|
||||||
|
public int UserLength;
|
||||||
|
|
||||||
|
[MarshalAs( UnmanagedType.LPWStr )]
|
||||||
|
public string Domain;
|
||||||
|
|
||||||
|
public int DomainLength;
|
||||||
|
|
||||||
|
[MarshalAs( UnmanagedType.LPWStr )]
|
||||||
|
public string Password;
|
||||||
|
|
||||||
|
public int PasswordLength;
|
||||||
|
|
||||||
|
public NativeAuthDataFlag Flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal enum NativeAuthDataFlag : int
|
||||||
|
{
|
||||||
|
Ansi = 1,
|
||||||
|
|
||||||
|
Unicode = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi.Credentials
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Represents the credentials of the user running the current process, for use as an SSPI client.
|
|
||||||
/// </summary>
|
|
||||||
public class ClientCredential : CurrentCredential
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the ClientCredential class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="package">The security package to acquire the credential handle from.</param>
|
|
||||||
public ClientCredential( string package )
|
|
||||||
: base( package, CredentialUse.Outbound )
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
20
NSspi/Credentials/ClientCurrentCredential.cs
Normal file
20
NSspi/Credentials/ClientCurrentCredential.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace NSspi.Credentials
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a handle to the credentials of the user running the current process, to be used to
|
||||||
|
/// authenticate as a client.
|
||||||
|
/// </summary>
|
||||||
|
public class ClientCurrentCredential : CurrentCredential
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the ClientCurrentCredential class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="package">The security package to acquire the credential handle from.</param>
|
||||||
|
public ClientCurrentCredential( string package )
|
||||||
|
: base( package, CredentialUse.Outbound )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.DirectoryServices.AccountManagement;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.ConstrainedExecution;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using NSspi.Credentials;
|
|
||||||
|
|
||||||
namespace NSspi.Credentials
|
namespace NSspi.Credentials
|
||||||
{
|
{
|
||||||
@@ -187,9 +180,9 @@ namespace NSspi.Credentials
|
|||||||
|
|
||||||
protected virtual void Dispose( bool disposing )
|
protected virtual void Dispose( bool disposing )
|
||||||
{
|
{
|
||||||
if ( this.disposed == false )
|
if( this.disposed == false )
|
||||||
{
|
{
|
||||||
if ( disposing )
|
if( disposing )
|
||||||
{
|
{
|
||||||
this.safeCredHandle.Dispose();
|
this.safeCredHandle.Dispose();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,12 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.ConstrainedExecution;
|
using System.Runtime.ConstrainedExecution;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using NSspi.Credentials;
|
|
||||||
|
|
||||||
namespace NSspi.Credentials
|
namespace NSspi.Credentials
|
||||||
{
|
{
|
||||||
internal static class CredentialNativeMethods
|
internal static class CredentialNativeMethods
|
||||||
{
|
{
|
||||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.MayFail)]
|
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.MayFail )]
|
||||||
[DllImport( "Secur32.dll", EntryPoint = "AcquireCredentialsHandle", CharSet = CharSet.Unicode )]
|
[DllImport( "Secur32.dll", EntryPoint = "AcquireCredentialsHandle", CharSet = CharSet.Unicode )]
|
||||||
internal static extern SecurityStatus AcquireCredentialsHandle(
|
internal static extern SecurityStatus AcquireCredentialsHandle(
|
||||||
string principleName,
|
string principleName,
|
||||||
@@ -25,13 +20,27 @@ namespace NSspi.Credentials
|
|||||||
ref TimeStamp expiry
|
ref TimeStamp expiry
|
||||||
);
|
);
|
||||||
|
|
||||||
|
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.MayFail )]
|
||||||
|
[DllImport( "Secur32.dll", EntryPoint = "AcquireCredentialsHandle", CharSet = CharSet.Unicode )]
|
||||||
|
internal static extern SecurityStatus AcquireCredentialsHandle_AuthData(
|
||||||
|
string principleName,
|
||||||
|
string packageName,
|
||||||
|
CredentialUse credentialUse,
|
||||||
|
IntPtr loginId,
|
||||||
|
ref NativeAuthData authData,
|
||||||
|
IntPtr getKeyFunc,
|
||||||
|
IntPtr getKeyData,
|
||||||
|
ref RawSspiHandle credentialHandle,
|
||||||
|
ref TimeStamp expiry
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
||||||
[DllImport( "Secur32.dll", EntryPoint = "FreeCredentialsHandle", CharSet = CharSet.Unicode )]
|
[DllImport( "Secur32.dll", EntryPoint = "FreeCredentialsHandle", CharSet = CharSet.Unicode )]
|
||||||
internal static extern SecurityStatus FreeCredentialsHandle(
|
internal static extern SecurityStatus FreeCredentialsHandle(
|
||||||
ref RawSspiHandle credentialHandle
|
ref RawSspiHandle credentialHandle
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The overload of the QueryCredentialsAttribute method that is used for querying the name attribute.
|
/// The overload of the QueryCredentialsAttribute method that is used for querying the name attribute.
|
||||||
/// In this call, it takes a void* to a structure that contains a wide char pointer. The wide character
|
/// In this call, it takes a void* to a structure that contains a wide char pointer. The wide character
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi.Credentials
|
namespace NSspi.Credentials
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi.Credentials
|
namespace NSspi.Credentials
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi.Credentials
|
namespace NSspi.Credentials
|
||||||
{
|
{
|
||||||
@@ -57,13 +53,12 @@ namespace NSspi.Credentials
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( status != SecurityStatus.OK )
|
if( status != SecurityStatus.OK )
|
||||||
{
|
{
|
||||||
throw new SSPIException( "Failed to call AcquireCredentialHandle", status );
|
throw new SSPIException( "Failed to call AcquireCredentialHandle", status );
|
||||||
}
|
}
|
||||||
|
|
||||||
this.Expiry = rawExpiry.ToDateTime();
|
this.Expiry = rawExpiry.ToDateTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
78
NSspi/Credentials/PasswordCredential.cs
Normal file
78
NSspi/Credentials/PasswordCredential.cs
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace NSspi.Credentials
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents credentials acquired by providing a username, password, and domain.
|
||||||
|
/// </summary>
|
||||||
|
public class PasswordCredential : Credential
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the PasswordCredential class.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// It is possible to acquire a valid handle to credentials that do not provide a valid
|
||||||
|
/// username-password combination. The username and password are not validation until the
|
||||||
|
/// authentication cycle begins.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="domain">The domain to authenticate to.</param>
|
||||||
|
/// <param name="username">The username of the user to authenticate as.</param>
|
||||||
|
/// <param name="password">The user's password.</param>
|
||||||
|
/// <param name="secPackage">The SSPI security package to create credentials for.</param>
|
||||||
|
/// <param name="use">
|
||||||
|
/// Specify inbound when acquiring credentials for a server; outbound for a client.
|
||||||
|
/// </param>
|
||||||
|
public PasswordCredential( string domain, string username, string password, string secPackage, CredentialUse use )
|
||||||
|
: base( secPackage )
|
||||||
|
{
|
||||||
|
NativeAuthData authData = new NativeAuthData( domain, username, password, NativeAuthDataFlag.Unicode );
|
||||||
|
|
||||||
|
Init( authData, secPackage, use );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Init( NativeAuthData authData, string secPackage, CredentialUse use )
|
||||||
|
{
|
||||||
|
string packageName;
|
||||||
|
TimeStamp rawExpiry = new TimeStamp();
|
||||||
|
SecurityStatus status = SecurityStatus.InternalError;
|
||||||
|
|
||||||
|
// -- Package --
|
||||||
|
// Copy off for the call, since this.SecurityPackage is a property.
|
||||||
|
packageName = this.SecurityPackage;
|
||||||
|
|
||||||
|
this.Handle = 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 = CredentialNativeMethods.AcquireCredentialsHandle_AuthData(
|
||||||
|
null,
|
||||||
|
packageName,
|
||||||
|
use,
|
||||||
|
IntPtr.Zero,
|
||||||
|
ref authData,
|
||||||
|
IntPtr.Zero,
|
||||||
|
IntPtr.Zero,
|
||||||
|
ref this.Handle.rawHandle,
|
||||||
|
ref rawExpiry
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( status != SecurityStatus.OK )
|
||||||
|
{
|
||||||
|
throw new SSPIException( "Failed to call AcquireCredentialHandle", status );
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Expiry = rawExpiry.ToDateTime();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi.Credentials
|
namespace NSspi.Credentials
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.ConstrainedExecution;
|
using System.Runtime.ConstrainedExecution;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi.Credentials
|
namespace NSspi.Credentials
|
||||||
{
|
{
|
||||||
@@ -28,5 +24,4 @@ namespace NSspi.Credentials
|
|||||||
return status == SecurityStatus.OK;
|
return status == SecurityStatus.OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,23 +1,19 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi.Credentials
|
namespace NSspi.Credentials
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents the credentials of the user running the current process, for use as an SSPI server.
|
/// Represents a handle to the credentials of the user running the current process, to be used to
|
||||||
|
/// authenticate as a server.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ServerCredential : CurrentCredential
|
public class ServerCurrentCredential : CurrentCredential
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the ServerCredential class, acquiring credentials from
|
/// Initializes a new instance of the ServerCredential class, acquiring credentials from
|
||||||
/// the current thread's security context.
|
/// the current thread's security context.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="package">The name of the security package to obtain credentials from.</param>
|
/// <param name="package">The name of the security package to obtain credentials from.</param>
|
||||||
public ServerCredential( string package )
|
public ServerCurrentCredential( string package )
|
||||||
: base( package, CredentialUse.Inbound )
|
: base( package, CredentialUse.Inbound )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace NSspi
|
namespace NSspi
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
|
||||||
<Prefer32Bit>false</Prefer32Bit>
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
|
<DocumentationFile>bin\Debug\NSspi.XML</DocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
<DebugType>pdbonly</DebugType>
|
<DebugType>pdbonly</DebugType>
|
||||||
@@ -54,18 +55,20 @@
|
|||||||
<Compile Include="Contexts\ContextQueryAttrib.cs" />
|
<Compile Include="Contexts\ContextQueryAttrib.cs" />
|
||||||
<Compile Include="Contexts\ImpersonationHandle.cs" />
|
<Compile Include="Contexts\ImpersonationHandle.cs" />
|
||||||
<Compile Include="Contexts\SafeContextHandle.cs" />
|
<Compile Include="Contexts\SafeContextHandle.cs" />
|
||||||
|
<Compile Include="Credentials\AuthData.cs" />
|
||||||
|
<Compile Include="Credentials\ClientCurrentCredential.cs" />
|
||||||
<Compile Include="Credentials\CurrentCredential.cs" />
|
<Compile Include="Credentials\CurrentCredential.cs" />
|
||||||
|
<Compile Include="Credentials\PasswordCredential.cs" />
|
||||||
|
<Compile Include="Credentials\ServerCurrentCredential.cs" />
|
||||||
<Compile Include="EnumMgr.cs" />
|
<Compile Include="EnumMgr.cs" />
|
||||||
<Compile Include="SecPkgInfo.cs" />
|
<Compile Include="SecPkgInfo.cs" />
|
||||||
<Compile Include="Contexts\ServerContext.cs" />
|
<Compile Include="Contexts\ServerContext.cs" />
|
||||||
<Compile Include="Credentials\ClientCredential.cs" />
|
|
||||||
<Compile Include="Credentials\Credential.cs" />
|
<Compile Include="Credentials\Credential.cs" />
|
||||||
<Compile Include="Credentials\CredentialNativeMethods.cs" />
|
<Compile Include="Credentials\CredentialNativeMethods.cs" />
|
||||||
<Compile Include="Credentials\CredentialQueryAttrib.cs" />
|
<Compile Include="Credentials\CredentialQueryAttrib.cs" />
|
||||||
<Compile Include="Credentials\CredentialUse.cs" />
|
<Compile Include="Credentials\CredentialUse.cs" />
|
||||||
<Compile Include="Credentials\QueryNameSupport.cs" />
|
<Compile Include="Credentials\QueryNameSupport.cs" />
|
||||||
<Compile Include="Credentials\SafeCredentialHandle.cs" />
|
<Compile Include="Credentials\SafeCredentialHandle.cs" />
|
||||||
<Compile Include="Credentials\ServerCredential.cs" />
|
|
||||||
<Compile Include="NativeMethods.cs" />
|
<Compile Include="NativeMethods.cs" />
|
||||||
<Compile Include="PackageSupport.cs" />
|
<Compile Include="PackageSupport.cs" />
|
||||||
<Compile Include="PackageNames.cs" />
|
<Compile Include="PackageNames.cs" />
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<package >
|
<package >
|
||||||
<metadata>
|
<metadata>
|
||||||
<id>NSspi</id>
|
<id>NSspi</id>
|
||||||
<version>0.1.3.0</version>
|
<version>0.2.0.0</version>
|
||||||
<authors>Kevin Thompson</authors>
|
<authors>Kevin Thompson</authors>
|
||||||
<owners>Kevin Thompson</owners>
|
<owners>Kevin Thompson</owners>
|
||||||
<projectUrl>https://github.com/antiduh/nsspi</projectUrl>
|
<projectUrl>https://github.com/antiduh/nsspi</projectUrl>
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
better known as Windows Integrated Authentication.
|
better known as Windows Integrated Authentication.
|
||||||
</description>
|
</description>
|
||||||
<language>C#</language>
|
<language>C#</language>
|
||||||
<releaseNotes>First release of NSspi.</releaseNotes>
|
<releaseNotes>Adds support for username/password credentials, but introduces a minor change in the interface that breaks existing code.</releaseNotes>
|
||||||
<copyright>Copyright 2017</copyright>
|
<copyright>Copyright 2017</copyright>
|
||||||
</metadata>
|
</metadata>
|
||||||
</package>
|
</package>
|
||||||
|
|||||||
@@ -1,21 +1,15 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.ConstrainedExecution;
|
using System.Runtime.ConstrainedExecution;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using NSspi.Contexts;
|
|
||||||
|
|
||||||
namespace NSspi
|
namespace NSspi
|
||||||
{
|
{
|
||||||
internal static class NativeMethods
|
internal static class NativeMethods
|
||||||
{
|
{
|
||||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success)]
|
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
||||||
[DllImport( "Secur32.dll", EntryPoint = "FreeContextBuffer", CharSet = CharSet.Unicode )]
|
[DllImport( "Secur32.dll", EntryPoint = "FreeContextBuffer", CharSet = CharSet.Unicode )]
|
||||||
internal static extern SecurityStatus FreeContextBuffer( IntPtr buffer );
|
internal static extern SecurityStatus FreeContextBuffer( IntPtr buffer );
|
||||||
|
|
||||||
|
|
||||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
||||||
[DllImport( "Secur32.dll", EntryPoint = "QuerySecurityPackageInfo", CharSet = CharSet.Unicode )]
|
[DllImport( "Secur32.dll", EntryPoint = "QuerySecurityPackageInfo", CharSet = CharSet.Unicode )]
|
||||||
internal static extern SecurityStatus QuerySecurityPackageInfo( string packageName, ref IntPtr pkgInfo );
|
internal static extern SecurityStatus QuerySecurityPackageInfo( string packageName, ref IntPtr pkgInfo );
|
||||||
@@ -23,6 +17,5 @@ namespace NSspi
|
|||||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
||||||
[DllImport( "Secur32.dll", EntryPoint = "EnumerateSecurityPackages", CharSet = CharSet.Unicode )]
|
[DllImport( "Secur32.dll", EntryPoint = "EnumerateSecurityPackages", CharSet = CharSet.Unicode )]
|
||||||
internal static extern SecurityStatus EnumerateSecurityPackages( ref int numPackages, ref IntPtr pkgInfoArry );
|
internal static extern SecurityStatus EnumerateSecurityPackages( ref int numPackages, ref IntPtr pkgInfoArry );
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi
|
namespace NSspi
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,10 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi
|
namespace NSspi
|
||||||
{
|
{
|
||||||
@@ -35,11 +31,11 @@ namespace NSspi
|
|||||||
{
|
{
|
||||||
status = NativeMethods.QuerySecurityPackageInfo( packageName, ref rawInfoPtr );
|
status = NativeMethods.QuerySecurityPackageInfo( packageName, ref rawInfoPtr );
|
||||||
|
|
||||||
if ( rawInfoPtr != IntPtr.Zero )
|
if( rawInfoPtr != IntPtr.Zero )
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if ( status == SecurityStatus.OK )
|
if( status == SecurityStatus.OK )
|
||||||
{
|
{
|
||||||
// This performs allocations as it makes room for the strings contained in the SecPkgInfo class.
|
// This performs allocations as it makes room for the strings contained in the SecPkgInfo class.
|
||||||
Marshal.PtrToStructure( rawInfoPtr, info );
|
Marshal.PtrToStructure( rawInfoPtr, info );
|
||||||
@@ -71,7 +67,7 @@ namespace NSspi
|
|||||||
IntPtr pkgArrayPtr;
|
IntPtr pkgArrayPtr;
|
||||||
IntPtr pkgPtr;
|
IntPtr pkgPtr;
|
||||||
int numPackages = 0;
|
int numPackages = 0;
|
||||||
int pkgSize = Marshal.SizeOf( typeof(SecPkgInfo) );
|
int pkgSize = Marshal.SizeOf( typeof( SecPkgInfo ) );
|
||||||
|
|
||||||
pkgArrayPtr = new IntPtr();
|
pkgArrayPtr = new IntPtr();
|
||||||
|
|
||||||
|
|||||||
@@ -1,26 +1,25 @@
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
// General Information about an assembly is controlled through the following
|
// General Information about an assembly is controlled through the following
|
||||||
// set of attributes. Change these attribute values to modify the information
|
// set of attributes. Change these attribute values to modify the information
|
||||||
// associated with an assembly.
|
// associated with an assembly.
|
||||||
[assembly: AssemblyTitle("NSspi")]
|
[assembly: AssemblyTitle( "NSspi" )]
|
||||||
[assembly: AssemblyDescription("")]
|
[assembly: AssemblyDescription( "" )]
|
||||||
[assembly: AssemblyConfiguration("")]
|
[assembly: AssemblyConfiguration( "" )]
|
||||||
[assembly: AssemblyCompany("Kevin Thompson")]
|
[assembly: AssemblyCompany( "Kevin Thompson" )]
|
||||||
[assembly: AssemblyProduct("NSspi")]
|
[assembly: AssemblyProduct( "NSspi" )]
|
||||||
[assembly: AssemblyCopyright("Copyright © Kevin Thompson 2014")]
|
[assembly: AssemblyCopyright( "Copyright © Kevin Thompson 2017" )]
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark( "" )]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture( "" )]
|
||||||
|
|
||||||
// Setting ComVisible to false makes the types in this assembly not visible
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
// to COM components. If you need to access a type in this assembly from
|
// to COM components. If you need to access a type in this assembly from
|
||||||
// COM, set the ComVisible attribute to true on that type.
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
[assembly: ComVisible(false)]
|
[assembly: ComVisible( false )]
|
||||||
|
|
||||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
[assembly: Guid("9abf710c-c646-42aa-8183-76bfa141a07b")]
|
[assembly: Guid( "9abf710c-c646-42aa-8183-76bfa141a07b" )]
|
||||||
|
|
||||||
// Version information for an assembly consists of the following four values:
|
// Version information for an assembly consists of the following four values:
|
||||||
//
|
//
|
||||||
@@ -32,5 +31,5 @@ using System.Runtime.InteropServices;
|
|||||||
// You can specify all the values or you can default the Build and Revision Numbers
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
// by using the '*' as shown below:
|
// by using the '*' as shown below:
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
[assembly: AssemblyVersion("0.1.3.0")]
|
[assembly: AssemblyVersion( "0.2.0.0" )]
|
||||||
[assembly: AssemblyFileVersion("0.1.2.0")]
|
[assembly: AssemblyFileVersion( "0.2.0.0" )]
|
||||||
@@ -1,9 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi
|
namespace NSspi
|
||||||
{
|
{
|
||||||
@@ -35,7 +31,7 @@ namespace NSspi
|
|||||||
protected SSPIException( SerializationInfo info, StreamingContext context )
|
protected SSPIException( SerializationInfo info, StreamingContext context )
|
||||||
: base( info, context )
|
: base( info, context )
|
||||||
{
|
{
|
||||||
this.message = info.GetString("message");
|
this.message = info.GetString( "message" );
|
||||||
this.errorCode = (SecurityStatus)info.GetUInt32( "errorCode" );
|
this.errorCode = (SecurityStatus)info.GetUInt32( "errorCode" );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,7 +70,7 @@ namespace NSspi
|
|||||||
"{0}. Error Code = '0x{1:X}' - \"{2}\".",
|
"{0}. Error Code = '0x{1:X}' - \"{2}\".",
|
||||||
this.message,
|
this.message,
|
||||||
this.errorCode,
|
this.errorCode,
|
||||||
EnumMgr.ToText(this.errorCode)
|
EnumMgr.ToText( this.errorCode )
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi
|
namespace NSspi
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi.Buffers
|
namespace NSspi.Buffers
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.ConstrainedExecution;
|
using System.Runtime.ConstrainedExecution;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi.Buffers
|
namespace NSspi.Buffers
|
||||||
{
|
{
|
||||||
@@ -120,7 +117,7 @@ namespace NSspi.Buffers
|
|||||||
this.bufferHandles = new GCHandle[this.buffers.Count];
|
this.bufferHandles = new GCHandle[this.buffers.Count];
|
||||||
this.bufferCarrier = new SecureBufferInternal[this.buffers.Count];
|
this.bufferCarrier = new SecureBufferInternal[this.buffers.Count];
|
||||||
|
|
||||||
for ( int i = 0; i < this.buffers.Count; i++ )
|
for( int i = 0; i < this.buffers.Count; i++ )
|
||||||
{
|
{
|
||||||
this.bufferHandles[i] = GCHandle.Alloc( this.buffers[i].Buffer, GCHandleType.Pinned );
|
this.bufferHandles[i] = GCHandle.Alloc( this.buffers[i].Buffer, GCHandleType.Pinned );
|
||||||
|
|
||||||
@@ -156,7 +153,7 @@ namespace NSspi.Buffers
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if ( this.disposed )
|
if( this.disposed )
|
||||||
{
|
{
|
||||||
throw new ObjectDisposedException( "Cannot use SecureBufferListHandle after it has been disposed" );
|
throw new ObjectDisposedException( "Cannot use SecureBufferListHandle after it has been disposed" );
|
||||||
}
|
}
|
||||||
@@ -184,9 +181,9 @@ namespace NSspi.Buffers
|
|||||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
||||||
private void Dispose( bool disposing )
|
private void Dispose( bool disposing )
|
||||||
{
|
{
|
||||||
if ( this.disposed == true ) { return; }
|
if( this.disposed == true ) { return; }
|
||||||
|
|
||||||
if ( disposing )
|
if( disposing )
|
||||||
{
|
{
|
||||||
// When this class is actually being used for its original purpose - to convey buffers
|
// When this class is actually being used for its original purpose - to convey buffers
|
||||||
// back and forth to SSPI calls - we need to copy the potentially modified structure members
|
// back and forth to SSPI calls - we need to copy the potentially modified structure members
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi.Buffers
|
namespace NSspi.Buffers
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,10 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.ConstrainedExecution;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi.Buffers
|
namespace NSspi.Buffers
|
||||||
{
|
{
|
||||||
@@ -12,7 +7,7 @@ namespace NSspi.Buffers
|
|||||||
/// Represents the native layout of the secure buffer descriptor that is provided directly
|
/// Represents the native layout of the secure buffer descriptor that is provided directly
|
||||||
/// to native API calls.
|
/// to native API calls.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[StructLayout( LayoutKind.Sequential)]
|
[StructLayout( LayoutKind.Sequential )]
|
||||||
internal struct SecureBufferDescInternal
|
internal struct SecureBufferDescInternal
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi.Buffers
|
namespace NSspi.Buffers
|
||||||
{
|
{
|
||||||
@@ -57,7 +53,7 @@ namespace NSspi.Buffers
|
|||||||
Stream = 0x0A,
|
Stream = 0x0A,
|
||||||
ChannelBindings = 0x0E,
|
ChannelBindings = 0x0E,
|
||||||
TargetHost = 0x10,
|
TargetHost = 0x10,
|
||||||
ReadOnlyFlag = unchecked( (int)0x80000000 ),
|
ReadOnlyFlag = unchecked((int)0x80000000),
|
||||||
ReadOnlyWithChecksum = 0x10000000
|
ReadOnlyWithChecksum = 0x10000000
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi
|
namespace NSspi
|
||||||
{
|
{
|
||||||
@@ -67,16 +63,16 @@ namespace NSspi
|
|||||||
Renegotiate = 0x00090321,
|
Renegotiate = 0x00090321,
|
||||||
|
|
||||||
// Errors
|
// Errors
|
||||||
[EnumString( "Not enough memory.")]
|
[EnumString( "Not enough memory." )]
|
||||||
OutOfMemory = 0x80090300,
|
OutOfMemory = 0x80090300,
|
||||||
|
|
||||||
[EnumString( "The handle provided to the API was invalid.")]
|
[EnumString( "The handle provided to the API was invalid." )]
|
||||||
InvalidHandle = 0x80090301,
|
InvalidHandle = 0x80090301,
|
||||||
|
|
||||||
[EnumString( "The attempted operation is not supported")]
|
[EnumString( "The attempted operation is not supported" )]
|
||||||
Unsupported = 0x80090302,
|
Unsupported = 0x80090302,
|
||||||
|
|
||||||
[EnumString( "The specified principle is not known in the authentication system.")]
|
[EnumString( "The specified principle is not known in the authentication system." )]
|
||||||
TargetUnknown = 0x80090303,
|
TargetUnknown = 0x80090303,
|
||||||
|
|
||||||
[EnumString( "An internal error occurred" )]
|
[EnumString( "An internal error occurred" )]
|
||||||
@@ -85,7 +81,7 @@ namespace NSspi
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// No security provider package was found with the given name.
|
/// No security provider package was found with the given name.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[EnumString( "The requested security package was not found.")]
|
[EnumString( "The requested security package was not found." )]
|
||||||
PackageNotFound = 0x80090305,
|
PackageNotFound = 0x80090305,
|
||||||
|
|
||||||
NotOwner = 0x80090306,
|
NotOwner = 0x80090306,
|
||||||
@@ -94,7 +90,7 @@ namespace NSspi
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A token was provided that contained incorrect or corrupted data.
|
/// A token was provided that contained incorrect or corrupted data.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[EnumString("The provided authentication token is invalid or corrupted.")]
|
[EnumString( "The provided authentication token is invalid or corrupted." )]
|
||||||
InvalidToken = 0x80090308,
|
InvalidToken = 0x80090308,
|
||||||
|
|
||||||
CannotPack = 0x80090309,
|
CannotPack = 0x80090309,
|
||||||
@@ -103,27 +99,26 @@ namespace NSspi
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Impersonation is not supported.
|
/// Impersonation is not supported.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[EnumString("Impersonation is not supported with the current security package.")]
|
[EnumString( "Impersonation is not supported with the current security package." )]
|
||||||
NoImpersonation = 0x8009030B,
|
NoImpersonation = 0x8009030B,
|
||||||
|
|
||||||
[EnumString("The logon was denied, perhaps because the provided credentials were incorrect.")]
|
[EnumString( "The logon was denied, perhaps because the provided credentials were incorrect." )]
|
||||||
LogonDenied = 0x8009030C,
|
LogonDenied = 0x8009030C,
|
||||||
|
|
||||||
|
[EnumString( "The credentials provided are not recognized by the selected security package." )]
|
||||||
[EnumString( "The credentials provided are not recognized by the selected security package.")]
|
|
||||||
UnknownCredentials = 0x8009030D,
|
UnknownCredentials = 0x8009030D,
|
||||||
|
|
||||||
[EnumString( "No credentials are available in the selected security package.")]
|
[EnumString( "No credentials are available in the selected security package." )]
|
||||||
NoCredentials = 0x8009030E,
|
NoCredentials = 0x8009030E,
|
||||||
|
|
||||||
[EnumString( "A message that was provided to the Decrypt or VerifySignature functions was altered " +
|
[EnumString( "A message that was provided to the Decrypt or VerifySignature functions was altered " +
|
||||||
"after it was created.")]
|
"after it was created." )]
|
||||||
MessageAltered = 0x8009030F,
|
MessageAltered = 0x8009030F,
|
||||||
|
|
||||||
[EnumString( "A message was received out of the expected order.")]
|
[EnumString( "A message was received out of the expected order." )]
|
||||||
OutOfSequence = 0x80090310,
|
OutOfSequence = 0x80090310,
|
||||||
|
|
||||||
[EnumString( "The current security package cannot contact an authenticating authority.")]
|
[EnumString( "The current security package cannot contact an authenticating authority." )]
|
||||||
NoAuthenticatingAuthority = 0x80090311,
|
NoAuthenticatingAuthority = 0x80090311,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -138,6 +133,7 @@ namespace NSspi
|
|||||||
/// type 'extra'.
|
/// type 'extra'.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
IncompleteMessage = 0x80090318,
|
IncompleteMessage = 0x80090318,
|
||||||
|
|
||||||
IncompleteCredentials = 0x80090320,
|
IncompleteCredentials = 0x80090320,
|
||||||
BufferNotEnough = 0x80090321,
|
BufferNotEnough = 0x80090321,
|
||||||
WrongPrincipal = 0x80090322,
|
WrongPrincipal = 0x80090322,
|
||||||
@@ -168,5 +164,4 @@ namespace NSspi
|
|||||||
return (uint)status > 0x80000000u;
|
return (uint)status > 0x80000000u;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.ConstrainedExecution;
|
using System.Runtime.ConstrainedExecution;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using NSspi.Contexts;
|
|
||||||
|
|
||||||
namespace NSspi
|
namespace NSspi
|
||||||
{
|
{
|
||||||
@@ -25,7 +19,7 @@ namespace NSspi
|
|||||||
/// to this handle for performing work (InitializeSecurityContext, eg) should be performed a CER
|
/// to this handle for performing work (InitializeSecurityContext, eg) should be performed a CER
|
||||||
/// that employs handle reference counting across the native API invocation.
|
/// that employs handle reference counting across the native API invocation.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[StructLayout( LayoutKind.Sequential, Pack = 1 ) ]
|
[StructLayout( LayoutKind.Sequential, Pack = 1 )]
|
||||||
internal struct RawSspiHandle
|
internal struct RawSspiHandle
|
||||||
{
|
{
|
||||||
private IntPtr lowPart;
|
private IntPtr lowPart;
|
||||||
@@ -46,7 +40,7 @@ namespace NSspi
|
|||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// This method is executed in a CER during handle release.
|
/// This method is executed in a CER during handle release.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success)]
|
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
|
||||||
public void SetInvalid()
|
public void SetInvalid()
|
||||||
{
|
{
|
||||||
this.lowPart = IntPtr.Zero;
|
this.lowPart = IntPtr.Zero;
|
||||||
|
|||||||
@@ -1,9 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace NSspi
|
namespace NSspi
|
||||||
{
|
{
|
||||||
@@ -29,13 +25,13 @@ namespace NSspi
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public DateTime ToDateTime()
|
public DateTime ToDateTime()
|
||||||
{
|
{
|
||||||
ulong test = (ulong)this.time + (ulong)(Epoch.Ticks);
|
ulong test = (ulong)this.time + (ulong)( Epoch.Ticks );
|
||||||
|
|
||||||
// Sometimes the value returned is massive, eg, 0x7fffff154e84ffff, which is a value
|
// Sometimes the value returned is massive, eg, 0x7fffff154e84ffff, which is a value
|
||||||
// somewhere in the year 30848. This would overflow DateTime, since it peaks at 31-Dec-9999.
|
// somewhere in the year 30848. This would overflow DateTime, since it peaks at 31-Dec-9999.
|
||||||
// It turns out that this value corresponds to a TimeStamp's maximum value, reduced by my local timezone
|
// It turns out that this value corresponds to a TimeStamp's maximum value, reduced by my local timezone
|
||||||
// http://stackoverflow.com/questions/24478056/
|
// http://stackoverflow.com/questions/24478056/
|
||||||
if ( test > (ulong)DateTime.MaxValue.Ticks )
|
if( test > (ulong)DateTime.MaxValue.Ticks )
|
||||||
{
|
{
|
||||||
return DateTime.MaxValue;
|
return DateTime.MaxValue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
<startup>
|
<startup>
|
||||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0" />
|
||||||
</startup>
|
</startup>
|
||||||
</configuration>
|
</configuration>
|
||||||
@@ -16,10 +16,10 @@ namespace NSspi
|
|||||||
|
|
||||||
private static void CredTest( string packageName )
|
private static void CredTest( string packageName )
|
||||||
{
|
{
|
||||||
ClientCredential clientCred = null;
|
ClientCurrentCredential clientCred = null;
|
||||||
ClientContext client = null;
|
ClientContext client = null;
|
||||||
|
|
||||||
ServerCredential serverCred = null;
|
ServerCurrentCredential serverCred = null;
|
||||||
ServerContext server = null;
|
ServerContext server = null;
|
||||||
|
|
||||||
byte[] clientToken;
|
byte[] clientToken;
|
||||||
@@ -30,8 +30,8 @@ namespace NSspi
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
clientCred = new ClientCredential( packageName );
|
clientCred = new ClientCurrentCredential( packageName );
|
||||||
serverCred = new ServerCredential( packageName );
|
serverCred = new ServerCurrentCredential( packageName );
|
||||||
|
|
||||||
Console.Out.WriteLine( clientCred.PrincipleName );
|
Console.Out.WriteLine( clientCred.PrincipleName );
|
||||||
|
|
||||||
@@ -47,7 +47,6 @@ namespace NSspi
|
|||||||
ContextAttrib.Delegate
|
ContextAttrib.Delegate
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
server = new ServerContext(
|
server = new ServerContext(
|
||||||
serverCred,
|
serverCred,
|
||||||
ContextAttrib.MutualAuth |
|
ContextAttrib.MutualAuth |
|
||||||
@@ -64,18 +63,17 @@ namespace NSspi
|
|||||||
|
|
||||||
clientStatus = client.Init( serverToken, out clientToken );
|
clientStatus = client.Init( serverToken, out clientToken );
|
||||||
|
|
||||||
while ( true )
|
while( true )
|
||||||
{
|
{
|
||||||
serverStatus = server.AcceptToken( clientToken, out serverToken );
|
serverStatus = server.AcceptToken( clientToken, out serverToken );
|
||||||
|
|
||||||
if ( serverStatus != SecurityStatus.ContinueNeeded && clientStatus != SecurityStatus.ContinueNeeded ) { break; }
|
if( serverStatus != SecurityStatus.ContinueNeeded && clientStatus != SecurityStatus.ContinueNeeded ) { break; }
|
||||||
|
|
||||||
clientStatus = client.Init( serverToken, out clientToken );
|
clientStatus = client.Init( serverToken, out clientToken );
|
||||||
|
|
||||||
if ( serverStatus != SecurityStatus.ContinueNeeded && clientStatus != SecurityStatus.ContinueNeeded ) { break; }
|
if( serverStatus != SecurityStatus.ContinueNeeded && clientStatus != SecurityStatus.ContinueNeeded ) { break; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Console.Out.WriteLine( "Server authority: " + server.AuthorityName );
|
Console.Out.WriteLine( "Server authority: " + server.AuthorityName );
|
||||||
Console.Out.WriteLine( "Server context user: " + server.ContextUserName );
|
Console.Out.WriteLine( "Server context user: " + server.ContextUserName );
|
||||||
|
|
||||||
@@ -102,7 +100,7 @@ namespace NSspi
|
|||||||
throw new Exception();
|
throw new Exception();
|
||||||
}
|
}
|
||||||
|
|
||||||
for( int i= 0; i < plainText.Length; i++ )
|
for( int i = 0; i < plainText.Length; i++ )
|
||||||
{
|
{
|
||||||
if( plainText[i] != roundTripPlaintext[i] )
|
if( plainText[i] != roundTripPlaintext[i] )
|
||||||
{
|
{
|
||||||
@@ -117,25 +115,23 @@ namespace NSspi
|
|||||||
throw new Exception();
|
throw new Exception();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
using( server.ImpersonateClient() )
|
using( server.ImpersonateClient() )
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cipherText = client.MakeSignature( plainText );
|
cipherText = client.MakeSignature( plainText );
|
||||||
|
|
||||||
bool goodSig = server.VerifySignature( cipherText, out roundTripPlaintext );
|
bool goodSig = server.VerifySignature( cipherText, out roundTripPlaintext );
|
||||||
|
|
||||||
if ( goodSig == false ||
|
if( goodSig == false ||
|
||||||
roundTripPlaintext.Length != plainText.Length )
|
roundTripPlaintext.Length != plainText.Length )
|
||||||
{
|
{
|
||||||
throw new Exception();
|
throw new Exception();
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( int i = 0; i < plainText.Length; i++ )
|
for( int i = 0; i < plainText.Length; i++ )
|
||||||
{
|
{
|
||||||
if ( plainText[i] != roundTripPlaintext[i] )
|
if( plainText[i] != roundTripPlaintext[i] )
|
||||||
{
|
{
|
||||||
throw new Exception();
|
throw new Exception();
|
||||||
}
|
}
|
||||||
@@ -145,12 +141,12 @@ namespace NSspi
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
if ( server != null )
|
if( server != null )
|
||||||
{
|
{
|
||||||
server.Dispose();
|
server.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( client != null )
|
if( client != null )
|
||||||
{
|
{
|
||||||
client.Dispose();
|
client.Dispose();
|
||||||
}
|
}
|
||||||
@@ -160,7 +156,7 @@ namespace NSspi
|
|||||||
clientCred.Dispose();
|
clientCred.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( serverCred != null )
|
if( serverCred != null )
|
||||||
{
|
{
|
||||||
serverCred.Dispose();
|
serverCred.Dispose();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
// General Information about an assembly is controlled through the following
|
// General Information about an assembly is controlled through the following
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
<startup>
|
<startup>
|
||||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0" />
|
||||||
</startup>
|
</startup>
|
||||||
</configuration>
|
</configuration>
|
||||||
@@ -1,12 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Data;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using NSspi;
|
using NSspi;
|
||||||
using NSspi.Contexts;
|
using NSspi.Contexts;
|
||||||
@@ -20,7 +14,7 @@ namespace TestClient
|
|||||||
public partial class ClientForm : Form
|
public partial class ClientForm : Form
|
||||||
{
|
{
|
||||||
private ClientContext context;
|
private ClientContext context;
|
||||||
private ClientCredential cred;
|
private ClientCurrentCredential cred;
|
||||||
|
|
||||||
private CustomConnection connection;
|
private CustomConnection connection;
|
||||||
|
|
||||||
@@ -48,7 +42,7 @@ namespace TestClient
|
|||||||
this.FormClosing += Form1_FormClosing;
|
this.FormClosing += Form1_FormClosing;
|
||||||
|
|
||||||
// --- SSPI ---
|
// --- SSPI ---
|
||||||
this.cred = new ClientCredential( PackageNames.Negotiate );
|
this.cred = new ClientCurrentCredential( PackageNames.Negotiate );
|
||||||
|
|
||||||
this.context = new ClientContext(
|
this.context = new ClientContext(
|
||||||
cred,
|
cred,
|
||||||
@@ -107,7 +101,6 @@ namespace TestClient
|
|||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,7 +109,6 @@ namespace TestClient
|
|||||||
this.connection.Stop();
|
this.connection.Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void encryptButton_Click( object sender, EventArgs e )
|
private void encryptButton_Click( object sender, EventArgs e )
|
||||||
{
|
{
|
||||||
byte[] plaintext;
|
byte[] plaintext;
|
||||||
@@ -149,7 +141,7 @@ namespace TestClient
|
|||||||
|
|
||||||
private void connection_Received( Message message )
|
private void connection_Received( Message message )
|
||||||
{
|
{
|
||||||
this.Invoke( (Action)delegate()
|
this.Invoke( (Action)delegate ()
|
||||||
{
|
{
|
||||||
if( message.Operation == ProtocolOp.ServerToken )
|
if( message.Operation == ProtocolOp.ServerToken )
|
||||||
{
|
{
|
||||||
@@ -180,7 +172,7 @@ namespace TestClient
|
|||||||
this.initializing = false;
|
this.initializing = false;
|
||||||
this.lastServerToken = null;
|
this.lastServerToken = null;
|
||||||
|
|
||||||
this.BeginInvoke( (Action)delegate()
|
this.BeginInvoke( (Action)delegate ()
|
||||||
{
|
{
|
||||||
this.context.Dispose();
|
this.context.Dispose();
|
||||||
this.context = new ClientContext(
|
this.context = new ClientContext(
|
||||||
@@ -195,7 +187,7 @@ namespace TestClient
|
|||||||
);
|
);
|
||||||
|
|
||||||
UpdateButtons();
|
UpdateButtons();
|
||||||
});
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DoInit()
|
private void DoInit()
|
||||||
|
|||||||
@@ -1,18 +1,15 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
namespace TestClient
|
namespace TestClient
|
||||||
{
|
{
|
||||||
static class Program
|
internal static class Program
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The main entry point for the application.
|
/// The main entry point for the application.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[STAThread]
|
[STAThread]
|
||||||
static void Main()
|
private static void Main()
|
||||||
{
|
{
|
||||||
Application.EnableVisualStyles();
|
Application.EnableVisualStyles();
|
||||||
Application.SetCompatibleTextRenderingDefault( false );
|
Application.SetCompatibleTextRenderingDefault( false );
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
// General Information about an assembly is controlled through the following
|
// General Information about an assembly is controlled through the following
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
<startup>
|
<startup>
|
||||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0" />
|
||||||
</startup>
|
</startup>
|
||||||
</configuration>
|
</configuration>
|
||||||
@@ -1,10 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Text;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using NSspi;
|
using NSspi;
|
||||||
|
|
||||||
@@ -33,7 +29,7 @@ namespace TestProtocol
|
|||||||
{
|
{
|
||||||
if( this.running )
|
if( this.running )
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Already running");
|
throw new InvalidOperationException( "Already running" );
|
||||||
}
|
}
|
||||||
|
|
||||||
this.socket = new Socket( AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp );
|
this.socket = new Socket( AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp );
|
||||||
@@ -65,7 +61,7 @@ namespace TestProtocol
|
|||||||
throw new InvalidOperationException( "Not connected" );
|
throw new InvalidOperationException( "Not connected" );
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] outBuffer = new byte[ message.Data.Length + 8 ];
|
byte[] outBuffer = new byte[message.Data.Length + 8];
|
||||||
int position = 0;
|
int position = 0;
|
||||||
|
|
||||||
ByteWriter.WriteInt32_BE( (int)message.Operation, outBuffer, position );
|
ByteWriter.WriteInt32_BE( (int)message.Operation, outBuffer, position );
|
||||||
@@ -124,7 +120,6 @@ namespace TestProtocol
|
|||||||
// |--4 bytes--|--4 bytes--|---N--|
|
// |--4 bytes--|--4 bytes--|---N--|
|
||||||
// Every command is a TLV - | Operation | Length | Data |
|
// Every command is a TLV - | Operation | Length | Data |
|
||||||
|
|
||||||
|
|
||||||
// Read the operation.
|
// Read the operation.
|
||||||
this.socket.Receive( readBuffer, 4, SocketFlags.None );
|
this.socket.Receive( readBuffer, 4, SocketFlags.None );
|
||||||
|
|
||||||
@@ -153,7 +148,6 @@ namespace TestProtocol
|
|||||||
remaining -= chunkLength;
|
remaining -= chunkLength;
|
||||||
position += chunkLength;
|
position += chunkLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
catch( SocketException e )
|
catch( SocketException e )
|
||||||
{
|
{
|
||||||
@@ -187,7 +181,6 @@ namespace TestProtocol
|
|||||||
catch( Exception e )
|
catch( Exception e )
|
||||||
{ }
|
{ }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -212,7 +212,6 @@ namespace TestProtocol
|
|||||||
catch( Exception )
|
catch( Exception )
|
||||||
{ }
|
{ }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
@@ -225,5 +224,4 @@ namespace TestProtocol
|
|||||||
catch { }
|
catch { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,14 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace TestProtocol
|
namespace TestProtocol
|
||||||
{
|
{
|
||||||
public class Message
|
public class Message
|
||||||
{
|
{
|
||||||
public Message(ProtocolOp op, byte[] data)
|
public Message( ProtocolOp op, byte[] data )
|
||||||
{
|
{
|
||||||
this.Operation = op;
|
this.Operation = op;
|
||||||
this.Data = data;
|
this.Data = data;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
// General Information about an assembly is controlled through the following
|
// General Information about an assembly is controlled through the following
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace TestProtocol
|
namespace TestProtocol
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
<startup>
|
<startup>
|
||||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0" />
|
||||||
</startup>
|
</startup>
|
||||||
</configuration>
|
</configuration>
|
||||||
@@ -1,18 +1,15 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
namespace TestServer
|
namespace TestServer
|
||||||
{
|
{
|
||||||
static class Program
|
internal static class Program
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The main entry point for the application.
|
/// The main entry point for the application.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[STAThread]
|
[STAThread]
|
||||||
static void Main()
|
private static void Main()
|
||||||
{
|
{
|
||||||
Application.EnableVisualStyles();
|
Application.EnableVisualStyles();
|
||||||
Application.SetCompatibleTextRenderingDefault( false );
|
Application.SetCompatibleTextRenderingDefault( false );
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
// General Information about an assembly is controlled through the following
|
// General Information about an assembly is controlled through the following
|
||||||
|
|||||||
@@ -1,11 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Data;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using TestProtocol;
|
using TestProtocol;
|
||||||
|
|
||||||
@@ -19,7 +13,7 @@ namespace TestServer
|
|||||||
|
|
||||||
public partial class ServerForm : Form
|
public partial class ServerForm : Form
|
||||||
{
|
{
|
||||||
private ServerCredential serverCred;
|
private ServerCurrentCredential serverCred;
|
||||||
|
|
||||||
private ServerContext serverContext;
|
private ServerContext serverContext;
|
||||||
|
|
||||||
@@ -35,7 +29,7 @@ namespace TestServer
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
this.serverCred = new ServerCredential( PackageNames.Negotiate );
|
this.serverCred = new ServerCurrentCredential( PackageNames.Negotiate );
|
||||||
|
|
||||||
this.serverContext = new ServerContext(
|
this.serverContext = new ServerContext(
|
||||||
serverCred,
|
serverCred,
|
||||||
@@ -129,7 +123,7 @@ namespace TestServer
|
|||||||
{
|
{
|
||||||
MessageBox.Show( "Starting impersonation: " + Environment.UserName );
|
MessageBox.Show( "Starting impersonation: " + Environment.UserName );
|
||||||
|
|
||||||
FileStream stream = File.Create( Environment.GetFolderPath( Environment.SpecialFolder.DesktopDirectory) + @"\test.txt" );
|
FileStream stream = File.Create( Environment.GetFolderPath( Environment.SpecialFolder.DesktopDirectory ) + @"\test.txt" );
|
||||||
StreamWriter writer = new StreamWriter( stream, Encoding.UTF8 );
|
StreamWriter writer = new StreamWriter( stream, Encoding.UTF8 );
|
||||||
|
|
||||||
writer.WriteLine( "Hello world." );
|
writer.WriteLine( "Hello world." );
|
||||||
@@ -150,7 +144,6 @@ namespace TestServer
|
|||||||
this.signButton.Enabled = this.connected;
|
this.signButton.Enabled = this.connected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void server_Received( Message message )
|
private void server_Received( Message message )
|
||||||
{
|
{
|
||||||
if( message.Operation == ProtocolOp.ClientToken )
|
if( message.Operation == ProtocolOp.ClientToken )
|
||||||
@@ -177,7 +170,6 @@ namespace TestServer
|
|||||||
this.initializing = true;
|
this.initializing = true;
|
||||||
this.connected = false;
|
this.connected = false;
|
||||||
|
|
||||||
|
|
||||||
this.serverContext.Dispose();
|
this.serverContext.Dispose();
|
||||||
this.serverContext = new ServerContext(
|
this.serverContext = new ServerContext(
|
||||||
serverCred,
|
serverCred,
|
||||||
@@ -189,14 +181,13 @@ namespace TestServer
|
|||||||
ContextAttrib.Confidentiality
|
ContextAttrib.Confidentiality
|
||||||
);
|
);
|
||||||
|
|
||||||
this.BeginInvoke( (Action)delegate()
|
this.BeginInvoke( (Action)delegate ()
|
||||||
{
|
{
|
||||||
UpdateButtons();
|
UpdateButtons();
|
||||||
this.clientUsernameTextBox.Text = "";
|
this.clientUsernameTextBox.Text = "";
|
||||||
});
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void HandleInit( Message message )
|
private void HandleInit( Message message )
|
||||||
{
|
{
|
||||||
byte[] nextToken;
|
byte[] nextToken;
|
||||||
@@ -218,7 +209,7 @@ namespace TestServer
|
|||||||
this.initializing = false;
|
this.initializing = false;
|
||||||
this.connected = true;
|
this.connected = true;
|
||||||
|
|
||||||
this.Invoke( (Action)delegate()
|
this.Invoke( (Action)delegate ()
|
||||||
{
|
{
|
||||||
UpdateButtons();
|
UpdateButtons();
|
||||||
this.clientUsernameTextBox.Text = serverContext.ContextUserName;
|
this.clientUsernameTextBox.Text = serverContext.ContextUserName;
|
||||||
@@ -227,18 +218,17 @@ namespace TestServer
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this.Invoke( (Action)delegate()
|
this.Invoke( (Action)delegate ()
|
||||||
{
|
{
|
||||||
MessageBox.Show( "Failed to accept token from client. Sspi error code: " + status );
|
MessageBox.Show( "Failed to accept token from client. Sspi error code: " + status );
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleEncrypted( Message message )
|
private void HandleEncrypted( Message message )
|
||||||
{
|
{
|
||||||
this.Invoke( (Action)delegate()
|
this.Invoke( (Action)delegate ()
|
||||||
{
|
{
|
||||||
byte[] plainText = this.serverContext.Decrypt( message.Data );
|
byte[] plainText = this.serverContext.Decrypt( message.Data );
|
||||||
string text = Encoding.UTF8.GetString( plainText );
|
string text = Encoding.UTF8.GetString( plainText );
|
||||||
@@ -249,7 +239,7 @@ namespace TestServer
|
|||||||
|
|
||||||
private void HandleSigned( Message message )
|
private void HandleSigned( Message message )
|
||||||
{
|
{
|
||||||
this.Invoke( (Action)delegate()
|
this.Invoke( (Action)delegate ()
|
||||||
{
|
{
|
||||||
byte[] plainText;
|
byte[] plainText;
|
||||||
|
|
||||||
@@ -268,11 +258,10 @@ namespace TestServer
|
|||||||
|
|
||||||
private void HandleUnknown( Message message )
|
private void HandleUnknown( Message message )
|
||||||
{
|
{
|
||||||
this.Invoke( (Action)delegate()
|
this.Invoke( (Action)delegate ()
|
||||||
{
|
{
|
||||||
MessageBox.Show( "Received unexpected message from server. Message type: " + message.Operation );
|
MessageBox.Show( "Received unexpected message from server. Message type: " + message.Operation );
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,12 @@
|
|||||||
## Downloads ##
|
## Downloads ##
|
||||||
|
|
||||||
The latest release of NSspi is v0.1.1.
|
The latest release of NSspi is v0.2.0.
|
||||||
|
|
||||||
* [Source](https://github.com/antiduh/nsspi/archive/0.1.1.zip)
|
Version 0.2.0 adds the ability to authenticate using provided username/password credentials.
|
||||||
* [Binaries](https://github.com/antiduh/nsspi/releases/download/0.1.1/nsspi-0.1.1-bin.zip)
|
**Please note** that v0.2.0 introduces a small change in the design that breaks backwards compatibility with previous verisons.
|
||||||
|
|
||||||
|
* [Source](https://github.com/antiduh/nsspi/archive/0.2.0.zip)
|
||||||
|
* [Binaries](https://github.com/antiduh/nsspi/releases/download/0.1.3/nsspi-0.2.0-bin.zip)
|
||||||
* [Nuget package](https://www.nuget.org/packages/NSspi)
|
* [Nuget package](https://www.nuget.org/packages/NSspi)
|
||||||
|
|
||||||
You can also browse the list of [releases](https://github.com/antiduh/nsspi/releases).
|
You can also browse the list of [releases](https://github.com/antiduh/nsspi/releases).
|
||||||
|
|||||||
Reference in New Issue
Block a user