Mega Code Archive

 
Categories / Delphi / Examples
 

SSH and SCP Class using Putty

Title: SSH and SCP Class using Putty Question: SSH and SCP are widely used on Linux and Unix platforms as replacements for REXEC and FTP, which are normally disabled. Answer: Finding a free component for Intel SSH on the web proved fruitless at this moment in time as all workable ones found come at a price. There is however free executables PLINK.EXE and PSCP.EXE available from Putty. These work very well and I decided to write a Delphi class to encapsulate them. You obviously need to distribute them with your application. The code is for Delphi 2010 and uses my WinMisc and Files class. You can implement your own WinMisc.ExecuteConsolePipe() and Files.CreateUnique(), or you can E-Mail me and I will send you the source of MW_WinMisc and MW_Files. The code should not be too difficult to port to lower Delphi versions. unit MW_PuttySSH; interface {$REGION 'Documentation'} // ================================================================================================= // UltraRAD Components // Mike Heydon 2010 // // MW_PuttySSH - Class to implement SSH scp and rexec using Putty PSCP and PLINK // // pscp command example // pscp -l oracle -pw ora123 192.168.0.112:"c:/eoh_logs/Shutdown*.log" "c:/ssh_tools" // // ================================================================================================= {$ENDREGION} uses Windows, Forms, SysUtils, Controls, Classes, MW_WinMisc, MW_Files; {$REGION 'Types and Classes'} type TPuttySSH = class(TComponent) public type TProtocolVersion = (pvDefault,pvSSH1,pvSSH2); private const C_TEST = '%spscp -l %s -pw %s -ls "%s:/"'; strict private FExecCommand, FRemoteFile,FLocalFile, FSSHToolspath, FRemoteHost,FUser,FPassword : string; FProtocolVersion : TProtocolVersion; FPrivateKeyFile : TFileName; FPort : integer; protected procedure _CheckFile(const AFile : string); procedure _Put(AResults : TStrings; AIsDir : boolean); procedure _Get(AResults : TStrings; AIsDir : boolean); public constructor Create(AOwner : TComponent); override; procedure Get(AResults : TStrings; ARecurse : boolean = false); procedure Put(AResults : TStrings; ARecurse : boolean = false); procedure Execute(AResults : TStrings); procedure Directory(const ADirectoryPath : string; AResults : TStrings); procedure TestConnection; published property SSHToolsPath : string read FSSHToolsPath write FSSHToolsPath; property RemoteHost : string read FRemoteHost write FRemoteHost; property User : string read FUser write FUser; property Password : string read FPassword write FPassword; property RemoteFile : string read FRemoteFile write FRemoteFile; property LocalFile : string read FLocalFile write FLocalFile; property ExecCommand : string read FExecCommand write FExecCommand; property ProtocolVersion : TProtocolVersion read FProtocolVersion write FProtocolversion; property PrivateKeyFile : TFileName read FPrivateKeyFile write FPrivateKeyFile; property Port : integer read FPort write FPort; end; {$ENDREGION} // ------------------------------------------------------------------------------------------------- implementation {$REGION 'PuttySSH Class'} constructor TPuttySSH.Create(AOwner : TComponent); begin inherited Create(AOwner); FSSHToolsPath := 'C:\SSH_TOOLS'; FRemoteHost := ''; FUser := ''; FPassword := ''; FProtocolVersion := pvDefault; FPrivateKeyFile := ''; FRemoteFile := ''; FLocalFile := ''; FExecCommand := ''; FPort := 22; end; procedure TPuttySSH._CheckFile(const AFile : string); var sFile : string; begin sFile := IncludeTrailingPathDelimiter(FSSHToolsPath) + AFile; if not FileExists(sFile) then raise Exception.Create('Cannot find file ' + sFile); end; procedure TPuttySSH._Put(AResults : TStrings; AIsDir : boolean); var oResults : TStringList; sCommand : string; begin _CheckFile('PSCP.EXE'); sCommand := '"' + IncludeTrailingPathDelimiter(FSSHToolsPath) + 'PSCP"'; if FUser '' then sCommand := sCommand + ' -l ' + Fuser; if FPassword '' then sCommand := sCommand + ' -pw ' + FPassword; if FPrivateKeyFile '' then sCommand := sCommand + ' -i "' + FPrivateKeyFile + '"'; if FPort 22 then sCommand := sCommand + ' -P ' + IntTostr(FPort); if AIsDir then sCommand := sCommand + ' -r'; case FprotocolVersion of pvSSH1 : sCommand := sCommand + ' -1'; pvSSH2 : sCommand := sCommand + ' -2'; end; sCommand := sCommand + ' -batch "' + FLocalFile + '" '; sCommand := sCommand + FRemoteHost + ':"' + FRemoteFile + '"'; Screen.Cursor := crHourGlass; if Assigned(AResults) then WinMisc.ExecConsolePipe(sCommand,AResults) else begin oResults := tStringList.Create; WinMisc.ExecConsolePipe(sCommand,oResults); FreeAndNil(oResults); end; Screen.Cursor := crDefault; end; procedure TPuttySSH._Get(AResults : TStrings; AIsDir : boolean); var oResults : TStringList; sCommand : string; begin _CheckFile('PSCP.EXE'); sCommand := '"' + IncludeTrailingPathDelimiter(FSSHToolsPath) + 'PSCP"'; if FUser '' then sCommand := sCommand + ' -l ' + Fuser; if FPassword '' then sCommand := sCommand + ' -pw ' + FPassword; if FPrivateKeyFile '' then sCommand := sCommand + ' -i "' + FPrivateKeyFile + '"'; if FPort 22 then sCommand := sCommand + ' -P ' + IntTostr(FPort); if AIsDir then sCommand := sCommand + ' -r'; case FprotocolVersion of pvSSH1 : sCommand := sCommand + ' -1'; pvSSH2 : sCommand := sCommand + ' -2'; end; sCommand := sCommand + ' -batch ' + FRemoteHost + ':"' + FRemoteFile + '"'; sCommand := sCommand + ' "' + LocalFile + '"'; Screen.Cursor := crHourGlass; if Assigned(AResults) then WinMisc.ExecConsolePipe(sCommand,AResults) else begin oResults := tStringList.Create; WinMisc.ExecConsolePipe(sCommand,oResults); FreeAndNil(oResults); end; Screen.Cursor := crDefault; end; procedure TPuttySSH.Get(AResults : TStrings; ARecurse : boolean = false); begin _Get(AResults,ARecurse); end; procedure TPuttySSH.Put(AResults : TStrings; ARecurse : boolean = false); begin _Put(AResults,ARecurse); end; procedure TPuttySSH.Directory(const ADirectoryPath : string; AResults : TStrings); var sCommand : string; begin _CheckFile('PSCP.EXE'); sCommand := '"' + IncludeTrailingPathDelimiter(FSSHToolsPath) + 'PSCP"'; if FUser '' then sCommand := sCommand + ' -l ' + Fuser; if FPassword '' then sCommand := sCommand + ' -pw ' + FPassword; if FPrivateKeyFile '' then sCommand := sCommand + ' -i "' + FPrivateKeyFile + '"'; if FPort 22 then sCommand := sCommand + ' -P ' + IntTostr(FPort); case FprotocolVersion of pvSSH1 : sCommand := sCommand + ' -1'; pvSSH2 : sCommand := sCommand + ' -2'; end; sCommand := sCommand + ' -batch -ls ' + FRemoteHost + ':"' + ADirectoryPath + '"'; Screen.Cursor := crHourGlass; WinMisc.ExecConsolePipe(sCommand,AResults); Screen.Cursor := crDefault; end; procedure TPuttySSH.TestConnection; var fBatch : TextFile; sBatch : string; iExit : longword; begin sBatch := Files.CreateUnique(); sBatch := ChangeFileExt(sBatch,'.cmd'); AssignFile(fBatch,sBatch); Rewrite(fBatch); WriteLn(fBatch,'echo off'); WriteLn(fBatch,'cls'); WriteLn(fBatch,'echo Testing SSH Connectivity to ' + FRemoteHost + ' ...'); WriteLn(fBatch,Format(C_TEST,[IncludeTrailingPathDelimiter(FSSHToolsPath),FUser, FPassword,FRemoteHost])); WriteLn(fBatch,'echo.'); WriteLn(fBatch,'echo If SSH Connectivity is working, you should see a dir listing.'); WriteLn(fBatch,'echo.'); WriteLn(fBatch,'pause'); CloseFile(fBatch); WinMisc.Execute(sBatch,iExit,'','',true); sleep(100); DeleteFile(sBatch); end; procedure TPuttySSH.Execute(AResults : TStrings); var oResults : TStringList; sCommand : string; begin _CheckFile('PLINK.EXE'); sCommand := '"' + IncludeTrailingPathDelimiter(FSSHToolsPath) + 'PLINK"'; if FUser '' then sCommand := sCommand + ' -l ' + Fuser; if FPassword '' then sCommand := sCommand + ' -pw ' + FPassword; if FPrivateKeyFile '' then sCommand := sCommand + ' -i "' + FPrivateKeyFile + '"'; if FPort 22 then sCommand := sCommand + ' -P ' + IntTostr(FPort); case FprotocolVersion of pvSSH1 : sCommand := sCommand + ' -1'; pvSSH2 : sCommand := sCommand + ' -2'; end; sCommand := sCommand + ' -ssh -batch ' + FRemoteHost + ' "' + FExecCommand + '"'; Screen.Cursor := crHourGlass; if Assigned(AResults) then WinMisc.ExecConsolePipe(sCommand,AResults) else begin oResults := tStringList.Create; WinMisc.ExecConsolePipe(sCommand,oResults); FreeAndNil(oResults); end; Screen.Cursor := crDefault; end; {$ENDREGION} end.