diff --git a/NSspi/Contexts/Context.cs b/NSspi/Contexts/Context.cs
index ead8cc6..402ab30 100644
--- a/NSspi/Contexts/Context.cs
+++ b/NSspi/Contexts/Context.cs
@@ -1,6 +1,7 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
+using System.Security.Principal;
using NSspi.Buffers;
using NSspi.Credentials;
@@ -117,6 +118,68 @@ namespace NSspi.Contexts
this.Disposed = true;
}
+ public IIdentity GetRemoteIdentity()
+ {
+ using( var tokenHandle = GetContextToken() )
+ {
+ return new WindowsIdentity(
+ tokenHandle.DangerousGetHandle(),
+ this.Credential.SecurityPackage
+ );
+ }
+ }
+
+ private SafeTokenHandle GetContextToken()
+ {
+ bool gotRef = false;
+ SecurityStatus status = SecurityStatus.InternalError;
+ SafeTokenHandle token;
+
+ RuntimeHelpers.PrepareConstrainedRegions();
+ try
+ {
+ this.ContextHandle.DangerousAddRef( ref gotRef );
+ }
+ catch( Exception )
+ {
+ if( gotRef )
+ {
+ this.ContextHandle.DangerousRelease();
+ gotRef = false;
+ }
+
+ throw;
+ }
+ finally
+ {
+ if( gotRef )
+ {
+ try
+ {
+ status = ContextNativeMethods.QuerySecurityContextToken(
+ ref this.ContextHandle.rawHandle,
+ out token
+ );
+ }
+ finally
+ {
+ this.ContextHandle.DangerousRelease();
+ }
+ }
+ else
+ {
+ token = null;
+ }
+ }
+
+ if( status != SecurityStatus.OK )
+ {
+ throw new SSPIException( "Failed to query context token.", status );
+ }
+
+ return token;
+ }
+
///
/// Encrypts the byte array using the context's session key.
///
diff --git a/NSspi/Contexts/ContextNativeMethods.cs b/NSspi/Contexts/ContextNativeMethods.cs
index dd44237..1d090d2 100644
--- a/NSspi/Contexts/ContextNativeMethods.cs
+++ b/NSspi/Contexts/ContextNativeMethods.cs
@@ -174,6 +174,10 @@ namespace NSspi.Contexts
[DllImport( "Secur32.dll", EntryPoint = "RevertSecurityContext", CharSet = CharSet.Unicode )]
internal static extern SecurityStatus RevertSecurityContext( ref RawSspiHandle contextHandle );
+ [ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
+ [DllImport( "Secur32.dll", EntryPoint = "QuerySecurityContextToken", SetLastError = true )]
+ internal static extern SecurityStatus QuerySecurityContextToken( ref RawSspiHandle contextHandle, [Out] out SafeTokenHandle handle );
+
[StructLayout( LayoutKind.Sequential )]
private class KeyStruct
{
diff --git a/NSspi/Contexts/ServerContext.cs b/NSspi/Contexts/ServerContext.cs
index 7f197de..373351d 100644
--- a/NSspi/Contexts/ServerContext.cs
+++ b/NSspi/Contexts/ServerContext.cs
@@ -246,7 +246,7 @@ namespace NSspi.Contexts
if( this.impersonating && this.impersonationSetsThreadPrinciple )
{
- SetThreadPrinciple();
+ Thread.CurrentPrincipal = new WindowsPrincipal( (WindowsIdentity)GetRemoteIdentity() );
}
return handle;
@@ -315,15 +315,5 @@ namespace NSspi.Contexts
base.Dispose( disposing );
}
-
- ///
- /// Set the current thread security context to the impersonated identity.
- ///
- private void SetThreadPrinciple()
- {
- Thread.CurrentPrincipal = new WindowsPrincipal(
- WindowsIdentity.GetCurrent( TokenAccessLevels.AllAccess )
- );
- }
}
}
\ No newline at end of file
diff --git a/NSspi/NativeMethods.cs b/NSspi/NativeMethods.cs
index 012c05e..d012c63 100644
--- a/NSspi/NativeMethods.cs
+++ b/NSspi/NativeMethods.cs
@@ -17,5 +17,9 @@ namespace NSspi
[ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
[DllImport( "Secur32.dll", EntryPoint = "EnumerateSecurityPackages", CharSet = CharSet.Unicode )]
internal static extern SecurityStatus EnumerateSecurityPackages( ref int numPackages, ref IntPtr pkgInfoArry );
+
+ [DllImport( "Kernel32.dll", EntryPoint = "CloseHandle", SetLastError = true )]
+ [ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )]
+ internal static extern bool CloseHandle( IntPtr handle );
}
}
\ No newline at end of file
diff --git a/TestServer/ServerForm.Designer.cs b/TestServer/ServerForm.Designer.cs
index 5314b64..a94ae55 100644
--- a/TestServer/ServerForm.Designer.cs
+++ b/TestServer/ServerForm.Designer.cs
@@ -170,7 +170,8 @@
//
// impersonateButton
//
- this.impersonateButton.Location = new System.Drawing.Point(262, 350);
+ this.impersonateButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
+ this.impersonateButton.Location = new System.Drawing.Point(262, 356);
this.impersonateButton.Name = "impersonateButton";
this.impersonateButton.Size = new System.Drawing.Size(116, 23);
this.impersonateButton.TabIndex = 4;
diff --git a/TestServer/ServerForm.cs b/TestServer/ServerForm.cs
index fdc8037..eba7fdd 100644
--- a/TestServer/ServerForm.cs
+++ b/TestServer/ServerForm.cs
@@ -1,14 +1,16 @@
using System;
+using System.IO;
+using System.Security.Principal;
using System.Text;
using System.Windows.Forms;
+using NSspi;
+using NSspi.Contexts;
+using NSspi.Credentials;
using TestProtocol;
namespace TestServer
{
- using System.IO;
- using NSspi;
- using NSspi.Contexts;
- using NSspi.Credentials;
+
using Message = TestProtocol.Message;
public partial class ServerForm : Form
@@ -38,7 +40,8 @@ namespace TestServer
ContextAttrib.SequenceDetect |
ContextAttrib.MutualAuth |
ContextAttrib.Delegate |
- ContextAttrib.Confidentiality
+ ContextAttrib.Confidentiality,
+ true
);
this.server = new CustomServer();
@@ -123,7 +126,11 @@ namespace TestServer
{
MessageBox.Show( "Starting impersonation: " + Environment.UserName );
- FileStream stream = File.Create( Environment.GetFolderPath( Environment.SpecialFolder.DesktopDirectory ) + @"\test.txt" );
+ var directory = Environment.GetFolderPath( Environment.SpecialFolder.DesktopDirectory );
+
+ Directory.CreateDirectory( directory );
+
+ FileStream stream = File.Create( directory + @"\test.txt" );
StreamWriter writer = new StreamWriter( stream, Encoding.UTF8 );
writer.WriteLine( "Hello world." );
@@ -164,6 +171,32 @@ namespace TestServer
}
}
+ private void InitComplete()
+ {
+ UpdateButtons();
+ this.clientUsernameTextBox.Text = serverContext.ContextUserName;
+
+ var builder = new StringBuilder();
+ var remoteId = this.serverContext.GetRemoteIdentity();
+
+ builder.AppendLine( "Client identity information:" );
+ builder.AppendLine( " - Name: " + remoteId.Name );
+
+ var windowsId = remoteId as WindowsIdentity;
+
+ if( windowsId != null )
+ {
+ builder.AppendLine( " - User SID: " + windowsId.User.Value );
+
+ foreach( var claim in windowsId.Claims )
+ {
+ builder.AppendLine( " - " + claim.ToString() );
+ }
+ }
+
+ this.receivedTextbox.AppendText( builder.ToString() );
+ }
+
private void server_Disconnected()
{
this.running = true;
@@ -209,11 +242,7 @@ namespace TestServer
this.initializing = false;
this.connected = true;
- this.Invoke( (Action)delegate ()
- {
- UpdateButtons();
- this.clientUsernameTextBox.Text = serverContext.ContextUserName;
- } );
+ this.Invoke( (Action)InitComplete );
}
}
else