SshClient.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Collections.ObjectModel;
  5. using System.Text;
  6. namespace Renci.SshNet
  7. {
  8. /// <summary>
  9. /// Provides client connection to SSH server.
  10. /// </summary>
  11. public class SshClient : BaseClient
  12. {
  13. /// <summary>
  14. /// Holds the list of forwarded ports
  15. /// </summary>
  16. private List<ForwardedPort> _forwardedPorts = new List<ForwardedPort>();
  17. /// <summary>
  18. /// Gets the list of forwarded ports.
  19. /// </summary>
  20. public IEnumerable<ForwardedPort> ForwardedPorts
  21. {
  22. get
  23. {
  24. return this._forwardedPorts.AsReadOnly();
  25. }
  26. }
  27. #region Constructors
  28. /// <summary>
  29. /// Initializes a new instance of the <see cref="SshClient"/> class.
  30. /// </summary>
  31. /// <param name="connectionInfo">The connection info.</param>
  32. /// <exception cref="ArgumentNullException"><paramref name="connectionInfo"/> is null.</exception>
  33. public SshClient(ConnectionInfo connectionInfo)
  34. : base(connectionInfo)
  35. {
  36. }
  37. /// <summary>
  38. /// Initializes a new instance of the <see cref="SshClient"/> class.
  39. /// </summary>
  40. /// <param name="host">Connection host.</param>
  41. /// <param name="port">Connection port.</param>
  42. /// <param name="username">Authentication username.</param>
  43. /// <param name="password">Authentication password.</param>
  44. /// <exception cref="ArgumentNullException"><paramref name="password"/> is null.</exception>
  45. /// <exception cref="ArgumentException"><paramref name="host"/> is invalid, or <paramref name="username"/> is null or contains whitespace characters.</exception>
  46. /// <exception cref="ArgumentOutOfRangeException"><paramref name="port"/> is not within <see cref="System.Net.IPEndPoint.MinPort"/> and <see cref="System.Net.IPEndPoint.MaxPort"/>.</exception>
  47. public SshClient(string host, int port, string username, string password)
  48. : this(new PasswordConnectionInfo(host, port, username, password))
  49. {
  50. }
  51. /// <summary>
  52. /// Initializes a new instance of the <see cref="SshClient"/> class.
  53. /// </summary>
  54. /// <param name="host">Connection host.</param>
  55. /// <param name="username">Authentication username.</param>
  56. /// <param name="password">Authentication password.</param>
  57. /// <exception cref="ArgumentNullException"><paramref name="password"/> is null.</exception>
  58. /// <exception cref="ArgumentException"><paramref name="host"/> is invalid, or <paramref name="username"/> is null or contains whitespace characters.</exception>
  59. public SshClient(string host, string username, string password)
  60. : this(host, 22, username, password)
  61. {
  62. }
  63. /// <summary>
  64. /// Initializes a new instance of the <see cref="SshClient"/> class.
  65. /// </summary>
  66. /// <param name="host">Connection host.</param>
  67. /// <param name="port">Connection port.</param>
  68. /// <param name="username">Authentication username.</param>
  69. /// <param name="keyFiles">Authentication private key file(s) .</param>
  70. /// <exception cref="ArgumentNullException"><paramref name="keyFiles"/> is null.</exception>
  71. /// <exception cref="ArgumentException"><paramref name="host"/> is invalid, -or- <paramref name="username"/> is null or contains whitespace characters.</exception>
  72. /// <exception cref="ArgumentOutOfRangeException"><paramref name="port"/> is not within <see cref="System.Net.IPEndPoint.MinPort"/> and <see cref="System.Net.IPEndPoint.MaxPort"/>.</exception>
  73. public SshClient(string host, int port, string username, params PrivateKeyFile[] keyFiles)
  74. : this(new PrivateKeyConnectionInfo(host, port, username, keyFiles))
  75. {
  76. }
  77. /// <summary>
  78. /// Initializes a new instance of the <see cref="SshClient"/> class.
  79. /// </summary>
  80. /// <param name="host">Connection host.</param>
  81. /// <param name="username">Authentication username.</param>
  82. /// <param name="keyFiles">Authentication private key file(s) .</param>
  83. /// <exception cref="ArgumentNullException"><paramref name="keyFiles"/> is null.</exception>
  84. /// <exception cref="ArgumentException"><paramref name="host"/> is invalid, -or- <paramref name="username"/> is null or contains whitespace characters.</exception>
  85. public SshClient(string host, string username, params PrivateKeyFile[] keyFiles)
  86. : this(host, 22, username, keyFiles)
  87. {
  88. }
  89. #endregion
  90. /// <summary>
  91. /// Called when client is disconnecting from the server.
  92. /// </summary>
  93. protected override void OnDisconnecting()
  94. {
  95. base.OnDisconnecting();
  96. foreach (var port in this._forwardedPorts)
  97. {
  98. port.Stop();
  99. }
  100. }
  101. /// <summary>
  102. /// Adds forwarded port to the list.
  103. /// </summary>
  104. /// <typeparam name="T">Type of forwarded port to add</typeparam>
  105. /// <param name="boundHost">The bound host.</param>
  106. /// <param name="boundPort">The bound port.</param>
  107. /// <param name="connectedHost">The connected host.</param>
  108. /// <param name="connectedPort">The connected port.</param>
  109. /// <returns>
  110. /// Forwarded port
  111. /// </returns>
  112. /// <exception cref="ArgumentNullException"><paramref name="boundHost"/> or <paramref name="connectedHost"/> is null.</exception>
  113. /// <exception cref="ArgumentException"><paramref name="boundHost"/> or <paramref name="connectedHost"/> is invalid.</exception>
  114. /// <exception cref="ArgumentOutOfRangeException"><paramref name="boundPort"/> or <paramref name="connectedPort"/> is not within <see cref="System.Net.IPEndPoint.MinPort"/> and <see cref="System.Net.IPEndPoint.MaxPort"/>.</exception>
  115. /// <exception cref="Renci.SshNet.Common.SshConnectionException">Client is not connected.</exception>
  116. public T AddForwardedPort<T>(string boundHost, uint boundPort, string connectedHost, uint connectedPort) where T : ForwardedPort, new()
  117. {
  118. if (boundHost == null)
  119. throw new ArgumentNullException("boundHost");
  120. if (connectedHost == null)
  121. throw new ArgumentNullException("connectedHost");
  122. if (!boundHost.IsValidHost())
  123. throw new ArgumentException("boundHost");
  124. if (!boundPort.IsValidPort())
  125. throw new ArgumentOutOfRangeException("boundPort");
  126. if (!connectedHost.IsValidHost())
  127. throw new ArgumentException("connectedHost");
  128. if (!connectedPort.IsValidPort())
  129. throw new ArgumentOutOfRangeException("connectedPort");
  130. // Ensure that connection is established.
  131. this.EnsureConnection();
  132. T port = new T();
  133. port.Session = this.Session;
  134. port.BoundHost = boundHost;
  135. port.BoundPort = boundPort;
  136. port.Host = connectedHost;
  137. port.Port = connectedPort;
  138. this._forwardedPorts.Add(port);
  139. return port;
  140. }
  141. /// <summary>
  142. /// Adds forwarded port to the list bound to "localhost".
  143. /// </summary>
  144. /// <typeparam name="T">Type of forwarded port to add</typeparam>
  145. /// <param name="boundPort">The bound port.</param>
  146. /// <param name="connectedHost">The connected host.</param>
  147. /// <param name="connectedPort">The connected port.</param>
  148. /// <returns></returns>
  149. /// <exception cref="ArgumentNullException"><paramref name="connectedHost"/> is null.</exception>
  150. /// <exception cref="ArgumentException"><paramref name="boundPort"/>, <paramref name="connectedPort"/> or <paramref name="connectedHost"/> is invalid.</exception>
  151. /// <exception cref="ArgumentOutOfRangeException"><paramref name="boundPort"/> or <paramref name="connectedPort"/> is not within <see cref="System.Net.IPEndPoint.MinPort"/> and <see cref="System.Net.IPEndPoint.MaxPort"/>.</exception>
  152. /// <exception cref="Renci.SshNet.Common.SshConnectionException">Client is not connected.</exception>
  153. public T AddForwardedPort<T>(uint boundPort, string connectedHost, uint connectedPort) where T : ForwardedPort, new()
  154. {
  155. return this.AddForwardedPort<T>("localhost", boundPort, connectedHost, connectedPort);
  156. }
  157. /// <summary>
  158. /// Stops and removes the forwarded port from the list.
  159. /// </summary>
  160. /// <param name="port">Forwarded port.</param>
  161. /// <exception cref="ArgumentNullException"><paramref name="port"/> is null.</exception>
  162. public void RemoveForwardedPort(ForwardedPort port)
  163. {
  164. if (port == null)
  165. throw new ArgumentNullException("port");
  166. // Stop port forwarding before removing it
  167. port.Stop();
  168. this._forwardedPorts.Remove(port);
  169. }
  170. /// <summary>
  171. /// Creates the command to be executed.
  172. /// </summary>
  173. /// <param name="commandText">The command text.</param>
  174. /// <returns><see cref="SshCommand"/> object.</returns>
  175. public SshCommand CreateCommand(string commandText)
  176. {
  177. return this.CreateCommand(commandText, Renci.SshNet.Common.ASCIIEncoding.Current);
  178. }
  179. /// <summary>
  180. /// Creates the command to be executed with specified encoding.
  181. /// </summary>
  182. /// <param name="commandText">The command text.</param>
  183. /// <param name="encoding">The encoding to use for results.</param>
  184. /// <returns><see cref="SshCommand"/> object which uses specified encoding.</returns>
  185. public SshCommand CreateCommand(string commandText, Encoding encoding)
  186. {
  187. // Ensure that connection is established.
  188. this.EnsureConnection();
  189. return new SshCommand(this.Session, commandText, encoding);
  190. }
  191. /// <summary>
  192. /// Creates and executes the command.
  193. /// </summary>
  194. /// <param name="commandText">The command text.</param>
  195. /// <returns></returns>
  196. public SshCommand RunCommand(string commandText)
  197. {
  198. var cmd = this.CreateCommand(commandText);
  199. cmd.Execute();
  200. return cmd;
  201. }
  202. /// <summary>
  203. /// Creates the shell.
  204. /// </summary>
  205. /// <param name="input">The input.</param>
  206. /// <param name="output">The output.</param>
  207. /// <param name="extendedOutput">The extended output.</param>
  208. /// <param name="terminalName">Name of the terminal.</param>
  209. /// <param name="columns">The columns.</param>
  210. /// <param name="rows">The rows.</param>
  211. /// <param name="width">The width.</param>
  212. /// <param name="height">The height.</param>
  213. /// <param name="terminalMode">The terminal mode.</param>
  214. /// <param name="bufferSize">Size of the internal read buffer.</param>
  215. /// <returns></returns>
  216. public Shell CreateShell(Stream input, Stream output, Stream extendedOutput, string terminalName, uint columns, uint rows, uint width, uint height, string terminalMode, int bufferSize)
  217. {
  218. // Ensure that connection is established.
  219. this.EnsureConnection();
  220. return new Shell(this.Session, input, output, extendedOutput, terminalName, columns, rows, width, height, terminalMode, bufferSize);
  221. }
  222. /// <summary>
  223. /// Creates the shell.
  224. /// </summary>
  225. /// <param name="input">The input.</param>
  226. /// <param name="output">The output.</param>
  227. /// <param name="extendedOutput">The extended output.</param>
  228. /// <param name="terminalName">Name of the terminal.</param>
  229. /// <param name="columns">The columns.</param>
  230. /// <param name="rows">The rows.</param>
  231. /// <param name="width">The width.</param>
  232. /// <param name="height">The height.</param>
  233. /// <param name="terminalMode">The terminal mode.</param>
  234. /// <returns></returns>
  235. public Shell CreateShell(Stream input, Stream output, Stream extendedOutput, string terminalName, uint columns, uint rows, uint width, uint height, string terminalMode)
  236. {
  237. return this.CreateShell(input, output, extendedOutput, terminalName, columns, rows, width, height, terminalMode, 1024);
  238. }
  239. /// <summary>
  240. /// Creates the shell.
  241. /// </summary>
  242. /// <param name="input">The input.</param>
  243. /// <param name="output">The output.</param>
  244. /// <param name="extendedOutput">The extended output.</param>
  245. /// <returns></returns>
  246. public Shell CreateShell(Stream input, Stream output, Stream extendedOutput)
  247. {
  248. return this.CreateShell(input, output, extendedOutput, string.Empty, 0, 0, 0, 0, string.Empty, 1024);
  249. }
  250. /// <summary>
  251. /// Creates the shell.
  252. /// </summary>
  253. /// <param name="encoding">The encoding to use to send the input.</param>
  254. /// <param name="input">The input.</param>
  255. /// <param name="output">The output.</param>
  256. /// <param name="extendedOutput">The extended output.</param>
  257. /// <param name="terminalName">Name of the terminal.</param>
  258. /// <param name="columns">The columns.</param>
  259. /// <param name="rows">The rows.</param>
  260. /// <param name="width">The width.</param>
  261. /// <param name="height">The height.</param>
  262. /// <param name="terminalMode">The terminal mode.</param>
  263. /// <param name="bufferSize">Size of the internal read buffer.</param>
  264. /// <returns></returns>
  265. public Shell CreateShell(Encoding encoding, string input, Stream output, Stream extendedOutput, string terminalName, uint columns, uint rows, uint width , uint height , string terminalMode, int bufferSize)
  266. {
  267. // Ensure that connection is established.
  268. this.EnsureConnection();
  269. var inputStream = new MemoryStream();
  270. var writer = new StreamWriter(inputStream, encoding);
  271. writer.Write(input);
  272. writer.Flush();
  273. inputStream.Seek(0, SeekOrigin.Begin);
  274. return this.CreateShell(inputStream, output, extendedOutput, terminalName, columns, rows, width, height, terminalMode, bufferSize);
  275. }
  276. /// <summary>
  277. /// Creates the shell.
  278. /// </summary>
  279. /// <param name="encoding">The encoding.</param>
  280. /// <param name="input">The input.</param>
  281. /// <param name="output">The output.</param>
  282. /// <param name="extendedOutput">The extended output.</param>
  283. /// <param name="terminalName">Name of the terminal.</param>
  284. /// <param name="columns">The columns.</param>
  285. /// <param name="rows">The rows.</param>
  286. /// <param name="width">The width.</param>
  287. /// <param name="height">The height.</param>
  288. /// <param name="terminalMode">The terminal mode.</param>
  289. /// <returns></returns>
  290. public Shell CreateShell(Encoding encoding, string input, Stream output, Stream extendedOutput, string terminalName, uint columns, uint rows, uint width, uint height, string terminalMode)
  291. {
  292. return this.CreateShell(encoding, input, output, extendedOutput, terminalName, columns, rows, width, height, terminalMode, 1024);
  293. }
  294. /// <summary>
  295. /// Creates the shell.
  296. /// </summary>
  297. /// <param name="encoding">The encoding.</param>
  298. /// <param name="input">The input.</param>
  299. /// <param name="output">The output.</param>
  300. /// <param name="extendedOutput">The extended output.</param>
  301. /// <returns></returns>
  302. public Shell CreateShell(Encoding encoding, string input, Stream output, Stream extendedOutput)
  303. {
  304. return this.CreateShell(encoding, input, output, extendedOutput, string.Empty, 0, 0, 0, 0, string.Empty, 1024);
  305. }
  306. }
  307. }