Posting at the Zeos Library Forum: www.zeoslib.net Forum Index -> Version 6.x SSH Tunneling ================================================================= Derrick Newbie Newbie Joined: Jun 12, 2003 Posts: 8 ================================================================= Posted: Sat Jun 12, 2004 1:44 am Post subject: SSH Tunneling ================================================================= Is there a pre-developed system for Zeos DBO to establish secure TCP/IP connection with a SSH tunnel to a postgres database on the server? If not, does anyone know how to get that to work using Zeos DBO from the client side? Otherwise, is there a way to get the connection between the client and the server secure using Zeos? Thanks, Derrick ================================================================= Ynexys Member Member Joined: Apr 22, 2004 Posts: 43 ================================================================= Posted: Sun Jun 13, 2004 12:40 am Post subject: I hardly recomend you a software called "Zebedee". ================================================================= Quote: ----------------------------------------------------------------- Zebedee is a simple program to establish an encrypted, compressed “tunnel” for TCP/IP or UDP data transfer between two systems. This allows traffic such as telnet, ftp and X to be protected from snooping as well as potentially gaining performance over low-bandwidth networks from compression. The main goals for Zebedee are to: Provide full client and server functionality under both UNIX/Linux and Windows. Be easy to install, use and maintain with little or no configuration required. Have a small footprint, low wire protocol overhead and give significant traffic reduction by the use of compression. Use only algorithms that are either unpatented or for which the patent has expired. Be entirely free for commercial or non-commercial use and distributed under the term of the GNU General Public Licence. Of course, Zebedee is by no means the first, or only secure tunnel program available. It does not pretend to compete with the likes of ssh, SSL or FreeS/WAN in terms of breadth of function but if you want something quick, simple and completely free then it may be the tool for you. ----------------------------------------------------------------- Url : http://www.winton.org.uk/zebedee/ ================================================================= Derrick Newbie Newbie Joined: Jun 12, 2003 Posts: 8 ================================================================= Posted: Sun Jun 13, 2004 2:55 am Post subject: ================================================================= This looks great. Thank you for the information! Derrick ================================================================= mydeja Member Member Joined: Feb 23, 2004 Posts: 21 ================================================================= Posted: Tue Jun 15, 2004 8:09 am Post subject: ================================================================= You can also use PUTTY from http://www.chiark.greenend.org.uk/~sgtatham/putty/ ================================================================= RayMarron Newbie Newbie Joined: Feb 12, 2004 Posts: 7 Location: Phoenix, Arizona USA ================================================================= Posted: Thu Jun 17, 2004 1:17 am Post subject: ================================================================= I use stunnel (http://www.stunnel.org). On Windows clients, you'll need the OpenSSL binaries (http://www.slproweb.com/products/Win32OpenSSL.html). ================================================================= mvaldez Guest ================================================================= Posted: Wed Aug 11, 2004 6:35 pm Post subject: I use PLink (from puTTY suit) called from Delphi. ================================================================= Hi. Just to share something... My application uses the plink.exe file from the puTTY SSH suit. My application creates the SSH tunnel by calling plink.exe (using ShellExecuteEx and stuff) between localhost and the remote database server. Then, TZConnection tries to connect to localhost (because there is the entrance of the tunnel) several times, waiting half a second between tries (because plink can take a couple of seconds to establish the SSH tunnel ). If succesful, we are done. When the application closes the DB connection (or when exiting), it just call TerminateProcess to shut down Plink and the SSH tunnel. The only note is that the user should have a SSH account in the server. If the user can be trusted, that's ok. But if the user cannot be trusted then the user account should not have an interactive shell. You can set a restricted shell on the server (rbash, rzsh, etc) or better yet, just create a dummy shell for that account. I use a C program with a sleep() inside a while(1), so, even if the user can see the PLink console, it cannot execute anything on the server. Also, before connecting the SSH tunnel, the application checks for running plink.exe processes and ask the user if it should terminate the other plinks or should create a new one. (This is useful if you have several tunnels for differente services). Mario A. Valdez-Ramirez. ================================================================= mvaldez Guest ================================================================= Posted: Wed Aug 11, 2004 6:51 pm Post subject: Other options. ================================================================= Well, I forgot to mention the other options I have tried: Stunnel and Zebedee. Those have been already mentioned by other posters. Well actually I have not tried Zebedee with Zeos but I have with several other apps. And I have tested Stunnel many times with Zeos. But I decided for SSH because: * The option to call a windows executable directly (without user intervention). * SSH is everywhere (Stunnel is second place in ubiquity). * No need to create SSL certificates and other stuff. Regards, Mario A. Valdez-Ramirez. ================================================================= dragos Member Member Joined: Jun 11, 2003 Posts: 10 Location: Tolosa/Gipuzkoa/Spain ================================================================= Posted: Thu Aug 12, 2004 2:34 am Post subject: ================================================================= Like mvaldez I am also using plink.exe (from puTTY) with a ssh server. The difference is that I monitor the output of plink to wait until the tunnel has been established and only then I connect to the DB server. The ssh account also uses a dummy shell (a C program that sleeps for like 15 seconds - time enough for the connection to be established). After the connection is establised the shell terminates, but because of the DB connection the tunnel/plink window remain open. When the DB connection is closed, the plink window closes automatically. And the plink console is a hidden window, so the user will not see it (ShellExecute + SW_HIDE). I have tried using stunnel, but I've encountered problems when reconnecting after disconnections. ================================================================= btrewern Guest ================================================================= Posted: Fri Aug 13, 2004 6:44 pm Post subject: ================================================================= Could someone share some code to get plink.exe up and running. If there is a tutorial somewhere that would be helpful as well. I've had a look at plink but couldn't get it working and ended up loading putty and creating a tunnel with that. (not the best) Regards, Ben ================================================================= mvaldez Guest ================================================================= Posted: Sun Aug 22, 2004 6:10 pm Post subject: Delphi example to lauch PLink for a SSH tunnel... btrewern: This code is part of a bigger application released under the GPL license. To protect your licensing scheme (if you care), I'm releasing this fragment under a MIT license. Feel free to use it to your heart's content in any open-source, closed-source, freeware, commercial or whatever software. Wink The program launches plink.exe with parameters to build a tunnel. By default to tunnel TCP port 3306 from localhost to the remote host. If you want to test it with your application, launch it, make it launch plink.exe and then use any other database application with Zeos to connect to MySQL but set its hostname as "127.0.0.1" (sometimes "localhost" is not good). This code if for a TForm with 3 TLabeledEdits and 5 TButtons. The 3 fields are for Hostname, Username and Password. The buttons are for: launch plink.exe with a visible console, launch it hidden, stop the launched plink process, stop any plink process and to check if there is any plink process. The plink.exe file should be in the same directory. You already have it. If you want all files (dfm, dpr, pas) get them here (4k): http://www.mariovaldez.net/files/launchplink.zip Also, I compiled this on Delphi 6, in Windows 2000. Code: {%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% launchplink. Copyright ©2004 by Mario A. Valdez-Ramirez. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%} unit mainexample; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls; CONST opmC_Def_SSHExe = 'plink.exe'; opmC_Def_SSHUsername = 'sshtunnel'; opmC_Def_SSHPassword = 'tunnel'; opmC_Def_SSHLocalHost = '127.0.0.1'; opmC_Def_SSHRemoteHost = 'wintermute'; opmC_Def_SSHLocalPort = 3306; opmC_Def_SSHCompress = 1; opmC_Def_SSHProtocol = 2; opmC_SSHConnectLapse = 5000; type TForm1 = class(TForm) opm_Button_Start: TButton; opm_Button_Stop: TButton; opm_LabeledEdit_Username: TLabeledEdit; opm_LabeledEdit_Password: TLabeledEdit; opm_LabeledEdit_Hostname: TLabeledEdit; opm_Button_StartHidden: TButton; opm_Button_CheckStall: TButton; opm_Button_StopAny: TButton; procedure FormShow(Sender: TObject); procedure opm_Button_StartClick(Sender: TObject); procedure opm_Button_StartHiddenClick(Sender: TObject); procedure opm_Button_StopClick(Sender: TObject); procedure opm_Button_CheckStallClick(Sender: TObject); procedure opm_Button_StopAnyClick(Sender: TObject); private public end; VAR SSHTunnelHandle : CARDINAL; Form1: TForm1; FUNCTION FNopm_OpenSSHTunnel (SSHLHost, SSHRHost : STRING; SSHLPort, SSHRPort : WORD; SSHUser, SSHPass : STRING; VisibleWindow : INTEGER) : BOOLEAN; FUNCTION FNopm_CheckStallTunnel : BOOLEAN; FUNCTION FNopm_RunExternalApp (ExeFileName, ExeParams, RunDirectory : STRING; ShowApp : BOOLEAN; WaitForIdle : LONGINT): CARDINAL; PROCEDURE PRopm_StopExternalApp (AppHandle : CARDINAL); PROCEDURE PRopm_StopExternalAppByName (AppTitle : STRING); FUNCTION FNopm_IsAppRunning (AppTitle : STRING) : BOOLEAN; implementation {$R *.dfm} USES ShellApi; {%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%} {%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%} FUNCTION FNopm_OpenSSHTunnel (SSHLHost, SSHRHost : STRING; SSHLPort, SSHRPort : WORD; SSHUser, SSHPass : STRING; VisibleWindow : INTEGER) : BOOLEAN; VAR PlinkParams : STRING; BEGIN PLinkParams := '-ssh -' + INTTOSTR (opmC_Def_SSHProtocol); IF (opmC_Def_SSHCompress > 0) THEN PLinkParams := PLinkParams + ' -C'; PLinkParams := PLinkParams + ' -l ' + SSHUser + ' -pw ' + SSHPass; PLinkParams := PLinkParams + ' -L ' + INTTOSTR (SSHLPort) + ':' + SSHLHost + ':' + INTTOSTR (SSHRPort); PLinkParams := PLinkParams + ' ' + SSHRHost + ''; IF (VisibleWindow > 0) THEN BEGIN MessageDlg ('About to execute: ' + ExtractFilePath (Application.Exename) + opmC_Def_SSHExe + ' ' + PLinkParams, mtInformation, [mbOk], 0); SSHTunnelHandle := FNopm_RunExternalApp (ExtractFilePath (Application.Exename) + opmC_Def_SSHExe, PLinkParams, ExtractFilePath (Application.Exename), TRUE, opmC_SSHConnectLapse); END ELSE SSHTunnelHandle := FNopm_RunExternalApp (ExtractFilePath (Application.Exename) + opmC_Def_SSHExe, PLinkParams, ExtractFilePath (Application.Exename), FALSE, opmC_SSHConnectLapse); FNopm_OpenSSHTunnel := (SSHTunnelHandle > 0); END; {%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%} {%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%} FUNCTION FNopm_CheckStallTunnel : BOOLEAN; BEGIN FNopm_CheckStallTunnel := (FNopm_IsAppRunning (opmC_Def_SSHExe) = TRUE); END; {%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%} {%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%} FUNCTION FNopm_RunExternalApp (ExeFileName, ExeParams, RunDirectory : STRING; ShowApp : BOOLEAN; WaitForIdle : LONGINT): CARDINAL; VAR ExeInfo : TShellExecuteInfo; BEGIN ExeInfo.cbSize := SIZEOF (ExeInfo); ExeInfo.fMask := (SEE_MASK_NOCLOSEPROCESS OR SEE_MASK_FLAG_NO_UI); ExeInfo.wnd := Application.Handle; ExeInfo.lpVerb := 'open'; ExeInfo.lpFile := PCHAR (ExeFileName); ExeInfo.lpParameters := PCHAR (ExeParams); ExeInfo.lpDirectory := PCHAR (RunDirectory); IF (ShowApp = FALSE) THEN ExeInfo.nShow := SW_HIDE // SW_SHOWMINNOACTIV ??? ELSE ExeInfo.nShow := SW_SHOWNORMAL; // SW_SHOWDEFAULT ??? IF (ShellExecuteEx (@ExeInfo) = TRUE) THEN BEGIN IF (WaitForIdle > 0) THEN WaitForInputIdle (ExeInfo.hProcess, WaitForIdle); FNopm_RunExternalApp := ExeInfo.hProcess; END ELSE FNopm_RunExternalApp := 0; end; {%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%} {%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%} PROCEDURE PRopm_StopExternalApp (AppHandle : CARDINAL); BEGIN IF (AppHandle > 0) THEN IF (TerminateProcess (AppHandle, ExitCode) = TRUE) THEN CloseHandle (AppHandle); end; {%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%} {%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%} PROCEDURE PRopm_StopExternalAppByName (AppTitle : STRING); VAR WindowHandle: HWND; WindowTitle: ARRAY [0..255] of CHAR; ProcID : CARDINAL; ProcHandle : CARDINAL; BEGIN WindowHandle := GetWindow (Application.Handle, GW_HWNDFIRST); WHILE (WindowHandle > 0) DO BEGIN FillChar (WindowTitle, LENGTH (WindowTitle), #0); GetWindowText (WindowHandle, WindowTitle, LENGTH (WindowTitle) - 1); IF (POS (UPPERCASE (AppTitle), UPPERCASE (STRING (WindowTitle))) > 0) THEN BEGIN GetWindowThreadProcessId (WindowHandle, @ProcID); ProcHandle := OpenProcess (PROCESS_TERMINATE, FALSE, ProcID); TerminateProcess (ProcHandle, 0); CloseHandle (ProcHandle); BREAK; END ELSE WindowHandle := GetWindow (WindowHandle, GW_HWNDNEXT); END; END; {%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%} {%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%} FUNCTION FNopm_IsAppRunning (AppTitle : STRING) : BOOLEAN; VAR WindowHandle: HWND; WindowTitle: ARRAY [0..255] of CHAR; BEGIN FNopm_IsAppRunning := FALSE; WindowHandle := GetWindow (Application.Handle, GW_HWNDFIRST); WHILE (WindowHandle > 0) DO BEGIN FillChar (WindowTitle, LENGTH (WindowTitle), #0); GetWindowText (WindowHandle, WindowTitle, LENGTH (WindowTitle) - 1); IF (POS (UPPERCASE (AppTitle), UPPERCASE (STRING (WindowTitle))) > 0) THEN BEGIN FNopm_IsAppRunning := TRUE; BREAK; END ELSE WindowHandle := GetWindow (WindowHandle, GW_HWNDNEXT); END; END; {%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%} {%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%} procedure TForm1.FormShow(Sender: TObject); begin opm_LabeledEdit_Hostname.Text := opmC_Def_SSHRemoteHost; opm_LabeledEdit_Username.Text := opmC_Def_SSHUsername; opm_LabeledEdit_Password.Text := opmC_Def_SSHPassword; end; {%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%} {%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%} procedure TForm1.opm_Button_StartClick(Sender: TObject); begin IF (MessageDlg ('This test will close any SSH tunnel currently active. Are you sure you want to proceed with the test?', mtWarning, [mbYes, mbNo], 0) = mrYes) THEN BEGIN PRopm_StopExternalAppByName (opmC_Def_SSHExe); IF (FNopm_OpenSSHTunnel (opmC_Def_SSHLocalHost, TRIM (opm_LabeledEdit_Hostname.Text), opmC_Def_SSHLocalPort, opmC_Def_SSHLocalPort, TRIM (opm_LabeledEdit_Username.Text), TRIM (opm_LabeledEdit_Password.Text), 1) = FALSE) THEN BEGIN MessageDlg ('Cannot launch SSH tunnel auxiliar application!', mtWarning, [mbOk], 0); END; END; end; {%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%} {%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%} procedure TForm1.opm_Button_StartHiddenClick(Sender: TObject); begin IF (MessageDlg ('This test will close any SSH tunnel currently active. Are you sure you want to proceed with the test?', mtWarning, [mbYes, mbNo], 0) = mrYes) THEN BEGIN PRopm_StopExternalAppByName (opmC_Def_SSHExe); IF (FNopm_OpenSSHTunnel (opmC_Def_SSHLocalHost, TRIM (opm_LabeledEdit_Hostname.Text), opmC_Def_SSHLocalPort, opmC_Def_SSHLocalPort, TRIM (opm_LabeledEdit_Username.Text), TRIM (opm_LabeledEdit_Password.Text), 0) = FALSE) THEN BEGIN MessageDlg ('Cannot launch SSH tunnel auxiliar application!', mtWarning, [mbOk], 0); END ELSE MessageDlg ('SSH tunnel started. PLink HandleID=' + INTTOSTR (SSHTunnelHandle), mtInformation, [mbOk], 0); END; end; {%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%} {%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%} procedure TForm1.opm_Button_StopClick(Sender: TObject); begin PRopm_StopExternalApp (SSHTunnelHandle); SSHTunnelHandle := 0; end; {%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%} {%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%} procedure TForm1.opm_Button_StopAnyClick(Sender: TObject); begin PRopm_StopExternalAppByName (opmC_Def_SSHExe); SSHTunnelHandle := 0; end; {%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%} {%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%} procedure TForm1.opm_Button_CheckStallClick(Sender: TObject); begin IF (FNopm_IsAppRunning (opmC_Def_SSHExe) = TRUE) THEN MessageDlg ('PLink is running!', mtInformation, [mbOk], 0) ELSE MessageDlg ('PLink is not running.', mtInformation, [mbOk], 0); end; end. I think the approach taken by dragos is better (to capture the plink.exe output). Also, please note that when you try to connect for the first time to a given host, plink will check in the Registry to see if it is a known server, if it isn't, it will ask the user to confirm that he/she wants to connect. This happens the first time only, but if the user cannot confirm (if you launch plink hidden) then the connection won't be completed. Regards, Mario A. Valdez-Ramirez. ================================================================= Guest ================================================================= Posted: Mon Aug 23, 2004 7:40 am Post subject: ================================================================= Wow, I wasn't expecting quite such a 'code fragment'. Smile It'll take me a minute or two to look through this. Thanks, Ben