From 06f1b08050864010047bd0936f60b2bd9fc04d7d Mon Sep 17 00:00:00 2001 From: Kevin Thompson Date: Fri, 19 Jul 2019 16:42:41 -0400 Subject: [PATCH] Added support to retrieve the remote identity. --- NSspi/Contexts/Context.cs | 63 ++++++++++++++++++++++++++ NSspi/Contexts/ContextNativeMethods.cs | 4 ++ NSspi/Contexts/ServerContext.cs | 12 +---- NSspi/NativeMethods.cs | 4 ++ TestServer/ServerForm.Designer.cs | 3 +- TestServer/ServerForm.cs | 51 ++++++++++++++++----- 6 files changed, 114 insertions(+), 23 deletions(-) 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