<PackageReference Include="SSH.NET" Version="2024.2.0" />

Session

public class Session : ISession, IDisposable
Provides functionality to connect and interact with SSH server.
using Org.BouncyCastle.Utilities; using Renci.SshNet.Abstractions; using Renci.SshNet.Channels; using Renci.SshNet.Common; using Renci.SshNet.Compression; using Renci.SshNet.Connection; using Renci.SshNet.Messages; using Renci.SshNet.Messages.Authentication; using Renci.SshNet.Messages.Connection; using Renci.SshNet.Messages.Transport; using Renci.SshNet.Security; using Renci.SshNet.Security.Cryptography; using Renci.SshNet.Security.Cryptography.Ciphers; using System; using System.Buffers.Binary; using System.Globalization; using System.Linq; using System.Net.Sockets; using System.Runtime.CompilerServices; using System.Runtime.ExceptionServices; using System.Security.Cryptography; using System.Text; using System.Threading; using System.Threading.Tasks; namespace Renci.SshNet { public class Session : ISession, IDisposable { internal const byte CarriageReturn = 13; internal const byte LineFeed = 10; private static readonly string ClientVersionString = "SSH-2.0-Renci.SshNet.SshClient." + "2024.2.0".Replace('-', '_'); internal const int MaximumSshPacketSize = 68536; private const int InitialLocalWindowSize = int.MaxValue; private const int LocalChannelDataPacketSize = 65536; private readonly IServiceFactory _serviceFactory; private readonly ISocketFactory _socketFactory; private readonly object _socketReadLock = new object(); private readonly object _socketWriteLock = new object(); private readonly SemaphoreSlim _socketDisposeLock = new SemaphoreSlim(1, 1); private readonly SemaphoreSlim _connectLock = new SemaphoreSlim(1, 1); private SshMessageFactory _sshMessageFactory; private ManualResetEvent _messageListenerCompleted; private volatile uint _outboundPacketSequence; private uint _inboundPacketSequence; private EventWaitHandle _serviceAccepted = new AutoResetEvent(false); private EventWaitHandle _exceptionWaitHandle = new ManualResetEvent(false); private ManualResetEventSlim _keyExchangeCompletedWaitHandle = new ManualResetEventSlim(false); private Exception _exception; private bool _isAuthenticated; private bool _isDisconnecting; private bool _isInitialKex; private bool _isStrictKex; private IKeyExchange _keyExchange; private HashAlgorithm _serverMac; private HashAlgorithm _clientMac; private bool _serverEtm; private bool _clientEtm; private Cipher _serverCipher; private Cipher _clientCipher; private bool _serverAead; private bool _clientAead; private Compressor _serverDecompression; private Compressor _clientCompression; private SemaphoreSlim _sessionSemaphore; private bool _isDisconnectMessageSent; private int _nextChannelNumber; private Socket _socket; private bool _disposed; public SemaphoreSlim SessionSemaphore { get { SemaphoreSlim sessionSemaphore = _sessionSemaphore; if (sessionSemaphore != null) return sessionSemaphore; sessionSemaphore = new SemaphoreSlim(ConnectionInfo.MaxSessions); if (Interlocked.CompareExchange(ref _sessionSemaphore, sessionSemaphore, null) != null) sessionSemaphore.Dispose(); return _sessionSemaphore; } } private uint NextChannelNumber => (uint)Interlocked.Increment(ref _nextChannelNumber); public bool IsConnected { get { if (_disposed || _isDisconnectMessageSent || !_isAuthenticated) return false; if (_messageListenerCompleted == null || _messageListenerCompleted.WaitOne(0)) return false; return IsSocketConnected(); } } public byte[] SessionId { get; set; } public Message ClientInitMessage { get; set; } public string ServerVersion { get; set; } public string ClientVersion => ClientVersionString; public ConnectionInfo ConnectionInfo { get; set; } IConnectionInfo ISession.ConnectionInfo { get { return ConnectionInfo; } } WaitHandle ISession.MessageListenerCompleted { get { return _messageListenerCompleted; } } public event EventHandler<ExceptionEventArgs> ErrorOccured; public event EventHandler<EventArgs> Disconnected; public event EventHandler<SshIdentificationEventArgs> ServerIdentificationReceived; public event EventHandler<HostKeyEventArgs> HostKeyReceived; public event EventHandler<MessageEventArgs<BannerMessage>> UserAuthenticationBannerReceived; internal event EventHandler<MessageEventArgs<InformationRequestMessage>> UserAuthenticationInformationRequestReceived; internal event EventHandler<MessageEventArgs<PasswordChangeRequiredMessage>> UserAuthenticationPasswordChangeRequiredReceived; internal event EventHandler<MessageEventArgs<PublicKeyMessage>> UserAuthenticationPublicKeyReceived; internal event EventHandler<MessageEventArgs<KeyExchangeDhGroupExchangeGroup>> KeyExchangeDhGroupExchangeGroupReceived; internal event EventHandler<MessageEventArgs<KeyExchangeDhGroupExchangeReply>> KeyExchangeDhGroupExchangeReplyReceived; internal event EventHandler<MessageEventArgs<DisconnectMessage>> DisconnectReceived; internal event EventHandler<MessageEventArgs<IgnoreMessage>> IgnoreReceived; internal event EventHandler<MessageEventArgs<UnimplementedMessage>> UnimplementedReceived; internal event EventHandler<MessageEventArgs<DebugMessage>> DebugReceived; internal event EventHandler<MessageEventArgs<ServiceRequestMessage>> ServiceRequestReceived; internal event EventHandler<MessageEventArgs<ServiceAcceptMessage>> ServiceAcceptReceived; internal event EventHandler<MessageEventArgs<KeyExchangeInitMessage>> KeyExchangeInitReceived; internal event EventHandler<MessageEventArgs<KeyExchangeDhReplyMessage>> KeyExchangeDhReplyMessageReceived; internal event EventHandler<MessageEventArgs<KeyExchangeEcdhReplyMessage>> KeyExchangeEcdhReplyMessageReceived; internal event EventHandler<MessageEventArgs<NewKeysMessage>> NewKeysReceived; internal event EventHandler<MessageEventArgs<RequestMessage>> UserAuthenticationRequestReceived; internal event EventHandler<MessageEventArgs<FailureMessage>> UserAuthenticationFailureReceived; internal event EventHandler<MessageEventArgs<SuccessMessage>> UserAuthenticationSuccessReceived; internal event EventHandler<MessageEventArgs<GlobalRequestMessage>> GlobalRequestReceived; public event EventHandler<MessageEventArgs<RequestSuccessMessage>> RequestSuccessReceived; public event EventHandler<MessageEventArgs<RequestFailureMessage>> RequestFailureReceived; public event EventHandler<MessageEventArgs<ChannelOpenMessage>> ChannelOpenReceived; public event EventHandler<MessageEventArgs<ChannelOpenConfirmationMessage>> ChannelOpenConfirmationReceived; public event EventHandler<MessageEventArgs<ChannelOpenFailureMessage>> ChannelOpenFailureReceived; public event EventHandler<MessageEventArgs<ChannelWindowAdjustMessage>> ChannelWindowAdjustReceived; public event EventHandler<MessageEventArgs<ChannelDataMessage>> ChannelDataReceived; public event EventHandler<MessageEventArgs<ChannelExtendedDataMessage>> ChannelExtendedDataReceived; public event EventHandler<MessageEventArgs<ChannelEofMessage>> ChannelEofReceived; public event EventHandler<MessageEventArgs<ChannelCloseMessage>> ChannelCloseReceived; public event EventHandler<MessageEventArgs<ChannelRequestMessage>> ChannelRequestReceived; public event EventHandler<MessageEventArgs<ChannelSuccessMessage>> ChannelSuccessReceived; public event EventHandler<MessageEventArgs<ChannelFailureMessage>> ChannelFailureReceived; internal Session(ConnectionInfo connectionInfo, IServiceFactory serviceFactory, ISocketFactory socketFactory) { ThrowHelper.ThrowIfNull(connectionInfo, "connectionInfo"); ThrowHelper.ThrowIfNull(serviceFactory, "serviceFactory"); ThrowHelper.ThrowIfNull(socketFactory, "socketFactory"); ConnectionInfo = connectionInfo; _serviceFactory = serviceFactory; _socketFactory = socketFactory; _messageListenerCompleted = new ManualResetEvent(true); } public void Connect() { if (!IsConnected) { _connectLock.Wait(); try { if (!IsConnected) { Reset(); _sshMessageFactory = new SshMessageFactory(); _socket = _serviceFactory.CreateConnector(ConnectionInfo, _socketFactory).Connect(ConnectionInfo); SshIdentification sshIdentification = _serviceFactory.CreateProtocolVersionExchange().Start(ClientVersion, _socket, ConnectionInfo.Timeout); string text3 = ServerVersion = (ConnectionInfo.ServerVersion = sshIdentification.ToString()); ConnectionInfo.ClientVersion = ClientVersion; if (!sshIdentification.ProtocolVersion.Equals("2.0") && !sshIdentification.ProtocolVersion.Equals("1.99")) throw new SshConnectionException(string.Format(CultureInfo.CurrentCulture, "Server version '{0}' is not supported.", sshIdentification.ProtocolVersion), DisconnectReason.ProtocolVersionNotSupported); this.ServerIdentificationReceived?.Invoke(this, new SshIdentificationEventArgs(sshIdentification)); RegisterMessage("SSH_MSG_DISCONNECT"); RegisterMessage("SSH_MSG_IGNORE"); RegisterMessage("SSH_MSG_UNIMPLEMENTED"); RegisterMessage("SSH_MSG_DEBUG"); RegisterMessage("SSH_MSG_SERVICE_ACCEPT"); RegisterMessage("SSH_MSG_KEXINIT"); RegisterMessage("SSH_MSG_NEWKEYS"); RegisterMessage("SSH_MSG_USERAUTH_BANNER"); _isInitialKex = true; ClientInitMessage = BuildClientInitMessage(true); SendMessage(ClientInitMessage); _messageListenerCompleted.Reset(); ThreadAbstraction.ExecuteThreadLongRunning(MessageListener); WaitOnHandle(_keyExchangeCompletedWaitHandle.WaitHandle); if (SessionId == null) Disconnect(); else { SendMessage(new ServiceRequestMessage(ServiceName.UserAuthentication)); WaitOnHandle(_serviceAccepted); if (string.IsNullOrEmpty(ConnectionInfo.Username)) throw new SshException("Username is not specified."); RegisterMessage("SSH_MSG_GLOBAL_REQUEST"); ConnectionInfo.Authenticate(this, _serviceFactory); _isAuthenticated = true; RegisterMessage("SSH_MSG_REQUEST_SUCCESS"); RegisterMessage("SSH_MSG_REQUEST_FAILURE"); RegisterMessage("SSH_MSG_CHANNEL_OPEN_CONFIRMATION"); RegisterMessage("SSH_MSG_CHANNEL_OPEN_FAILURE"); RegisterMessage("SSH_MSG_CHANNEL_WINDOW_ADJUST"); RegisterMessage("SSH_MSG_CHANNEL_EXTENDED_DATA"); RegisterMessage("SSH_MSG_CHANNEL_REQUEST"); RegisterMessage("SSH_MSG_CHANNEL_SUCCESS"); RegisterMessage("SSH_MSG_CHANNEL_FAILURE"); RegisterMessage("SSH_MSG_CHANNEL_DATA"); RegisterMessage("SSH_MSG_CHANNEL_EOF"); RegisterMessage("SSH_MSG_CHANNEL_CLOSE"); } } } finally { _connectLock.Release(); } } } [AsyncStateMachine(typeof(<ConnectAsync>d__176))] public Task ConnectAsync(CancellationToken cancellationToken) { <ConnectAsync>d__176 stateMachine = default(<ConnectAsync>d__176); stateMachine.<>t__builder = AsyncTaskMethodBuilder.Create(); stateMachine.<>4__this = this; stateMachine.cancellationToken = cancellationToken; stateMachine.<>1__state = -1; stateMachine.<>t__builder.Start(ref stateMachine); return stateMachine.<>t__builder.Task; } public void Disconnect() { Disconnect(DisconnectReason.ByApplication, "Connection terminated by the client."); if (_messageListenerCompleted != null) _messageListenerCompleted.WaitOne(); } private void Disconnect(DisconnectReason reason, string message) { _isDisconnecting = true; if (IsConnected) TrySendDisconnect(reason, message); SocketDisconnectAndDispose(); } void ISession.WaitOnHandle(WaitHandle waitHandle) { WaitOnHandle(waitHandle, ConnectionInfo.Timeout); } void ISession.WaitOnHandle(WaitHandle waitHandle, TimeSpan timeout) { WaitOnHandle(waitHandle, timeout); } WaitResult ISession.TryWait(WaitHandle waitHandle, TimeSpan timeout) { Exception exception; return TryWait(waitHandle, timeout, out exception); } WaitResult ISession.TryWait(WaitHandle waitHandle, TimeSpan timeout, out Exception exception) { return TryWait(waitHandle, timeout, out exception); } private WaitResult TryWait(WaitHandle waitHandle, TimeSpan timeout, out Exception exception) { ThrowHelper.ThrowIfNull(waitHandle, "waitHandle"); switch (WaitHandle.WaitAny(new WaitHandle[3] { _exceptionWaitHandle, _messageListenerCompleted, waitHandle }, timeout)) { case 0: if (_exception is SshConnectionException) { exception = null; return WaitResult.Disconnected; } exception = _exception; return WaitResult.Failed; case 1: exception = null; return WaitResult.Disconnected; case 2: exception = null; return WaitResult.Success; case 258: exception = null; return WaitResult.TimedOut; default: throw new InvalidOperationException("Unexpected result."); } } internal void WaitOnHandle(WaitHandle waitHandle) { WaitOnHandle(waitHandle, ConnectionInfo.Timeout); } internal void WaitOnHandle(WaitHandle waitHandle, TimeSpan timeout) { ThrowHelper.ThrowIfNull(waitHandle, "waitHandle"); int num = WaitHandle.WaitAny(new WaitHandle[3] { _exceptionWaitHandle, _messageListenerCompleted, waitHandle }, timeout); switch (num) { case 2: break; case 0: ExceptionDispatchInfo.Capture(_exception).Throw(); break; case 1: throw new SshConnectionException("Client not connected."); case 258: if (!_isDisconnecting) throw new SshOperationTimeoutException("Session operation has timed out"); break; default: throw new SshException("Unexpected element '" + num.ToString(CultureInfo.InvariantCulture) + "' signaled."); } } internal void SendMessage(Message message) { if (!_socket.CanWrite()) throw new SshConnectionException("Client not connected."); if (!_keyExchangeCompletedWaitHandle.IsSet && !(message is IKeyExchangedAllowed)) WaitOnHandle(_keyExchangeCompletedWaitHandle.WaitHandle); byte paddingMultiplier = (byte)((_clientCipher == null) ? 8 : Math.Max((byte)8, _clientCipher.MinimumSize)); byte[] array = message.GetPacket(paddingMultiplier, _clientCompression, _clientEtm || _clientAead); lock (_socketWriteLock) { byte[] array2 = null; int num = 4; BinaryPrimitives.WriteUInt32BigEndian(array, _outboundPacketSequence); if (_clientMac != null && !_clientEtm) array2 = _clientMac.ComputeHash(array); if (_clientCipher != null) { _clientCipher.SetSequenceNumber(_outboundPacketSequence); if (_clientEtm) { byte[] array3 = _clientCipher.Encrypt(array, num + 4, array.Length - num - 4); Array.Resize(ref array, num + 4 + array3.Length); Buffer.BlockCopy(array3, 0, array, num + 4, array3.Length); array2 = _clientMac.ComputeHash(array); } else { array = _clientCipher.Encrypt(array, num, array.Length - num); num = 0; } } if (array.Length > 68536) throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, "Packet is too big. Maximum packet size is {0} bytes.", 68536)); int num2 = array.Length - num; if (array2 == null) SendPacket(array, num, num2); else { byte[] array4 = new byte[num2 + array2.Length]; Buffer.BlockCopy(array, num, array4, 0, num2); Buffer.BlockCopy(array2, 0, array4, num2, array2.Length); SendPacket(array4, 0, array4.Length); } if (_isStrictKex && message is NewKeysMessage) _outboundPacketSequence = 0; else _outboundPacketSequence++; } } private void SendPacket(byte[] packet, int offset, int length) { _socketDisposeLock.Wait(); try { if (!_socket.IsConnected()) throw new SshConnectionException("Client not connected."); SocketAbstraction.Send(_socket, packet, offset, length); } finally { _socketDisposeLock.Release(); } } private bool TrySendMessage(Message message) { try { SendMessage(message); return true; } catch (SshException) { return false; } catch (SocketException) { return false; } } private Message ReceiveMessage(Socket socket) { int num = (_serverEtm || _serverAead) ? 4 : ((_serverCipher == null) ? 8 : Math.Max((byte)8, _serverCipher.MinimumSize)); int num2 = 0; if (_serverAead) num2 = _serverCipher.TagSize; else if (_serverMac != null) { num2 = _serverMac.HashSize / 8; } uint num3 = default(uint); byte[] array3 = default(byte[]); lock (_socketReadLock) { byte[] array = new byte[num]; if (TrySocketRead(socket, array, 0, num) == 0) return null; byte[] array2 = array; Cipher serverCipher = _serverCipher; if (serverCipher != null && !(serverCipher is AesGcmCipher)) { _serverCipher.SetSequenceNumber(_inboundPacketSequence); if (_serverMac == null || !_serverEtm) array2 = _serverCipher.Decrypt(array); } num3 = BinaryPrimitives.ReadUInt32BigEndian(array2); if (num3 < Math.Max(8, num) - 4 || num3 > 68532) throw new SshConnectionException(string.Format(CultureInfo.CurrentCulture, "Bad packet length: {0}.", num3), DisconnectReason.ProtocolError); int num4 = (int)(num3 - (num - 4)) + num2; array3 = new byte[num4 + num + 4]; BinaryPrimitives.WriteUInt32BigEndian(array3, _inboundPacketSequence); if (_serverAead) Buffer.BlockCopy(array, 0, array3, 4, num); else Buffer.BlockCopy(array2, 0, array3, 4, num); if (num4 > 0 && TrySocketRead(socket, array3, num + 4, num4) == 0) return null; } if (_serverMac != null && _serverEtm) { byte[] array4 = _serverMac.ComputeHash(array3, 0, array3.Length - num2); if (!Arrays.FixedTimeEquals(num2, array4, 0, array3, array3.Length - num2)) throw new SshConnectionException("MAC error", DisconnectReason.MacError); } if (_serverCipher != null) { int num5 = array3.Length - (num + 4 + num2); if (num5 > 0) { byte[] array5 = _serverCipher.Decrypt(array3, num + 4, num5); Buffer.BlockCopy(array5, 0, array3, num + 4, array5.Length); } } byte b = array3[8]; int num6 = (int)(num3 - b - 1); int offset = 9; if (_serverMac != null && !_serverEtm) { byte[] array6 = _serverMac.ComputeHash(array3, 0, array3.Length - num2); if (!Arrays.FixedTimeEquals(num2, array6, 0, array3, array3.Length - num2)) throw new SshConnectionException("MAC error", DisconnectReason.MacError); } if (_serverDecompression != null) { array3 = _serverDecompression.Decompress(array3, offset, num6); offset = 0; num6 = array3.Length; } _inboundPacketSequence++; if (_inboundPacketSequence == uint.MaxValue && _isInitialKex) throw new SshConnectionException("Inbound packet sequence number is about to wrap during initial key exchange.", DisconnectReason.KeyExchangeFailed); return LoadMessage(array3, offset, num6); } private void TrySendDisconnect(DisconnectReason reasonCode, string message) { DisconnectMessage message2 = new DisconnectMessage(reasonCode, message); TrySendMessage(message2); _isDisconnectMessageSent = true; } internal void OnDisconnectReceived(DisconnectMessage message) { _isDisconnecting = true; _exception = new SshConnectionException(string.Format(CultureInfo.InvariantCulture, "The connection was closed by the server: {0} ({1}).", message.Description, message.ReasonCode), message.ReasonCode); _exceptionWaitHandle.Set(); this.DisconnectReceived?.Invoke(this, new MessageEventArgs<DisconnectMessage>(message)); this.Disconnected?.Invoke(this, EventArgs.Empty); SocketDisconnectAndDispose(); } internal void OnIgnoreReceived(IgnoreMessage message) { this.IgnoreReceived?.Invoke(this, new MessageEventArgs<IgnoreMessage>(message)); } internal void OnUnimplementedReceived(UnimplementedMessage message) { this.UnimplementedReceived?.Invoke(this, new MessageEventArgs<UnimplementedMessage>(message)); } internal void OnDebugReceived(DebugMessage message) { this.DebugReceived?.Invoke(this, new MessageEventArgs<DebugMessage>(message)); } internal void OnServiceRequestReceived(ServiceRequestMessage message) { this.ServiceRequestReceived?.Invoke(this, new MessageEventArgs<ServiceRequestMessage>(message)); } internal void OnServiceAcceptReceived(ServiceAcceptMessage message) { this.ServiceAcceptReceived?.Invoke(this, new MessageEventArgs<ServiceAcceptMessage>(message)); _serviceAccepted.Set(); } internal void OnKeyExchangeDhGroupExchangeGroupReceived(KeyExchangeDhGroupExchangeGroup message) { this.KeyExchangeDhGroupExchangeGroupReceived?.Invoke(this, new MessageEventArgs<KeyExchangeDhGroupExchangeGroup>(message)); } internal void OnKeyExchangeDhGroupExchangeReplyReceived(KeyExchangeDhGroupExchangeReply message) { this.KeyExchangeDhGroupExchangeReplyReceived?.Invoke(this, new MessageEventArgs<KeyExchangeDhGroupExchangeReply>(message)); } internal void OnKeyExchangeInitReceived(KeyExchangeInitMessage message) { bool isSet = _keyExchangeCompletedWaitHandle.IsSet; _keyExchangeCompletedWaitHandle.Reset(); if (_isInitialKex && message.KeyExchangeAlgorithms.Contains("kex-strict-s-v00@openssh.com")) { _isStrictKex = true; if (_inboundPacketSequence != 1) throw new SshConnectionException("KEXINIT was not the first packet during strict key exchange.", DisconnectReason.KeyExchangeFailed); } _sshMessageFactory.DisableNonKeyExchangeMessages(_isStrictKex); _keyExchange = _serviceFactory.CreateKeyExchange(ConnectionInfo.KeyExchangeAlgorithms, message.KeyExchangeAlgorithms); ConnectionInfo.CurrentKeyExchangeAlgorithm = _keyExchange.Name; _keyExchange.HostKeyReceived += KeyExchange_HostKeyReceived; _keyExchange.Start(this, message, isSet); this.KeyExchangeInitReceived?.Invoke(this, new MessageEventArgs<KeyExchangeInitMessage>(message)); } internal void OnKeyExchangeDhReplyMessageReceived(KeyExchangeDhReplyMessage message) { this.KeyExchangeDhReplyMessageReceived?.Invoke(this, new MessageEventArgs<KeyExchangeDhReplyMessage>(message)); } internal void OnKeyExchangeEcdhReplyMessageReceived(KeyExchangeEcdhReplyMessage message) { this.KeyExchangeEcdhReplyMessageReceived?.Invoke(this, new MessageEventArgs<KeyExchangeEcdhReplyMessage>(message)); } internal void OnNewKeysReceived(NewKeysMessage message) { if (SessionId == null) { byte[] array = SessionId = _keyExchange.ExchangeHash; } (_serverCipher as IDisposable)?.Dispose(); (_clientCipher as IDisposable)?.Dispose(); if (_serverMac != null) { _serverMac.Dispose(); _serverMac = null; } if (_clientMac != null) { _clientMac.Dispose(); _clientMac = null; } _serverCipher = _keyExchange.CreateServerCipher(out _serverAead); _clientCipher = _keyExchange.CreateClientCipher(out _clientAead); _serverMac = _keyExchange.CreateServerHash(out _serverEtm); _clientMac = _keyExchange.CreateClientHash(out _clientEtm); _clientCompression = _keyExchange.CreateCompressor(); _serverDecompression = _keyExchange.CreateDecompressor(); _keyExchange.HostKeyReceived -= KeyExchange_HostKeyReceived; _keyExchange.Dispose(); _keyExchange = null; _sshMessageFactory.EnableActivatedMessages(); if (_isInitialKex) { _isInitialKex = false; ClientInitMessage = BuildClientInitMessage(false); } if (_isStrictKex) _inboundPacketSequence = 0; this.NewKeysReceived?.Invoke(this, new MessageEventArgs<NewKeysMessage>(message)); _keyExchangeCompletedWaitHandle.Set(); } void ISession.OnDisconnecting() { _isDisconnecting = true; } internal void OnUserAuthenticationRequestReceived(RequestMessage message) { this.UserAuthenticationRequestReceived?.Invoke(this, new MessageEventArgs<RequestMessage>(message)); } internal void OnUserAuthenticationFailureReceived(FailureMessage message) { this.UserAuthenticationFailureReceived?.Invoke(this, new MessageEventArgs<FailureMessage>(message)); } internal void OnUserAuthenticationSuccessReceived(SuccessMessage message) { this.UserAuthenticationSuccessReceived?.Invoke(this, new MessageEventArgs<SuccessMessage>(message)); } internal void OnUserAuthenticationBannerReceived(BannerMessage message) { this.UserAuthenticationBannerReceived?.Invoke(this, new MessageEventArgs<BannerMessage>(message)); } internal void OnUserAuthenticationInformationRequestReceived(InformationRequestMessage message) { this.UserAuthenticationInformationRequestReceived?.Invoke(this, new MessageEventArgs<InformationRequestMessage>(message)); } internal void OnUserAuthenticationPasswordChangeRequiredReceived(PasswordChangeRequiredMessage message) { this.UserAuthenticationPasswordChangeRequiredReceived?.Invoke(this, new MessageEventArgs<PasswordChangeRequiredMessage>(message)); } internal void OnUserAuthenticationPublicKeyReceived(PublicKeyMessage message) { this.UserAuthenticationPublicKeyReceived?.Invoke(this, new MessageEventArgs<PublicKeyMessage>(message)); } internal void OnGlobalRequestReceived(GlobalRequestMessage message) { this.GlobalRequestReceived?.Invoke(this, new MessageEventArgs<GlobalRequestMessage>(message)); } internal void OnRequestSuccessReceived(RequestSuccessMessage message) { this.RequestSuccessReceived?.Invoke(this, new MessageEventArgs<RequestSuccessMessage>(message)); } internal void OnRequestFailureReceived(RequestFailureMessage message) { this.RequestFailureReceived?.Invoke(this, new MessageEventArgs<RequestFailureMessage>(message)); } internal void OnChannelOpenReceived(ChannelOpenMessage message) { this.ChannelOpenReceived?.Invoke(this, new MessageEventArgs<ChannelOpenMessage>(message)); } internal void OnChannelOpenConfirmationReceived(ChannelOpenConfirmationMessage message) { this.ChannelOpenConfirmationReceived?.Invoke(this, new MessageEventArgs<ChannelOpenConfirmationMessage>(message)); } internal void OnChannelOpenFailureReceived(ChannelOpenFailureMessage message) { this.ChannelOpenFailureReceived?.Invoke(this, new MessageEventArgs<ChannelOpenFailureMessage>(message)); } internal void OnChannelWindowAdjustReceived(ChannelWindowAdjustMessage message) { this.ChannelWindowAdjustReceived?.Invoke(this, new MessageEventArgs<ChannelWindowAdjustMessage>(message)); } internal void OnChannelDataReceived(ChannelDataMessage message) { this.ChannelDataReceived?.Invoke(this, new MessageEventArgs<ChannelDataMessage>(message)); } internal void OnChannelExtendedDataReceived(ChannelExtendedDataMessage message) { this.ChannelExtendedDataReceived?.Invoke(this, new MessageEventArgs<ChannelExtendedDataMessage>(message)); } internal void OnChannelEofReceived(ChannelEofMessage message) { this.ChannelEofReceived?.Invoke(this, new MessageEventArgs<ChannelEofMessage>(message)); } internal void OnChannelCloseReceived(ChannelCloseMessage message) { this.ChannelCloseReceived?.Invoke(this, new MessageEventArgs<ChannelCloseMessage>(message)); } internal void OnChannelRequestReceived(ChannelRequestMessage message) { this.ChannelRequestReceived?.Invoke(this, new MessageEventArgs<ChannelRequestMessage>(message)); } internal void OnChannelSuccessReceived(ChannelSuccessMessage message) { this.ChannelSuccessReceived?.Invoke(this, new MessageEventArgs<ChannelSuccessMessage>(message)); } internal void OnChannelFailureReceived(ChannelFailureMessage message) { this.ChannelFailureReceived?.Invoke(this, new MessageEventArgs<ChannelFailureMessage>(message)); } private void KeyExchange_HostKeyReceived(object sender, HostKeyEventArgs e) { this.HostKeyReceived?.Invoke(this, e); } public void RegisterMessage(string messageName) { _sshMessageFactory.EnableAndActivateMessage(messageName); } public void UnRegisterMessage(string messageName) { _sshMessageFactory.DisableAndDeactivateMessage(messageName); } private Message LoadMessage(byte[] data, int offset, int count) { byte messageNumber = data[offset]; Message message = _sshMessageFactory.Create(messageNumber); message.Load(data, offset + 1, count - 1); return message; } private static string ToHex(byte[] bytes, int offset) { int num = bytes.Length - offset; StringBuilder stringBuilder = new StringBuilder(bytes.Length * 2); for (int i = offset; i < num; i++) { byte b = bytes[i]; stringBuilder.Append(b.ToString("X2")); } return stringBuilder.ToString(); } internal static string ToHex(byte[] bytes) { if (bytes == null) return null; return ToHex(bytes, 0); } private bool IsSocketConnected() { _socketDisposeLock.Wait(); try { if (_socket.IsConnected()) { if (Monitor.TryEnter(_socketReadLock)) try { return !_socket.Poll(0, SelectMode.SelectRead) || _socket.Available != 0; } finally { Monitor.Exit(_socketReadLock); } return true; } return false; } finally { _socketDisposeLock.Release(); } } private static int TrySocketRead(Socket socket, byte[] buffer, int offset, int length) { return SocketAbstraction.Read(socket, buffer, offset, length, Timeout.InfiniteTimeSpan); } private void SocketDisconnectAndDispose() { if (_socket != null) { _socketDisposeLock.Wait(); try { if (_socket != null) { if (_socket.Connected) try { _socket.Shutdown(SocketShutdown.Send); } catch (SocketException) { } _socket.Dispose(); _socket = null; } } finally { _socketDisposeLock.Release(); } } } private void MessageListener() { try { while (true) { Socket socket = _socket; if (socket == null || !socket.Connected) break; try { if (socket.Poll(-1, SelectMode.SelectRead) && socket.Available == 0) break; } catch (ObjectDisposedException) { break; } Message message = ReceiveMessage(socket); if (message == null) break; message.Process(this); } RaiseError(CreateConnectionAbortedByServerException()); } catch (SocketException ex2) { RaiseError(new SshConnectionException(ex2.Message, DisconnectReason.ConnectionLost, ex2)); } catch (Exception exp) { RaiseError(exp); } finally { _messageListenerCompleted.Set(); } } private void RaiseError(Exception exp) { SshConnectionException ex = exp as SshConnectionException; if (_isDisconnecting) { if (ex != null) return; SocketException ex2 = exp as SocketException; if (ex2 != null && ex2.SocketErrorCode == SocketError.TimedOut) return; } _exception = exp; _exceptionWaitHandle.Set(); this.ErrorOccured?.Invoke(this, new ExceptionEventArgs(exp)); if (ex != null) Disconnect(ex.DisconnectReason, exp.ToString()); } private void Reset() { _exceptionWaitHandle?.Reset(); _keyExchangeCompletedWaitHandle?.Reset(); _messageListenerCompleted?.Set(); SessionId = null; _isDisconnectMessageSent = false; _isDisconnecting = false; _isAuthenticated = false; _exception = null; } private static SshConnectionException CreateConnectionAbortedByServerException() { return new SshConnectionException("An established connection was aborted by the server.", DisconnectReason.ConnectionLost); } private KeyExchangeInitMessage BuildClientInitMessage(bool includeStrictKexPseudoAlgorithm) { KeyExchangeInitMessage keyExchangeInitMessage = new KeyExchangeInitMessage(); keyExchangeInitMessage.KeyExchangeAlgorithms = (includeStrictKexPseudoAlgorithm ? ConnectionInfo.KeyExchangeAlgorithms.Keys.Concat(new <>z__ReadOnlySingleElementList<string>("kex-strict-c-v00@openssh.com")).ToArray() : ConnectionInfo.KeyExchangeAlgorithms.Keys.ToArray()); keyExchangeInitMessage.ServerHostKeyAlgorithms = ConnectionInfo.HostKeyAlgorithms.Keys.ToArray(); keyExchangeInitMessage.EncryptionAlgorithmsClientToServer = ConnectionInfo.Encryptions.Keys.ToArray(); keyExchangeInitMessage.EncryptionAlgorithmsServerToClient = ConnectionInfo.Encryptions.Keys.ToArray(); keyExchangeInitMessage.MacAlgorithmsClientToServer = ConnectionInfo.HmacAlgorithms.Keys.ToArray(); keyExchangeInitMessage.MacAlgorithmsServerToClient = ConnectionInfo.HmacAlgorithms.Keys.ToArray(); keyExchangeInitMessage.CompressionAlgorithmsClientToServer = ConnectionInfo.CompressionAlgorithms.Keys.ToArray(); keyExchangeInitMessage.CompressionAlgorithmsServerToClient = ConnectionInfo.CompressionAlgorithms.Keys.ToArray(); keyExchangeInitMessage.LanguagesClientToServer = new string[1] { string.Empty }; keyExchangeInitMessage.LanguagesServerToClient = new string[1] { string.Empty }; keyExchangeInitMessage.FirstKexPacketFollows = false; keyExchangeInitMessage.Reserved = 0; return keyExchangeInitMessage; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (!_disposed && disposing) { Disconnect(); EventWaitHandle serviceAccepted = _serviceAccepted; if (serviceAccepted != null) { serviceAccepted.Dispose(); _serviceAccepted = null; } EventWaitHandle exceptionWaitHandle = _exceptionWaitHandle; if (exceptionWaitHandle != null) { exceptionWaitHandle.Dispose(); _exceptionWaitHandle = null; } ManualResetEventSlim keyExchangeCompletedWaitHandle = _keyExchangeCompletedWaitHandle; if (keyExchangeCompletedWaitHandle != null) { keyExchangeCompletedWaitHandle.Dispose(); _keyExchangeCompletedWaitHandle = null; } (_serverCipher as IDisposable)?.Dispose(); (_clientCipher as IDisposable)?.Dispose(); HashAlgorithm serverMac = _serverMac; if (serverMac != null) { serverMac.Dispose(); _serverMac = null; } HashAlgorithm clientMac = _clientMac; if (clientMac != null) { clientMac.Dispose(); _clientMac = null; } Compressor serverDecompression = _serverDecompression; if (serverDecompression != null) { serverDecompression.Dispose(); _serverDecompression = null; } Compressor clientCompression = _clientCompression; if (clientCompression != null) { clientCompression.Dispose(); _clientCompression = null; } IKeyExchange keyExchange = _keyExchange; if (keyExchange != null) { keyExchange.HostKeyReceived -= KeyExchange_HostKeyReceived; keyExchange.Dispose(); _keyExchange = null; } ManualResetEvent messageListenerCompleted = _messageListenerCompleted; if (messageListenerCompleted != null) { messageListenerCompleted.Dispose(); _messageListenerCompleted = null; } _disposed = true; } } IChannelSession ISession.CreateChannelSession() { return new ChannelSession(this, NextChannelNumber, 2147483647, 65536); } IChannelDirectTcpip ISession.CreateChannelDirectTcpip() { return new ChannelDirectTcpip(this, NextChannelNumber, 2147483647, 65536); } IChannelForwardedTcpip ISession.CreateChannelForwardedTcpip(uint remoteChannelNumber, uint remoteWindowSize, uint remoteChannelDataPacketSize) { return new ChannelForwardedTcpip(this, NextChannelNumber, 2147483647, 65536, remoteChannelNumber, remoteWindowSize, remoteChannelDataPacketSize); } void ISession.SendMessage(Message message) { SendMessage(message); } bool ISession.TrySendMessage(Message message) { return TrySendMessage(message); } } }