Protecting MySQL Sessions With SSH Port Forwarding (Part 2)
Introduction
In my last article, I described how to secure connections to a MySQL server using SSH port forwarding (or SSH tunneling). Responses to the article included requests for information on connecting to an SSH server running under Windows and instructions on closing a tunnel opened from within Visual Basic. In this article I will show how to use the OpenSSH For Windows tool to host SSH tunnels on a Windows server, and will also cover how to use the shellexecuteex, terminateprocess and closeHandle API calls to open and close an SSH tunnel from within VB. The instructions given will be based on a Windows 2000 installation, but should be adaptable to any NT based system.
SSH For Windows
One of the advantages of the OpenSSH project is that it is designed for portability and variations exist for a variety of platforms. Michael Johnson maintains a Windows version of OpenSSH at http://lexa.mckenna.edu/sshwindows/ which I will be using in this article. OpenSSH for Windows can be downloaded at http://lexa.mckenna.edu/sshwindows/download/releases/
OpenSSH uses components from the Cygwin project, a Linux emulator that runs on most varieties of Windows. It should be noted that OpenSSH for Windows does not create a full Cygwin installation, and will not be compatible with systems that have Cygwin already installed.
Installing SSH For Windows
Once you download and extract the OpenSSH zip archive at http://lexa.mckenna.edu/sshwindows/download/releases/ you will have a single executable with a name like setupssh371-20031015.exe which you can double-click to install OpenSSH for Windows on your system. I would recommend installing OpenSSH to the default location of c:\program files\openssh.
Creating An NT User
OpenSSH for Windows relies on the Windows NT authentication system to validate users, and as such we need to create an NT user for OpenSSH to validate against.
Open the control panel with Start > Settings > Control Panel and double-click on the Users And Passwords icon. If you login automatically without specifying a password you will find most of the form grayed out, but you can gain access to the controls by checking the box titled “Users must enter a user name and password to access this computer.”

