tlntsend.pas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. {==============================================================================|
  2. | Project : Ararat Synapse | 001.003.000 |
  3. |==============================================================================|
  4. | Content: TELNET and SSH2 client |
  5. |==============================================================================|
  6. | Copyright (c)1999-2008, 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 Lukas Gebauer (Czech Republic).|
  36. | Portions created by Lukas Gebauer are Copyright (c)2002-2008. |
  37. | All Rights Reserved. |
  38. |==============================================================================|
  39. | Contributor(s): |
  40. |==============================================================================|
  41. | History: see HISTORY.HTM from distribution package |
  42. | (Found at URL: http://www.ararat.cz/synapse/) |
  43. |==============================================================================}
  44. {:@abstract(Telnet script client)
  45. Used RFC: RFC-854
  46. }
  47. {$IFDEF FPC}
  48. {$MODE DELPHI}
  49. {$ENDIF}
  50. {$H+}
  51. unit tlntsend;
  52. interface
  53. uses
  54. SysUtils, Classes,
  55. blcksock, synautil;
  56. const
  57. cTelnetProtocol = '23';
  58. cSSHProtocol = '22';
  59. TLNT_EOR = #239;
  60. TLNT_SE = #240;
  61. TLNT_NOP = #241;
  62. TLNT_DATA_MARK = #242;
  63. TLNT_BREAK = #243;
  64. TLNT_IP = #244;
  65. TLNT_AO = #245;
  66. TLNT_AYT = #246;
  67. TLNT_EC = #247;
  68. TLNT_EL = #248;
  69. TLNT_GA = #249;
  70. TLNT_SB = #250;
  71. TLNT_WILL = #251;
  72. TLNT_WONT = #252;
  73. TLNT_DO = #253;
  74. TLNT_DONT = #254;
  75. TLNT_IAC = #255;
  76. type
  77. {:@abstract(State of telnet protocol). Used internaly by TTelnetSend.}
  78. TTelnetState =(tsDATA, tsIAC, tsIAC_SB, tsIAC_WILL, tsIAC_DO, tsIAC_WONT,
  79. tsIAC_DONT, tsIAC_SBIAC, tsIAC_SBDATA, tsSBDATA_IAC);
  80. {:@abstract(Class with implementation of Telnet/SSH script client.)
  81. Note: Are you missing properties for specify server address and port? Look to
  82. parent @link(TSynaClient) too!}
  83. TTelnetSend = class(TSynaClient)
  84. private
  85. FSock: TTCPBlockSocket;
  86. FBuffer: Ansistring;
  87. FState: TTelnetState;
  88. FSessionLog: Ansistring;
  89. FSubNeg: Ansistring;
  90. FSubType: Ansichar;
  91. FTermType: Ansistring;
  92. function Connect: Boolean;
  93. function Negotiate(const Buf: Ansistring): Ansistring;
  94. procedure FilterHook(Sender: TObject; var Value: AnsiString);
  95. public
  96. constructor Create;
  97. destructor Destroy; override;
  98. {:Connects to Telnet server.}
  99. function Login: Boolean;
  100. {:Connects to SSH2 server and login by Username and Password properties.
  101. You must use some of SSL plugins with SSH support. For exammple CryptLib.}
  102. function SSHLogin: Boolean;
  103. {:Logout from telnet server.}
  104. procedure Logout;
  105. {:Send this data to telnet server.}
  106. procedure Send(const Value: string);
  107. {:Reading data from telnet server until Value is readed. If it is not readed
  108. until timeout, result is @false. Otherwise result is @true.}
  109. function WaitFor(const Value: string): Boolean;
  110. {:Read data terminated by terminator from telnet server.}
  111. function RecvTerminated(const Terminator: string): string;
  112. {:Read string from telnet server.}
  113. function RecvString: string;
  114. published
  115. {:Socket object used for TCP/IP operation. Good for seting OnStatus hook, etc.}
  116. property Sock: TTCPBlockSocket read FSock;
  117. {:all readed datas in this session (from connect) is stored in this large
  118. string.}
  119. property SessionLog: Ansistring read FSessionLog write FSessionLog;
  120. {:Terminal type indentification. By default is 'SYNAPSE'.}
  121. property TermType: Ansistring read FTermType write FTermType;
  122. end;
  123. implementation
  124. constructor TTelnetSend.Create;
  125. begin
  126. inherited Create;
  127. FSock := TTCPBlockSocket.Create;
  128. FSock.OnReadFilter := FilterHook;
  129. FTimeout := 60000;
  130. FTargetPort := cTelnetProtocol;
  131. FSubNeg := '';
  132. FSubType := #0;
  133. FTermType := 'SYNAPSE';
  134. end;
  135. destructor TTelnetSend.Destroy;
  136. begin
  137. FSock.Free;
  138. inherited Destroy;
  139. end;
  140. function TTelnetSend.Connect: Boolean;
  141. begin
  142. // Do not call this function! It is calling by LOGIN method!
  143. FBuffer := '';
  144. FSessionLog := '';
  145. FState := tsDATA;
  146. FSock.CloseSocket;
  147. FSock.LineBuffer := '';
  148. FSock.Bind(FIPInterface, cAnyPort);
  149. FSock.Connect(FTargetHost, FTargetPort);
  150. Result := FSock.LastError = 0;
  151. end;
  152. function TTelnetSend.RecvTerminated(const Terminator: string): string;
  153. begin
  154. Result := FSock.RecvTerminated(FTimeout, Terminator);
  155. end;
  156. function TTelnetSend.RecvString: string;
  157. begin
  158. Result := FSock.RecvTerminated(FTimeout, CRLF);
  159. end;
  160. function TTelnetSend.WaitFor(const Value: string): Boolean;
  161. begin
  162. Result := FSock.RecvTerminated(FTimeout, Value) <> '';
  163. end;
  164. procedure TTelnetSend.FilterHook(Sender: TObject; var Value: AnsiString);
  165. begin
  166. Value := Negotiate(Value);
  167. FSessionLog := FSessionLog + Value;
  168. end;
  169. function TTelnetSend.Negotiate(const Buf: Ansistring): Ansistring;
  170. var
  171. n: integer;
  172. c: Ansichar;
  173. Reply: Ansistring;
  174. SubReply: Ansistring;
  175. begin
  176. Result := '';
  177. for n := 1 to Length(Buf) do
  178. begin
  179. c := Buf[n];
  180. Reply := '';
  181. case FState of
  182. tsData:
  183. if c = TLNT_IAC then
  184. FState := tsIAC
  185. else
  186. Result := Result + c;
  187. tsIAC:
  188. case c of
  189. TLNT_IAC:
  190. begin
  191. FState := tsData;
  192. Result := Result + TLNT_IAC;
  193. end;
  194. TLNT_WILL:
  195. FState := tsIAC_WILL;
  196. TLNT_WONT:
  197. FState := tsIAC_WONT;
  198. TLNT_DONT:
  199. FState := tsIAC_DONT;
  200. TLNT_DO:
  201. FState := tsIAC_DO;
  202. TLNT_EOR:
  203. FState := tsDATA;
  204. TLNT_SB:
  205. begin
  206. FState := tsIAC_SB;
  207. FSubType := #0;
  208. FSubNeg := '';
  209. end;
  210. else
  211. FState := tsData;
  212. end;
  213. tsIAC_WILL:
  214. begin
  215. case c of
  216. #3: //suppress GA
  217. Reply := TLNT_DO;
  218. else
  219. Reply := TLNT_DONT;
  220. end;
  221. FState := tsData;
  222. end;
  223. tsIAC_WONT:
  224. begin
  225. Reply := TLNT_DONT;
  226. FState := tsData;
  227. end;
  228. tsIAC_DO:
  229. begin
  230. case c of
  231. #24: //termtype
  232. Reply := TLNT_WILL;
  233. else
  234. Reply := TLNT_WONT;
  235. end;
  236. FState := tsData;
  237. end;
  238. tsIAC_DONT:
  239. begin
  240. Reply := TLNT_WONT;
  241. FState := tsData;
  242. end;
  243. tsIAC_SB:
  244. begin
  245. FSubType := c;
  246. FState := tsIAC_SBDATA;
  247. end;
  248. tsIAC_SBDATA:
  249. begin
  250. if c = TLNT_IAC then
  251. FState := tsSBDATA_IAC
  252. else
  253. FSubNeg := FSubNeg + c;
  254. end;
  255. tsSBDATA_IAC:
  256. case c of
  257. TLNT_IAC:
  258. begin
  259. FState := tsIAC_SBDATA;
  260. FSubNeg := FSubNeg + c;
  261. end;
  262. TLNT_SE:
  263. begin
  264. SubReply := '';
  265. case FSubType of
  266. #24: //termtype
  267. begin
  268. if (FSubNeg <> '') and (FSubNeg[1] = #1) then
  269. SubReply := #0 + FTermType;
  270. end;
  271. end;
  272. Sock.SendString(TLNT_IAC + TLNT_SB + FSubType + SubReply + TLNT_IAC + TLNT_SE);
  273. FState := tsDATA;
  274. end;
  275. else
  276. FState := tsDATA;
  277. end;
  278. else
  279. FState := tsData;
  280. end;
  281. if Reply <> '' then
  282. Sock.SendString(TLNT_IAC + Reply + c);
  283. end;
  284. end;
  285. procedure TTelnetSend.Send(const Value: string);
  286. begin
  287. Sock.SendString(ReplaceString(Value, TLNT_IAC, TLNT_IAC + TLNT_IAC));
  288. end;
  289. function TTelnetSend.Login: Boolean;
  290. begin
  291. Result := False;
  292. if not Connect then
  293. Exit;
  294. Result := True;
  295. end;
  296. function TTelnetSend.SSHLogin: Boolean;
  297. begin
  298. Result := False;
  299. if Connect then
  300. begin
  301. FSock.SSL.SSLType := LT_SSHv2;
  302. FSock.SSL.Username := FUsername;
  303. FSock.SSL.Password := FPassword;
  304. FSock.SSLDoConnect;
  305. Result := FSock.LastError = 0;
  306. end;
  307. end;
  308. procedure TTelnetSend.Logout;
  309. begin
  310. FSock.CloseSocket;
  311. end;
  312. end.