ssl_libssh2.pas 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. {==============================================================================|
  2. | Project : Ararat Synapse | 001.000.000 |
  3. |==============================================================================|
  4. | Content: SSH support by LibSSH2 |
  5. |==============================================================================|
  6. | Copyright (c)1999-2013, Lukas Gebauer |
  7. | All rights reserved. |
  8. | |
  9. | Redistribution and use in source and binary forms, with or without |
  10. | modification, are permitted provided that the following conditions are met: |
  11. | |
  12. | Redistributions of source code must retain the above copyright notice, this |
  13. | list of conditions and the following disclaimer. |
  14. | |
  15. | Redistributions in binary form must reproduce the above copyright notice, |
  16. | this list of conditions and the following disclaimer in the documentation |
  17. | and/or other materials provided with the distribution. |
  18. | |
  19. | Neither the name of Lukas Gebauer nor the names of its contributors may |
  20. | be used to endorse or promote products derived from this software without |
  21. | specific prior written permission. |
  22. | |
  23. | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
  24. | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
  25. | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
  26. | ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR |
  27. | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
  28. | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
  29. | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
  30. | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
  31. | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
  32. | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
  33. | DAMAGE. |
  34. |==============================================================================|
  35. | The Initial Developer of the Original Code is Alexey Suhinin. |
  36. | Portions created by Alexey Suhinin are Copyright (c)2012-2013. |
  37. | Portions created by Lukas Gebauer are Copyright (c)2013-2013. |
  38. | All Rights Reserved. |
  39. |==============================================================================|
  40. | Contributor(s): |
  41. |==============================================================================|
  42. | History: see HISTORY.HTM from distribution package |
  43. | (Found at URL: http://www.ararat.cz/synapse/) |
  44. |==============================================================================}
  45. //requires LibSSH2 libraries! http://libssh2.org
  46. {:@abstract(SSH plugin for LibSSH2)
  47. Requires libssh2.dll or libssh2.so.
  48. You can download binaries as part of the CURL project from
  49. http://curl.haxx.se/download.html
  50. You need Pascal bindings for the library too! You can find one at:
  51. http://www.lazarus.freepascal.org/index.php/topic,15935.msg86465.html#msg86465
  52. This plugin implements the client part only.
  53. }
  54. {$IFDEF FPC}
  55. {$MODE DELPHI}
  56. {$ENDIF}
  57. {$H+}
  58. unit ssl_libssh2;
  59. interface
  60. uses
  61. SysUtils,
  62. blcksock, synsock,
  63. libssh2;
  64. type
  65. {:@abstract(class implementing LibSSH2 SSH plugin.)
  66. Instance of this class will be created for each @link(TTCPBlockSocket).
  67. You not need to create instance of this class, all is done by Synapse itself!}
  68. TSSLLibSSH2 = class(TCustomSSL)
  69. protected
  70. FSession: PLIBSSH2_SESSION;
  71. FChannel: PLIBSSH2_CHANNEL;
  72. function SSHCheck(Value: integer): Boolean;
  73. function DeInit: Boolean;
  74. public
  75. {:See @inherited}
  76. constructor Create(const Value: TTCPBlockSocket); override;
  77. destructor Destroy; override;
  78. {:See @inherited}
  79. function LibVersion: String; override;
  80. {:See @inherited}
  81. function LibName: String; override;
  82. {:See @inherited}
  83. function Connect: boolean; override;
  84. {:See @inherited}
  85. function Shutdown: boolean; override;
  86. {:See @inherited}
  87. function BiShutdown: boolean; override;
  88. {:See @inherited}
  89. function SendBuffer(Buffer: TMemory; Len: Integer): Integer; override;
  90. {:See @inherited}
  91. function RecvBuffer(Buffer: TMemory; Len: Integer): Integer; override;
  92. {:See @inherited}
  93. function WaitingData: Integer; override;
  94. {:See @inherited}
  95. function GetSSLVersion: string; override;
  96. published
  97. end;
  98. implementation
  99. {==============================================================================}
  100. function TSSLLibSSH2.SSHCheck(Value: integer): Boolean;
  101. var
  102. PLastError: PAnsiChar;
  103. ErrMsgLen: Integer;
  104. begin
  105. Result := true;
  106. FLastError := 0;
  107. FLastErrorDesc := '';
  108. if Value<0 then
  109. begin
  110. FLastError := libssh2_session_last_error(FSession, PLastError, ErrMsglen, 0);
  111. FLastErrorDesc := PLastError;
  112. Result := false;
  113. end;
  114. end;
  115. function TSSLLibSSH2.DeInit: Boolean;
  116. begin
  117. if Assigned(FChannel) then
  118. begin
  119. libssh2_channel_free(FChannel);
  120. FChannel := nil;
  121. end;
  122. if Assigned(FSession) then
  123. begin
  124. libssh2_session_disconnect(FSession,'Goodbye');
  125. libssh2_session_free(FSession);
  126. FSession := nil;
  127. end;
  128. FSSLEnabled := False;
  129. Result := true;
  130. end;
  131. constructor TSSLLibSSH2.Create(const Value: TTCPBlockSocket);
  132. begin
  133. inherited Create(Value);
  134. FSession := nil;
  135. FChannel := nil;
  136. end;
  137. destructor TSSLLibSSH2.Destroy;
  138. begin
  139. DeInit;
  140. inherited Destroy;
  141. end;
  142. function TSSLLibSSH2.Connect: boolean;
  143. begin
  144. Result := False;
  145. if SSLEnabled then DeInit;
  146. if (FSocket.Socket <> INVALID_SOCKET) and (FSocket.SSL.SSLType = LT_SSHv2) then
  147. begin
  148. FSession := libssh2_session_init();
  149. if not Assigned(FSession) then
  150. begin
  151. FLastError := -999;
  152. FLastErrorDesc := 'Cannot initialize SSH session';
  153. exit;
  154. end;
  155. if not SSHCheck(libssh2_session_startup(FSession, FSocket.Socket)) then
  156. exit;
  157. // Attempt private key authentication, then fall back to username/password but
  158. // do not forget original private key auth error. This avoids giving spurious errors like
  159. // Authentication failed (username/password)
  160. // instead of e.g.
  161. // Unable to extract public key from private key file: Method unimplemented in libgcrypt backend
  162. if FSocket.SSL.PrivateKeyFile<>'' then
  163. if (not SSHCheck(libssh2_userauth_publickey_fromfile(FSession, PChar(FSocket.SSL.Username), nil, PChar(FSocket.SSL.PrivateKeyFile), PChar(FSocket.SSL.KeyPassword))))
  164. and (libssh2_userauth_password(FSession, PChar(FSocket.SSL.Username), PChar(FSocket.SSL.Password))<0) then
  165. exit;
  166. FChannel := libssh2_channel_open_session(FSession);
  167. if not assigned(FChannel) then
  168. begin
  169. // SSHCheck(-1);
  170. FLastError:=-999;
  171. FLastErrorDesc := 'Cannot open session';
  172. exit;
  173. end;
  174. if not SSHCheck(libssh2_channel_request_pty(FChannel, 'vanilla')) then
  175. exit;
  176. if not SSHCheck(libssh2_channel_shell(FChannel)) then
  177. exit;
  178. FSSLEnabled := True;
  179. Result := True;
  180. end;
  181. end;
  182. function TSSLLibSSH2.LibName: String;
  183. begin
  184. Result := 'ssl_libssh2';
  185. end;
  186. function TSSLLibSSH2.Shutdown: boolean;
  187. begin
  188. Result := DeInit;
  189. end;
  190. function TSSLLibSSH2.BiShutdown: boolean;
  191. begin
  192. Result := DeInit;
  193. end;
  194. function TSSLLibSSH2.SendBuffer(Buffer: TMemory; Len: Integer): Integer;
  195. begin
  196. Result:=libssh2_channel_write(FChannel, PAnsiChar(Buffer), Len);
  197. SSHCheck(Result);
  198. end;
  199. function TSSLLibSSH2.RecvBuffer(Buffer: TMemory; Len: Integer): Integer;
  200. begin
  201. result:=libssh2_channel_read(FChannel, PAnsiChar(Buffer), Len);
  202. SSHCheck(Result);
  203. end;
  204. function TSSLLibSSH2.WaitingData: Integer;
  205. begin
  206. if libssh2_poll_channel_read(FChannel, Result) <> 1 then
  207. Result := 0;
  208. end;
  209. function TSSLLibSSH2.GetSSLVersion: string;
  210. begin
  211. Result := 'SSH2';
  212. end;
  213. function TSSLLibSSH2.LibVersion: String;
  214. begin
  215. Result := libssh2_version(0);
  216. end;
  217. initialization
  218. if libssh2_init(0)=0 then
  219. SSLImplementation := TSSLLibSSH2;
  220. finalization
  221. libssh2_exit;
  222. end.