2424
2525#include < cstdarg>
2626#include < cerrno>
27+ #include < wx/file.h>
2728#include < wx/intl.h>
2829#include < wx/log.h>
2930#include < wx/socket.h>
3233#else
3334#include < arpa/inet.h>
3435#endif
35- #include < libsshtunnel.h>
3636#include " VNCConn.h"
3737
3838bool VNCConn::libsshtunnel_initialized = false ;
@@ -95,6 +95,7 @@ VNCConn::VNCConn(void* p) : condition_auth(mutex_auth)
9595 err.Printf (_ (" libsshtunnel initialization failed" ));
9696 }
9797 }
98+ ssh_tunnel = NULL ;
9899
99100 // statistics stuff
100101 do_stats = false ;
@@ -227,6 +228,60 @@ wxThread::ExitCode VNCConn::Entry()
227228{
228229 // init connection before going into main loop if this is not a listening one
229230 if (!thread_listenmode) {
231+ if (!ssh_host.IsEmpty ()) {
232+ // ssh-tunneling, check whether it's password- or key-based
233+ if (ssh_password.IsOk ()) {
234+ // password-based
235+ ssh_tunnel = ssh_tunnel_open_with_password (ssh_host.mb_str (),
236+ wxAtoi (ssh_port),
237+ ssh_username.mb_str (),
238+ ssh_password.GetAsString ().mb_str (),
239+ cl->serverHost ,
240+ cl->serverPort ,
241+ this ,
242+ thread_on_ssh_fingerprint_check,
243+ thread_on_ssh_error);
244+ } else {
245+ // key-based
246+ std::vector<char > ssh_priv_key;
247+ if (!ssh_priv_key_filename.IsEmpty ()) {
248+ wxFile sshPrivKeyFile (ssh_priv_key_filename);
249+ if (sshPrivKeyFile.IsOpened ()) {
250+ wxFileOffset fileSize = sshPrivKeyFile.Length ();
251+ ssh_priv_key.resize (fileSize);
252+ sshPrivKeyFile.Read (ssh_priv_key.data (), fileSize);
253+ }
254+ }
255+ ssh_tunnel = ssh_tunnel_open_with_privkey (ssh_host.mb_str (),
256+ wxAtoi (ssh_port),
257+ ssh_username.mb_str (),
258+ ssh_priv_key.data (),
259+ ssh_priv_key.size (),
260+ ssh_priv_key_password.GetAsString ().mb_str (),
261+ cl->serverHost ,
262+ cl->serverPort ,
263+ this ,
264+ thread_on_ssh_fingerprint_check,
265+ thread_on_ssh_error);
266+ }
267+
268+ if (ssh_tunnel) {
269+ cl->serverHost = strdup (" 127.0.0.1" );
270+ cl->serverPort = ssh_tunnel_get_port (ssh_tunnel);
271+ } else {
272+ err.Printf (_ (" Failure connecting to SSH server at %s:%s!" ), ssh_host, ssh_port);
273+ if (thread_shutdown) {
274+ wxLogDebug (" VNCConn %p: ssh_tunnel_open_* canceled." , this );
275+ thread_post_init_notify (InitState::CONNECT_CANCEL);
276+ } else {
277+ wxLogDebug (" VNCConn %p: ssh_tunnel_open_* failed." , this );
278+ thread_post_init_notify (InitState::CONNECT_FAIL);
279+ }
280+ wxLogDebug (" VNCConn %p: vncthread done early" , this );
281+ return 0 ;
282+ }
283+ }
284+
230285 rfbClientLog (" About to connect to '%s', port %d\n " , cl->serverHost , cl->serverPort );
231286
232287 // save these for the error case
@@ -235,6 +290,10 @@ wxThread::ExitCode VNCConn::Entry()
235290
236291 if (!rfbClientConnect (cl)) {
237292 err.Printf (_ (" Failure connecting to server at %s:%d!" ), host, port);
293+ // There might be the case that the SSH tunnel got setup alright, but connecting to the VNC server failed.
294+ // In this case we have to dispose of the tunnel explicitly here.
295+ ssh_tunnel_close (ssh_tunnel);
296+ ssh_tunnel = NULL ;
238297 if (thread_shutdown) {
239298 wxLogDebug (" VNCConn %p: rfbClientConnect() canceled." , this );
240299 thread_post_init_notify (InitState::CONNECT_CANCEL);
@@ -248,6 +307,10 @@ wxThread::ExitCode VNCConn::Entry()
248307 wxLogDebug (" VNCConn %p: rfbClientConnect() succeeded." , this );
249308 thread_post_init_notify (InitState::CONNECT_SUCCESS);
250309 if (!rfbClientInitialise (cl)) {
310+ // There might be the case that the SSH tunnel got setup alright, but auth at the VNC server failed.
311+ // In this case we have to dispose of the tunnel explicitly here.
312+ ssh_tunnel_close (ssh_tunnel);
313+ ssh_tunnel = NULL ;
251314 err.Printf (_ (" Failure connecting to server at %s:%d!" ), host, port);
252315 if (thread_shutdown) {
253316 wxLogDebug (" VNCConn %p: rfbClientInitialise() canceled." , this );
@@ -1030,8 +1093,23 @@ void VNCConn::thread_logger(const char *format, ...)
10301093}
10311094
10321095
1096+ void VNCConn::thread_on_ssh_error (void *client, ssh_tunnel_error_t error_code, const char *error_message) {
1097+ wxString msg = wxString::Format (" SSH tunnel error: %d - %s" , error_code, error_message);
1098+ rfbClientErr (msg.mb_str ());
1099+ VNCConn* conn = (VNCConn*) client;
1100+ conn->err .Printf (msg);
1101+ }
10331102
10341103
1104+ int VNCConn::thread_on_ssh_fingerprint_check (void *client,
1105+ const char *fingerprint,
1106+ int fingerprint_len,
1107+ const char *host) {
1108+ VNCConn* conn = (VNCConn*) client;
1109+ // TODO
1110+ return 0 ;
1111+ }
1112+
10351113
10361114/*
10371115 public members
@@ -1204,6 +1282,9 @@ void VNCConn::Shutdown()
12041282 rfbCloseSocket (cl->sock );
12051283 }
12061284
1285+ ssh_tunnel_close (ssh_tunnel);
1286+ ssh_tunnel = NULL ;
1287+
12071288 // end vnc thread and wait for it to get done
12081289 if (GetThread () && GetThread ()->IsRunning ())
12091290 {
0 commit comments