internal ShellStream(Session session, string terminalName, uint columns, uint rows, uint width, uint height, int maxLines, PrivateKeyAgent forwardedPrivateKeyAgent, params KeyValuePair <TerminalModes, uint>[] terminalModeValues) { this._encoding = new Renci.SshNet.Common.ASCIIEncoding(); this._session = session; this._incoming = new Queue <byte>(); this._outgoing = new Queue <byte>(); this._channel = this._session.CreateChannel <ChannelSession>(); this._channel.DataReceived += new EventHandler <ChannelDataEventArgs>(Channel_DataReceived); this._channel.Closed += new EventHandler <ChannelEventArgs>(Channel_Closed); this._session.Disconnected += new EventHandler <EventArgs>(Session_Disconnected); this._session.ErrorOccured += new EventHandler <ExceptionEventArgs>(Session_ErrorOccured); this.forwardedPrivateKeyAgent = forwardedPrivateKeyAgent; this._channel.Open(); if (this.forwardedPrivateKeyAgent != null) { if (this._channel.SendPrivateKeyAgentForwardingRequest()) { this._session.RegisterMessage("SSH_MSG_CHANNEL_OPEN"); this._session.ChannelOpenReceived += OnChannelOpen; } } this._channel.SendPseudoTerminalRequest(terminalName, columns, rows, width, height, terminalModeValues); this._channel.SendShellRequest(); }
internal ShellStream(Session session, string terminalName, uint columns, uint rows, uint width, uint height, int maxLines, PrivateKeyAgent forwardedPrivateKeyAgent, params KeyValuePair<TerminalModes, uint>[] terminalModeValues) { this._encoding = new Renci.SshNet.Common.ASCIIEncoding(); this._session = session; this._incoming = new Queue<byte>(); this._outgoing = new Queue<byte>(); this._channel = this._session.CreateChannel<ChannelSession>(); this._channel.DataReceived += new EventHandler<ChannelDataEventArgs>(Channel_DataReceived); this._channel.Closed += new EventHandler<ChannelEventArgs>(Channel_Closed); this._session.Disconnected += new EventHandler<EventArgs>(Session_Disconnected); this._session.ErrorOccured += new EventHandler<ExceptionEventArgs>(Session_ErrorOccured); this.forwardedPrivateKeyAgent = forwardedPrivateKeyAgent; this._channel.Open(); if (this.forwardedPrivateKeyAgent != null) { if (this._channel.SendPrivateKeyAgentForwardingRequest()) { this._session.RegisterMessage("SSH_MSG_CHANNEL_OPEN"); this._session.ChannelOpenReceived += OnChannelOpen; } } this._channel.SendPseudoTerminalRequest(terminalName, columns, rows, width, height, terminalModeValues); this._channel.SendShellRequest(); }
/// <summary> /// Establishes the connection to the server, using the specified <paramref name="terminal"/> for connection initialization (authentication, etc.). /// </summary> /// <param name="terminal">The terminal to use for connection initialization.</param> /// <returns>A value indicating whether the connection was successfully established.</returns> /// <exception cref="ObjectDisposedException">The connection object is already disposed.</exception> /// <exception cref="InvalidOperationException">The connection object is currently connected.</exception> public async Task<bool> ConnectAsync(IConnectionInitializingTerminal terminal) { this.CheckDisposed(); this.MustBeConnected(false); Lazy<string> username = new Lazy<string>(() => { if (string.IsNullOrEmpty(this.connectionData.Username)) { return terminal.ReadLineAsync("Username: "******"Username: "******"Password: "******"Password expired for user " + e.Username); do { var readNewPassword1Task = terminal.ReadLineAsync("New password: "******"Repeat new password: "******"Performing keyboard-interactive authentication."); } if (!string.IsNullOrEmpty(e.Instruction)) { terminal.WriteLine(e.Instruction); } foreach (var prompt in e.Prompts) { var readLineTask = terminal.ReadLineAsync(prompt.Request, echo: prompt.IsEchoed); readLineTask.Wait(); prompt.Response = readLineTask.Result; } }; connectionInfo = keyboardInteractiveConnectionInfo; break; case Model.AuthenticationType.PrivateKey: if (this.privateKeyData == null) { throw new Exception("Private Key '" + connectionData.PrivateKeyName + "' not found. Please correct the authentication details of the connection."); } PrivateKeyFile privateKey; try { using (var privateKeyStream = new MemoryStream(privateKeyData.Data)) { privateKey = new PrivateKeyFile(privateKeyStream); } } catch (SshPassPhraseNullOrEmptyException) { privateKey = null; } // In the normal PrivateKey authentication there is only a connection-local PrivateKeyAgent. var localPprivateKeyAgent = new Lazy<PrivateKeyAgent>(() => { terminal.WriteLine("Performing authentication with Private Key '" + connectionData.PrivateKeyName + "'."); if (privateKey == null) { string privateKeyPassword = terminal.ReadLineAsync("Private Key password: "******"Wrong Private Key password, please try again.", ex); } } } var pka = new PrivateKeyAgent(); pka.AddSsh2(privateKey.HostKey, connectionData.PrivateKeyName); return pka; }); var privateKeyConnectionInfo = new PrivateKeyConnectionInfo(this.connectionData.Host, this.connectionData.Port, username, localPprivateKeyAgent); connectionInfo = privateKeyConnectionInfo; break; case AuthenticationType.PrivateKeyAgent: if (PrivateKeyAgentManager.PrivateKeyAgent.ListSsh2().Count == 0) { throw new SshAuthenticationException("The private key agent doesn't contain any private keys."); } var globalPrivateKeyAgent = new Lazy<PrivateKeyAgent>(() => { var pka = PrivateKeyAgentManager.PrivateKeyAgent; terminal.WriteLine("Performing private key agent authentication."); return pka; }); var privateKeyAgentConnectionInfo = new PrivateKeyConnectionInfo(this.connectionData.Host, this.connectionData.Port, username, globalPrivateKeyAgent); connectionInfo = privateKeyAgentConnectionInfo; if (connectionData.PrivateKeyAgentForwarding == true) { forwardedPrivateKeyAgent = globalPrivateKeyAgent; terminal.WriteLine("Agent forwarding is enabled."); } break; default: throw new NotImplementedException("Authentication method '" + this.connectionData.Authentication + "' not implemented."); } connectionInfo.AuthenticationBanner += (sender, e) => { terminal.WriteLine(e.BannerMessage.Replace("\n", "\r\n")); }; this.client = new SshClient(connectionInfo); this.client.HostKeyReceived += (s, e) => { string fingerprint = string.Join(":", e.FingerPrint.Select(b => b.ToString("x2"))); bool trustHostKey = true; bool storeHostKey = false; string newHostKey = string.Join(null, e.HostKey.Select(b => b.ToString("x2"))); if (oldHostKey == null) { terminal.WriteLine("Remote Terminal has not yet cached a host key for this server."); terminal.WriteLine("Host key's fingerprint: " + fingerprint); terminal.WriteLine("Please make sure the fingerprint matches the server's actual host key."); trustHostKey = QueryYesNo(terminal, "Do you want to continue connecting to the host?"); if (trustHostKey) { storeHostKey = QueryYesNo(terminal, "Do you want to store this host key in the cache?"); } } else if (oldHostKey != newHostKey) { terminal.WriteLine("POSSIBLE SECURITY BREACH DETECTED!"); terminal.WriteLine("Remote Terminal has cached another host key for this server."); terminal.WriteLine("This could mean one of two things:"); terminal.WriteLine(" * the server's host key was changed by an administrator"); terminal.WriteLine(" * another computer is trying to intercept your connection"); terminal.WriteLine("Host key's new fingerprint: " + fingerprint); trustHostKey = QueryYesNo(terminal, "Do you want to continue connecting to the host?"); if (trustHostKey) { storeHostKey = QueryYesNo(terminal, "Do you want to update the cache with the new host key?"); } } e.CanTrust = trustHostKey; if (trustHostKey) { oldHostKey = newHostKey; } if (storeHostKey) { HostKeysDataSource.AddOrUpdate(this.connectionData.Host, this.connectionData.Port, newHostKey); } }; this.client.ConnectionInfo.Timeout = new TimeSpan(0, 15, 0); await Task.Run(() => { this.client.Connect(); }); this.client.ConnectionInfo.Timeout = new TimeSpan(0, 1, 0); var terminalModes = new Dictionary<TerminalModes, uint>(); terminalModes[TerminalModes.TTY_OP_ISPEED] = 0x00009600; terminalModes[TerminalModes.TTY_OP_OSPEED] = 0x00009600; this.stream = this.client.CreateShellStream(terminal.TerminalName, (uint)terminal.Columns, (uint)terminal.Rows, 0, 0, 1024, forwardedPrivateKeyAgent.Value, terminalModes.ToArray()); this.reader = new StreamReader(this.stream); this.writer = new StreamWriter(this.stream); this.writer.AutoFlush = true; return true; } catch (SshConnectionException ex) { terminal.WriteLine(ex.Message); retry = false; } catch (SshAuthenticationException ex) { terminal.WriteLine(ex.Message); if (connectionData.Authentication == AuthenticationType.PrivateKeyAgent) { terminal.WriteLine("Please load the necessary private key(s) into the private key agent."); retry = false; } else { retry = true; } } catch (Exception ex) { terminal.WriteLine(ex.Message); retry = false; } if (!retry || numRetries++ > 5) { return false; } } while (true); }
/// <summary> /// Creates the shell stream. /// </summary> /// <param name="terminalName">Name of the terminal.</param> /// <param name="columns">The columns.</param> /// <param name="rows">The rows.</param> /// <param name="width">The width.</param> /// <param name="height">The height.</param> /// <param name="bufferSize">Size of the buffer.</param> /// <param name="terminalModeValues">The terminal mode values.</param> /// <returns></returns> public ShellStream CreateShellStream(string terminalName, uint columns, uint rows, uint width, uint height, int bufferSize, PrivateKeyAgent forwardedPrivateKeyAgent, params KeyValuePair <TerminalModes, uint>[] terminalModeValues) { // Ensure that connection is established. this.EnsureConnection(); return(new ShellStream(this.Session, terminalName, columns, rows, width, height, bufferSize, forwardedPrivateKeyAgent, terminalModeValues)); }
/// <summary> /// Creates the shell stream. /// </summary> /// <param name="terminalName">Name of the terminal.</param> /// <param name="columns">The columns.</param> /// <param name="rows">The rows.</param> /// <param name="width">The width.</param> /// <param name="height">The height.</param> /// <param name="bufferSize">Size of the buffer.</param> /// <param name="terminalModeValues">The terminal mode values.</param> /// <returns></returns> public ShellStream CreateShellStream(string terminalName, uint columns, uint rows, uint width, uint height, int bufferSize, PrivateKeyAgent forwardedPrivateKeyAgent, params KeyValuePair<TerminalModes, uint>[] terminalModeValues) { // Ensure that connection is established. this.EnsureConnection(); return new ShellStream(this.Session, terminalName, columns, rows, width, height, bufferSize, forwardedPrivateKeyAgent, terminalModeValues); }