We will need to create a user which has password-protected access to the system. If you do not plan to do anything beyond opening SSH tunnels with the account then creating a user with Guest-level permissions will be adequate. In this case I will be creating a user named ‘tunnel’ as a member of the guests group. You can create a new user by clicking the Add… button on the Users and Passwords panel.
Configuring The passwd And group Files
Configuration for OpenSSH For Windows is done through the command shell. To open a command shell select Start > Run… then enter cmd in the dialogue box and click Ok. Once in the command shell enter the following:
cd c:\program files\openssh\bin mkgroup -l >> ..\etc\group
This command will add your user groups (Administrator, Guests, etc.) to the openssh\etc\group file. Please note that this will import local groups only. If your NT security is based on a domain controller you will need to reference the openssh\docs\readme.txt file for instructions on using domain users and groups.
Once your groups are imported you can use the following command to import users into the openssh\etc\passwd file:
mkpasswd -l -u tunnel >> ..\etc\passwd
This will import the tunnel user into the passwd file. While you can import all Windows users at once by omitting the -u argument and username, I would recommend only importing the specific users you intend to use for SSH access.
Starting The Server
Once our server is configured we can start the OpenSSH server with the following command:
net start opensshd
We can also use the services manager to start the OpenSSH server and configure it to start when the system is booting. Right-click on the My Computer icon on the desktop and select Manage from the context menu. You can then see a list of available services by choosing the Services entry of the Services And Applications tree.
You can then right-click on the OpenSSH Server entry and choose the Start option to start the OpenSSH server. You can also choose the Properties option and change the Startup type: option from Manual to Automatic to have OpenSSH start during your server’s boot sequence.
Once your server is running you can then connect using tools like Putty and Plink as discussed in my previous article.
Opening And Closing Tunnels In Visual Basic
In my previous article I discussed how to open a tunnel in Visual Basic using the Plink utility and the shellexecute API call. While this worked quite well for opening SSH tunnels, I failed to cover how to close the tunnels from within VB. In order to open and also close tunnels from within Visual Basic we’ll be using the shellexecuteex, terminateprocess, and closeHandle API calls.
For this project I am going to split the API calls into a separate module that will contain the following:
Option Explicit
Dim si As SHELLEXECUTEINFO
Private Sub cmdClose_Click()
Dim exitCode As Long
If TerminateProcess(si.hProcess, exitCode) <> 0 Then
CloseHandle (si.hProcess)
MsgBox "Tunnel Closed!"
End If
End Sub
Private Sub cmdOpen_Click()
si.cbSize = Len(si)
si.fMask = SEE_MASK_NOCLOSEPROCESS
si.hwnd = frmMain.hwnd
si.lpVerb = "open"
si.lpFile = App.Path & "\plink.exe"
si.lpParameters = "-ssh -l tunnel -pw 123456 -L 3306:127.0.0.1:3306 -batch 127.0.0.1"
si.lpDirectory = App.Path
si.nShow = SW_HIDE
If ShellExecuteEx(si) Then
MsgBox "Tunnel Open!"
Else
MsgBox "Opening Failed!"
End If
End Sub
In addition I will create a form with two command buttons named cmdOpen and cmdClose (see attached project). These buttons will handle the actual opening and closing of the tunnel. Place the following code in your form:
Option Explicit
Dim si As SHELLEXECUTEINFO
Private Sub cmdClose_Click()
Dim exitCode As Long
If TerminateProcess(si.hProcess, exitCode) <> 0 Then
CloseHandle (si.hProcess)
MsgBox "Tunnel Closed!"
End If
End Sub
Private Sub cmdOpen_Click()
si.cbSize = Len(si)
si.fMask = SEE_MASK_NOCLOSEPROCESS
si.hwnd = frmMain.hwnd
si.lpVerb = "open"
si.lpFile = App.Path & "\plink.exe"
si.lpParameters = "-ssh -l tunnel -pw 123456 -L 3306:127.0.0.1:3306 -batch 127.0.0.1"
si.lpDirectory = App.Path
si.nShow = SW_HIDE
If ShellExecuteEx(si) Then
MsgBox "Tunnel Open!"
Else
MsgBox "Opening Failed!"
End If
End Sub
This code will open the Plink tunnel and store it’s process ID in si.hProcess, allowing us to later kill the process by referencing it’s process ID with the TerminateProcess API call.
Conclusion
OpenSSH For Windows is an excellent tool for providing secure access to Windows based servers through SSH tunnels. The shellexecuteex and terminateprocess API functions allow us to not only open an SSH tunnel from within Visual Basic, but close it as well.
February 6th, 2007 at 12:32 pm
Hi,
This looks just the code what I’m looking for, but I’m having little difficulties to implement this, since I’m quite new about this.
There is a reference to see attached project, but I can’t see it. I was just thinking, if I could take look that and notice what is wrong. Thanks for awesome examples!!
March 28th, 2007 at 9:46 pm
Excellent tutorial, thanks. The first part of the tutorial has worked a treat for me, but the second part regarding opening and closing through VB is a little confusing. It looks like the two code windows at the bottom of the page duplicate each other. What are SHELLEXECUTEINFO and SEE_MASK_NOCLOSEPROCESS? Is there separate code available for the API declarations, as in the first part of the tutorial? Thanks again for a VERY useful tutorial.
April 5th, 2007 at 6:46 pm
Exactly what I’ve searched for! Many thanks!!!
And the missing declarations can be found here:
http://www.vbarchiv.net/vbapi/ShellExecuteEx.php
http://www.vbarchiv.net/faq/allg_exitprocess.php
April 17th, 2007 at 5:07 pm
Hi,
This is what I am looking for. I was able to get the first tutorial working, but am not able to get the 2nd part … I am new to VB … The below code will compile and nothing … I was wondering if anyone has any feedback to help me out … thanks so much ..
Natasha
Option Explicit
Dim si As SHELLEXECUTEINFO
Private Type SHELLEXECUTEINFO
cbSize As Long
fMask As Long
hwnd As Long
lpVerb As String
lpFile As String
lpParameters As String
lpDirectory As String
nShow As Long
hInstApp As Long
lpIDList As Long
lpClass As String
hkeyClass As Long
dwHotKey As Long
hIcon As Long
hProcess As Long
End Type
Private Declare Function ShellExecuteEx Lib “shell32.dll” Alias “ShellExecuteExA” _
(si As SHELLEXECUTEINFO) As Long
Private Declare Function TerminateProcess Lib “kernel32″ (ByVal _
hProcess As Long, ByVal uExitCode As Long) As Long
Private Declare Function CloseHandle Lib “kernel32″ (ByVal _
hObject As Long) As Long
Private Sub cmdClose_Click()
Dim exitCode As Long
If TerminateProcess(si.hProcess, exitCode) 0 Then
CloseHandle (si.hProcess)
MsgBox “Tunnel Closed!”
End If
End Sub
Private Sub cmdOpen_Click()
si.cbSize = Len(si)
si.fMask = SEE_MASK_NOCLOSEPROCESS
si.hwnd = frmMain.hwnd
si.lpVerb = “open”
si.lpFile = “c:\plink.exe”
si.lpParameters = “-ssh -l tunnel -pw Cyber4me 192.168.10.25″
si.lpDirectory = “c:\”
si.nShow = SW_HIDE
If ShellExecuteEx(si) Then
MsgBox “Tunnel Open!”
Else
MsgBox “Opening Failed!”
End If
End Sub