The branch, master has been updated
via c01d49db3afcbc028d704d3048f96fabee5827b4 (commit)
from ac2eeb5461e7f27cef3aaff705f690bf839bd8ce (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit c01d49db3afcbc028d704d3048f96fabee5827b4
Author: Oleksandr Shneyder <o.shneyder(a)phoca-gmbh.de>
Date: Mon Nov 12 16:37:59 2012 +0100
implement class SshProcess. Add support for type SSH in X2GoBroker
-----------------------------------------------------------------------
Summary of changes:
sshconnection.cpp | 561 ++++++++++++++++++++++++++++++++++++++++++++++++++-
sshconnection.h | 80 +++++---
sshprocess.cpp | 242 ++++++++++++++++++++++
sshprocess.h | 84 ++++++++
x2goapplication.cpp | 5 +-
x2gobroker.cpp | 50 ++++-
x2gobroker.h | 9 +-
x2goclient2.pro | 2 +
8 files changed, 991 insertions(+), 42 deletions(-)
create mode 100644 sshprocess.cpp
create mode 100644 sshprocess.h
The diff of changes is:
diff --git a/sshconnection.cpp b/sshconnection.cpp
index 878c66c..29f22cf 100644
--- a/sshconnection.cpp
+++ b/sshconnection.cpp
@@ -20,6 +20,7 @@
#include "sshconnection.h"
#include "sshconnectionguiinteraction.h"
+#include "sshprocess.h"
#define PROXYTUNNELPORT 44444
@@ -68,6 +69,7 @@ SshConnection::SshConnection(QObject* parent, QString host, int port, bool accep
sshProxyReady=false;
nextPid=0;
my_ssh_session=0;
+ connected=false;
breakLoop=false;
this->host=host;
@@ -94,11 +96,71 @@ SshConnection::SshConnection(QObject* parent, QString host, int port, bool accep
}
}
+//private constructor for reverse tunnel connections
+SshConnection::SshConnection(QObject* parent, QString host, int port, bool acceptUnknownServers,
+ QString user, QString pass, QString key, bool autoLogin, bool krbLogin,
+ int remotePort, QString localHost, int localPort, SshProcess* creator, bool useProxy,
+ SshConnection::ProxyType proxyType, QString proxyServer, quint16 proxyPort, QString proxyLogin,
+ QString proxyPassword, QString proxyKey, bool proxyAutoLogin, int localProxyPort): QThread(parent)
+{
+#if defined ( Q_OS_DARWIN )
+ setStackSize (sizeof (char) * 1024 * 1024 * 2);
+#endif
+ nextPid=0;
+ my_ssh_session=0;
+ tcpProxySocket = NULL;
+ tcpNetworkProxy = NULL;
+ sshProxy= NULL;
+ sshProxyReady=false;
+ breakLoop=false;
+ this->host=host;
+ this->port=port;
+ this->user=user;
+ this->pass=pass;
+ this->key=key;
+ this->autoLogin=autoLogin;
+ this->acceptUnknownServers=acceptUnknownServers;
+ this->useProxy=useProxy;
+ this->proxyServer=proxyServer;
+ this->proxyPort=proxyPort;
+ this->proxyLogin=proxyLogin;
+ this->proxyPassword=proxyPassword;
+ this->proxyType=proxyType;
+ this->proxyAutoLogin=proxyAutoLogin;
+ this->proxyKey=proxyKey;
+ this->localProxyPort=localProxyPort;
+ this->kerberos=krbLogin;
+ reverseTunnelLocalHost=localHost;
+ reverseTunnelLocalPort=localPort;
+ reverseTunnelCreator=creator;
+ reverseTunnel=true;
+ reverseTunnelRemotePort=remotePort;
+#ifdef DEBUG
+ qDebug()<<"SshMasterConnection, instance "<<this<<" created (reverse tunnel)";
+#endif
+}
+
+
SshConnection::~SshConnection()
{
+ disconnectFlagMutex.lock();
+ disconnectSessionFlag=true;
+ disconnectFlagMutex.unlock();
+#ifdef DEBUG
+ qDebug()<<"SshConnection, instance "<<this<<" waiting for thread to finish";
+#endif
+ wait();
+#ifdef DEBUG
+ qDebug()<<"SshConnection, instance "<<this<<" thread finished";
+#endif
+ for(int i=processes.count()-1; i>=0; --i)
+ {
+ delete processes[i];
+ }
if(my_ssh_session)
{
ssh_free(my_ssh_session);
+ my_ssh_session=0;
}
qDebug()<<"ssh connection destructor";
}
@@ -106,6 +168,7 @@ SshConnection::~SshConnection()
void SshConnection::run()
{
disconnectSessionFlag=false;
+#warning implement ssh proxy code
if ( !isLibSshInited )
{
if ( ssh_init() !=0 )
@@ -113,7 +176,7 @@ void SshConnection::run()
QString err=tr ( "Can not initialize libssh" );
qDebug()<<err<<endl;
guiInteractor->critical(err, MessageBox::OK);
- emit signalError ( CONNECTION, err );
+ emit signalError ( (int)CONNECTION, err );
return;
}
isLibSshInited=true;
@@ -133,7 +196,7 @@ void SshConnection::run()
QString err=tr ( "Can not create ssh session" );
qDebug()<<err<<endl;
guiInteractor->critical(err, MessageBox::OK);
- emit signalError ( CONNECTION, err);
+ emit signalError ( (int)CONNECTION, err);
if ( reverseTunnel )
emit signalIoError ( reverseTunnelCreator, err, "" );
return;
@@ -161,8 +224,9 @@ void SshConnection::run()
QString message=tr ( "Can not connect to proxy server" );
qDebug()<<message<<endl;
guiInteractor->critical(message, MessageBox::OK);
- emit signalError ( CONNECTION, message );
+ emit signalError ( (int)CONNECTION, message );
ssh_free ( my_ssh_session );
+ my_ssh_session=0;
return;
}
ssh_options_set( my_ssh_session, SSH_OPTIONS_FD, &proxysocket);
@@ -176,10 +240,11 @@ void SshConnection::run()
message+=" - "+err;
qDebug()<<message;
guiInteractor->critical(message, MessageBox::OK);
- emit signalError (CONNECTION, message);
+ emit signalError ((int)CONNECTION, message);
if ( reverseTunnel )
emit signalIoError ( reverseTunnelCreator, message, err);
ssh_free ( my_ssh_session );
+ my_ssh_session=0;
return;
}
QString errMsg;
@@ -187,9 +252,10 @@ void SshConnection::run()
if ( state != SSH_SERVER_KNOWN_OK )
{
guiInteractor->critical(errMsg, MessageBox::OK);
- emit signalError (SERVERAUTH, errMsg);
+ emit signalError ((int)SERVERAUTH, errMsg);
ssh_disconnect ( my_ssh_session );
ssh_free ( my_ssh_session );
+ my_ssh_session=0;
return;
}
@@ -201,6 +267,7 @@ void SshConnection::run()
{
qDebug()<<"SSH session connected";
emit signalConnectionOk(host);
+ connected=true;
}
else
{
@@ -211,11 +278,12 @@ void SshConnection::run()
guiInteractor->critical(message, MessageBox::OK);
message+=" - "+err+"\n"+authErrors.join ( "\n" );
qDebug()<<message;
- emit signalError (USERAUTH, message );
+ emit signalError ((int)USERAUTH, message );
if ( reverseTunnel )
emit signalIoError ( reverseTunnelCreator,message,err );
ssh_disconnect ( my_ssh_session );
ssh_free ( my_ssh_session );
+ my_ssh_session=0;
return;
}
@@ -241,6 +309,7 @@ void SshConnection::run()
emit signalIoError ( reverseTunnelCreator, message, err );
ssh_disconnect ( my_ssh_session );
ssh_free ( my_ssh_session );
+ my_ssh_session=0;
return;
}
emit signalReverseListenOk ( reverseTunnelCreator );
@@ -303,7 +372,7 @@ int SshConnection::serverAuth(QString& errorMsg)
return SSH_SERVER_ERROR;
#ifdef DEBUG
- x2goDebug<<"state: "<<state<<endl;
+ qDebug()<<"state: "<<state<<endl;
#endif
switch ( state )
@@ -466,12 +535,488 @@ bool SshConnection::userAuthWithPass()
}
+
+void SshConnection::copy()
+{
+ for ( int i=copyRequests.size()-1; i>=0; --i )
+ {
+ QStringList lst=copyRequests[i].dst.split ( "/" );
+ QString dstFile=lst.last();
+ lst.removeLast();
+ QString dstPath=lst.join ( "/" );
+#ifdef DEBUG
+ qDebug()<<"dst path:"<<dstPath<<" file:"<<dstFile<<endl;
+#endif
+ ssh_scp scp=ssh_scp_new ( my_ssh_session, SSH_SCP_WRITE|SSH_SCP_RECURSIVE, dstPath.toAscii() );
+ if ( scp == NULL )
+ {
+ qDebug()<<"Error allocating scp session: "<< ssh_get_error ( my_ssh_session ) <<endl;
+ return;
+ }
+ int rc = ssh_scp_init ( scp );
+ if ( rc != SSH_OK )
+ {
+ qDebug()<<"Error initializing scp session: "<< ssh_get_error ( my_ssh_session ) <<endl;
+ ssh_scp_free ( scp );
+ return;
+ }
+ QFile file ( copyRequests[i].src );
+ if ( !file.open ( QIODevice::ReadOnly ) )
+ {
+ QString errMsg=tr ( "Can not open file " ) +copyRequests[i].src;
+ emit signalCopyError ( copyRequests[i].creator, errMsg, "" );
+ copyRequests.removeAt ( i );
+ ssh_scp_close ( scp );
+ ssh_scp_free ( scp );
+ continue;
+ }
+ QByteArray arr=file.readAll();
+ file.close();
+ rc=ssh_scp_push_file ( scp,dstFile.toAscii(),arr.size(), 0600 );
+ if ( rc != SSH_OK )
+ {
+ QString errMsg=tr ( "Can not create remote file " ) +copyRequests[i].dst;
+ QString serr=ssh_get_error ( my_ssh_session );
+ qDebug()<<errMsg<<" - "<<serr<<endl;
+ emit signalCopyError ( copyRequests[i].creator, errMsg, serr );
+ copyRequests.removeAt ( i );
+ ssh_scp_close ( scp );
+ ssh_scp_free ( scp );
+ continue;
+ }
+ rc=ssh_scp_write ( scp,arr.data(),arr.size() );
+ if ( rc != SSH_OK )
+ {
+ QString serr=ssh_get_error ( my_ssh_session );
+ QString errMsg=tr ( "Can not write to remote file " ) +copyRequests[i].dst;
+ qDebug()<<errMsg<<" - "<<serr<<endl;
+ emit signalCopyError ( copyRequests[i].creator, errMsg, serr );
+ copyRequests.removeAt ( i );
+ ssh_scp_close ( scp );
+ ssh_scp_free ( scp );
+ continue;
+ }
+ emit signalCopyOk ( copyRequests[i].creator );
+#ifdef DEBUG
+ qDebug()<<"scp ok: "<<copyRequests[i].src<<" -> "<<user<<"@"<<host<<":"<<copyRequests[i].dst<<endl;
+#endif
+ copyRequests.removeAt ( i );
+ ssh_scp_close ( scp );
+ ssh_scp_free ( scp );
+ }
+}
+
+
void SshConnection::channelLoop()
{
+ forever
+ {
+ copyRequestMutex.lock();
+ if ( copyRequests.size() >0 )
+ copy();
+ copyRequestMutex.unlock();
+ if ( reverseTunnel )
+ {
+ ssh_channel newChan=channel_forward_accept ( my_ssh_session,0 );
+ if ( newChan )
+ {
+#ifdef DEBUG
+ qDebug()<<"new forward connection"<<endl;
+#endif
+ int sock=socket ( AF_INET, SOCK_STREAM,0 );
+#ifndef Q_OS_WIN
+ const int y=1;
+#else
+ const char y=1;
+#endif
+ setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,&y, sizeof(int));
+
+ struct sockaddr_in address;
+ address.sin_family=AF_INET;
+ address.sin_port=htons ( reverseTunnelLocalPort );
+#ifdef DEBUG
+ qDebug()<<"connecting to "<<reverseTunnelLocalHost<<":"<<reverseTunnelLocalPort<<endl;
+#endif
+#ifndef Q_OS_WIN
+ inet_aton ( reverseTunnelLocalHost.toAscii(), &address.sin_addr );
+#else
+ address.sin_addr.s_addr=inet_addr (
+ reverseTunnelLocalHost.toAscii() );
+#endif
+
+ if ( ::connect ( sock, ( struct sockaddr * ) &address,sizeof ( address ) ) !=0 )
+ {
+ QString errMsg=tr ( "can not connect to " ) +
+ reverseTunnelLocalHost+":"+QString::number ( reverseTunnelLocalPort );
+ qDebug()<<errMsg<<endl;
+ emit signalIoError ( reverseTunnelCreator, errMsg, "" );
+ continue;
+ }
+#ifdef DEBUG
+ qDebug()<<"creating new channel connection"<<endl;
+#endif
+ ChannelConnection con;
+ con.channel=newChan;
+ con.sock=sock;
+ con.creator=reverseTunnelCreator;
+ channelConnectionsMutex.lock();
+ channelConnections<<con;
+ channelConnectionsMutex.unlock();
+ }
+ }
+
+ char buffer[1024*512]; //512K buffer
+ int nbytes;
+ fd_set rfds;
+
+ struct timeval tv;
+
+ tv.tv_sec = 0;
+ tv.tv_usec = 500;
+
+ int retval;
+ int maxsock=-1;
+
+ disconnectFlagMutex.lock();
+ bool disconnect=disconnectSessionFlag;
+ disconnectFlagMutex.unlock();
+
+ if ( disconnect )
+ {
+
+ if (useProxy && proxyType==PROXYSSH && sshProxy)
+ {
+ delete sshProxy;
+ sshProxy=0;
+ }
+
+#ifdef DEBUG
+ if ( !reverseTunnel )
+ qDebug()<<"Disconnecting..."<<endl;
+#endif
+ reverseTunnelConnectionsMutex.lock();
+ for ( int i=reverseTunnelConnections.size()-1; i>=0; --i)
+ {
+ delete reverseTunnelConnections[i];
+ }
+ reverseTunnelConnectionsMutex.unlock();
+
+ channelConnectionsMutex.lock();
+ for ( int i=0; i<channelConnections.size(); ++i )
+ {
+ finalize ( i );
+ }
+ channelConnectionsMutex.unlock();
+ ssh_disconnect ( my_ssh_session );
+ ssh_free ( my_ssh_session );
+ my_ssh_session=0;
+
+ if (tcpProxySocket != NULL)
+ delete tcpProxySocket;
+ if (tcpNetworkProxy != NULL)
+ delete tcpNetworkProxy;
+#ifdef DEBUG
+ if ( !reverseTunnel )
+ qDebug()<<"All channels closed, session disconnected, quiting session loop"<<endl;
+#endif
+ return;
+ }
+
+ channelConnectionsMutex.lock();
+ if ( channelConnections.size() <=0 )
+ {
+ channelConnectionsMutex.unlock();
+ usleep ( 500 );
+ continue;
+ }
+ ssh_channel* read_chan=new ssh_channel[channelConnections.size() +1];
+ ssh_channel* out_chan=new ssh_channel[channelConnections.size() +1];
+ read_chan[channelConnections.size() ]=NULL;
+
+ FD_ZERO ( &rfds );
+
+ for ( int i=0; i<channelConnections.size(); ++i )
+ {
+ int tcpSocket=channelConnections.at ( i ).sock;
+ if ( tcpSocket>0 )
+ FD_SET ( tcpSocket, &rfds );
+ if ( channelConnections.at ( i ).channel==0l )
+ {
+#ifdef DEBUG
+ qDebug()<<"creating new channel"<<endl;
+#endif
+ ssh_channel channel=channel_new ( my_ssh_session );
+#ifdef DEBUG
+ qDebug()<<"new channel:"<<channel<<endl;
+#endif
+ channelConnections[i].channel=channel;
+ if ( tcpSocket>0 )
+ {
+#ifdef DEBUG
+ qDebug()<<"forwarding new channel, local port: "<<channelConnections.at ( i ).localPort<<endl;
+#endif
+ if ( channel_open_forward ( channel,
+ channelConnections.at ( i ).forwardHost.toAscii(),
+ channelConnections.at ( i ).forwardPort,
+ channelConnections.at ( i ).localHost.toAscii(),
+ channelConnections.at ( i ).localPort ) != SSH_OK )
+ {
+ QString err=ssh_get_error ( my_ssh_session );
+ QString errorMsg=tr ( "channel_open_forward failed" );
+ emit signalIoError ( channelConnections[i].creator, errorMsg, err );
+ qDebug()<<errorMsg<<": "<<err<<endl;
+ }
+#ifdef DEBUG
+ else
+ {
+ qDebug()<<" new channel forwarded"<<endl;
+ }
+#endif
+ }
+ else
+ {
+#ifdef DEBUG
+ qDebug()<<"executing remote: "<<channelConnections.at ( i ).command<<endl;
+#endif
+ if ( channel_open_session ( channel ) !=SSH_OK )
+ {
+ QString err=ssh_get_error ( my_ssh_session );
+ QString errorMsg=tr ( "channel_open_session failed" );
+ emit signalIoError ( channelConnections[i].creator, errorMsg, err );
+ qDebug()<<errorMsg<<": "<<err<<endl;
+ }
+ else if ( channel_request_exec ( channel, channelConnections[i].command.toAscii() ) != SSH_OK )
+ {
+ QString err=ssh_get_error ( my_ssh_session );
+ QString errorMsg=tr ( "channel_request_exec failed" );
+ emit signalIoError ( channelConnections[i].creator, errorMsg, err );
+ qDebug()<<errorMsg<<": "<<err<<endl;
+ }
+#ifdef DEBUG
+ else
+ {
+ qDebug()<<" new exec channel created"<<endl;
+ }
+#endif
+ }
+ }
+ read_chan[i]=channelConnections.at ( i ).channel;
+ if ( tcpSocket>maxsock )
+ maxsock=tcpSocket;
+ }
+ channelConnectionsMutex.unlock();
+ retval=ssh_select ( read_chan,out_chan,maxsock+1,&rfds,&tv );
+ delete [] read_chan;
+ delete [] out_chan;
+
+ if ( retval == -1 )
+ {
+ qDebug()<<"select error\n";
+ continue;
+ }
+
+ channelConnectionsMutex.lock();
+ for ( int i=channelConnections.size()-1; i>=0; --i )
+ {
+ int tcpSocket=channelConnections.at ( i ).sock;
+ ssh_channel channel=channelConnections.at ( i ).channel;
+ if ( channel==0l )
+ continue;
+ if ( channel_poll ( channel,1 ) >0 )
+ {
+ nbytes = channel_read ( channel, buffer, sizeof ( buffer )-1, 1 );
+ emit signalStdErr ( channelConnections[i].creator, QByteArray ( buffer,nbytes ) );
+ }
+ int rez=channel_poll ( channel,0 );
+ if ( rez==SSH_EOF )
+ {
+#ifdef DEBUG
+ qDebug()<<"EOF ON CHANNEL "<<channel<<endl;
+#endif
+ //////Finished////////
+ finalize ( i );
+ continue;
+ }
+ if ( rez>0 )
+ {
+ nbytes = channel_read ( channel, buffer, sizeof ( buffer )-1, 0 );
+ if ( nbytes > 0 )
+ {
+ if ( tcpSocket>0 )
+ {
+ if ( send ( tcpSocket,buffer, nbytes,0 ) != nbytes )
+ {
+ QString errMsg=tr ( "error writing to socket" );
+ qDebug()<<"error writing "<<nbytes<<" to tcp socket"<<tcpSocket<<endl;
+ emit signalIoError ( channelConnections[i].creator,errMsg,"" );
+ finalize ( i );
+ continue;
+ }
+ }
+ else
+ {
+ emit signalStdOut ( channelConnections[i].creator, QByteArray ( buffer,nbytes ) );
+ }
+ }
+
+ if ( nbytes < 0 )
+ {
+ //////ERROR!!!!!////////
+ QString err=ssh_get_error ( my_ssh_session );
+ QString errorMsg=tr ( "error reading channel" );
+ emit signalIoError ( channelConnections[i].creator, errorMsg, err );
+ qDebug()<<errorMsg<<" - "<<err<<endl;
+ finalize ( i );
+ continue;
+ }
+
+ if ( channel_is_eof ( channel ) )
+ {
+#ifdef DEBUG
+ qDebug()<<"EOF ON CHANNEL "<<channel<<endl;
+#endif
+ //////Finished////////
+ finalize ( i );
+ continue;
+ }
+ }
+ if ( tcpSocket<=0 )
+ {
+ continue;
+ }
+ if ( FD_ISSET ( tcpSocket,&rfds ) )
+ {
+ nbytes = recv ( tcpSocket, buffer, sizeof ( buffer )-1,0 );
+ if ( nbytes > 0 )
+ {
+ if ( channel_write ( channel, buffer, nbytes ) !=nbytes )
+ {
+ QString err=ssh_get_error ( my_ssh_session );
+ QString errorMsg=tr ( "channel_write failed" );
+ emit signalIoError ( channelConnections[i].creator, errorMsg, err );
+ qDebug()<<errorMsg<<" - "<<err<<endl;
+ finalize ( i );
+ continue;
+ }
+ }
+ if ( nbytes < 0 )
+ {
+ //////ERROR!!!!!////////
+ QString err="";
+ QString errorMsg=tr ( "error reading tcp socket" );
+ emit signalIoError ( channelConnections[i].creator, errorMsg, err );
+ qDebug()<<errorMsg<<" - "<<err<<endl;
+ finalize ( i );
+ continue;
+ }
+ if ( nbytes==0 )
+ {
+#ifdef DEBUG
+ qDebug()<<"socket closed "<<tcpSocket<<endl;
+#endif
+ finalize ( i );
+ continue;
+ }
+ }
+ }
+ channelConnectionsMutex.unlock();
+ }
+}
+
+void SshConnection::finalize(int item)
+{
+ int tcpSocket=channelConnections.at ( item ).sock;
+ ssh_channel channel=channelConnections.at ( item ).channel;
+ if ( channel )
+ {
+ channel_send_eof ( channel );
+#ifdef DEBUG
+ qDebug()<<"eof sent\n";
+#endif
+ channel_close ( channel );
+#ifdef DEBUG
+ qDebug()<<"channel closed\n";
+#endif
+ channel_free ( channel );
+ }
+ if ( tcpSocket>0 )
+ {
+#ifndef Q_OS_WIN
+ shutdown(tcpSocket, SHUT_RDWR);
+#endif
+ close ( tcpSocket );
+ }
+ SshProcess* proc=channelConnections[item].creator;
+ channelConnections.removeAt ( item );
+ emit signalChannelClosed ( proc );
+}
+void SshConnection::addChannelConnection(SshProcess* creator, QString cmd)
+{
+ ChannelConnection con;
+ con.channel=NULL;
+ con.sock=-1;
+ con.creator=creator;
+ con.command=cmd;
+
+ channelConnectionsMutex.lock();
+ channelConnections<<con;
+ channelConnectionsMutex.unlock();
+}
+
+void SshConnection::addChannelConnection(SshProcess* creator, int sock, QString forwardHost, int forwardPort, QString localHost, int localPort, void* channel)
+{
+ ChannelConnection con;
+ con.channel= ( ssh_channel ) channel;
+ con.sock=sock;
+ con.creator=creator;
+ con.forwardHost=forwardHost;
+ con.forwardPort=forwardPort;
+ con.localHost=localHost;
+ con.localPort=localPort;
+
+
+ channelConnectionsMutex.lock();
+ channelConnections<<con;
+ channelConnectionsMutex.unlock();
}
-void SshConnection::finalize(int arg1)
+void SshConnection::addCopyRequest(SshProcess* creator, QString src, QString dst)
{
+ CopyRequest req;
+ req.src=src;
+ req.dst=dst;
+ req.creator=creator;
+ copyRequestMutex.lock();
+ copyRequests<<req;
+ copyRequestMutex.unlock();
+}
+SshConnection* SshConnection::reverseTunnelConnection(SshProcess* creator, int remotePort, QString localHost, int localPort)
+{
+ SshConnection* con=new SshConnection (this, host, port, acceptUnknownServers, user, pass,
+ key, autoLogin, kerberos, remotePort,localHost,
+ localPort, creator, useProxy, proxyType, proxyServer, proxyPort, proxyLogin,
+ proxyPassword, proxyKey, proxyAutoLogin, localProxyPort );
+
+ connect(con, SIGNAL(signalIoError(SshProcess*, QString, QString)), this, SIGNAL(signalIoError(SshProcess*, QString, QString)));
+ connect(con, SIGNAL(signalStdErr(SshProcess*, QByteArray)), this, SIGNAL ( signalStdErr(SshProcess*, QByteArray)));
+ connect(con, SIGNAL(signalReverseListenOk(SshProcess*)), this, SIGNAL(signalReverseListenOk(SshProcess*)));
+ con->start();
+ reverseTunnelConnectionsMutex.lock();
+ reverseTunnelConnections.append ( con );
+ reverseTunnelConnectionsMutex.unlock();
+ return con;
+}
+
+int SshConnection::executeCommand(const QString& command, QObject* receiver, const char* slotFinished)
+{
+ SshProcess* proc=new SshProcess(this, nextPid++);
+ if(receiver && slotFinished)
+ {
+ connect(proc, SIGNAL(signalSshFinished(bool,QString,int)), receiver, slotFinished);
+ }
+ proc->startCommand(command);
+ processes<<proc;
+ return proc->pid;
}
diff --git a/sshconnection.h b/sshconnection.h
index abb08e7..81171ab 100644
--- a/sshconnection.h
+++ b/sshconnection.h
@@ -35,32 +35,10 @@
class SshProcess;
class SshConnectionGuiInteraction;
-struct ChannelConnection
-{
- ssh_channel channel;
- int sock;
- SshProcess* creator;
- int forwardPort;
- int localPort;
- QString forwardHost;
- QString localHost;
- QString command;
- bool operator==(ChannelConnection& t)
- {
- return (channel==t.channel);
- }
-};
-
-struct CopyRequest
-{
- SshProcess* creator;
- QString src;
- QString dst;
-};
-
class SshConnection: public QThread
{
Q_OBJECT
+ X2GO_RO_PROPERTY(bool, connected)
public:
enum ProxyType {PROXYSSH, PROXYHTTP};
enum Error {CONNECTION, SERVERAUTH, USERAUTH};
@@ -71,7 +49,39 @@ public:
bool proxyAutoLogin=false);
~SshConnection();
static void finalizeLibSsh();
+ void addChannelConnection(SshProcess* creator, QString cmd);
+ void addChannelConnection(SshProcess* creator, int sock, QString forwardHost,
+ int forwardPort, QString localHost, int localPort, void* channel=0l);
+
+ void addCopyRequest(SshProcess* creator, QString src, QString dst);
+ SshConnection* reverseTunnelConnection(SshProcess* creator, int remotePort,
+ QString localHost, int localPort);
+ int executeCommand(const QString& command, QObject* receiver=0, const char* slotFinished=0);
+
+
+
private:
+ struct ChannelConnection
+ {
+ ssh_channel channel;
+ int sock;
+ SshProcess* creator;
+ int forwardPort;
+ int localPort;
+ QString forwardHost;
+ QString localHost;
+ QString command;
+ bool operator==(ChannelConnection& t)
+ {
+ return (channel==t.channel);
+ }
+ };
+ struct CopyRequest
+ {
+ SshProcess* creator;
+ QString src;
+ QString dst;
+ };
ssh_session my_ssh_session;
QList<ChannelConnection> channelConnections;
QList<CopyRequest> copyRequests;
@@ -110,20 +120,40 @@ private:
bool breakLoop;
static bool isLibSshInited;
static SshConnectionGuiInteraction* guiInteractor;
+
+ QMutex channelConnectionsMutex;
+ QMutex copyRequestMutex;
+ QMutex disconnectFlagMutex;
+ QMutex reverseTunnelConnectionsMutex;
+
private:
+ SshConnection(QObject* parent, QString host, int port, bool acceptUnknownServers, QString user,
+ QString pass, QString key, bool autoLogin, bool krbLogin, int remotePort, QString localHost,
+ int localPort, SshProcess* creator,
+ bool useProxy=false, ProxyType proxyType=PROXYSSH, QString proxyServer=QString::null, quint16 proxyPort=0,
+ QString proxyLogin=QString::null, QString proxyPassword=QString::null, QString proxyKey=QString::null,
+ bool proxyAutoLogin=false, int localProxyPort=0);
+
bool sshConnect();
bool userAuthWithPass();
bool userAuthAuto();
bool userAuthWithKey();
bool userAuth();
void channelLoop();
- void finalize(int arg1);
+ void finalize(int item);
int serverAuth(QString& errorMsg);
+ void copy();
protected:
void run();
signals:
- void signalError(Error, QString);
+ void signalError(int, QString);
void signalIoError(SshProcess* caller, QString error, QString lastSessionError);
+ void signalCopyError(SshProcess* caller, QString error, QString lastSessionError);
+ void signalCopyOk(SshProcess* caller);
+ void signalChannelClosed(SshProcess* caller);
+
+ void signalStdErr(SshProcess* caller, QByteArray data);
+ void signalStdOut(SshProcess* caller, QByteArray data);
void signalConnectionOk( QString host);
void signalReverseListenOk(SshProcess* creator);
diff --git a/sshprocess.cpp b/sshprocess.cpp
new file mode 100644
index 0000000..f382f64
--- /dev/null
+++ b/sshprocess.cpp
@@ -0,0 +1,242 @@
+/**************************************************************************
+* Copyright (C) 2005-2012 by Oleksandr Shneyder *
+* o.shneyder(a)phoca-gmbh.de *
+* *
+* This program is free software; you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License as published by *
+* the Free Software Foundation; either version 2 of the License, or *
+* (at your option) any later version. *
+* *
+* This program is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU General Public License for more details. *
+* *
+* You should have received a copy of the GNU General Public License *
+* along with this program; if not, write to the *
+* Free Software Foundation, Inc., *
+* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+***************************************************************************/
+
+
+#include "sshprocess.h"
+#include <QTimer>
+#include <QDebug>
+
+#ifndef Q_OS_WIN
+#include <arpa/inet.h>
+#include <netinet/tcp.h>
+#endif
+
+#undef DEBUG
+// #define DEBUG
+
+
+SshProcess::SshProcess(SshConnection* masterConnection, int pid): QObject()
+{
+ this->masterConnection=masterConnection;
+ serverSocket=0;
+ this->pid=pid;
+ connect(masterConnection, SIGNAL(signalStdErr(SshProcess*,QByteArray)),this,SLOT(slotStdErr(SshProcess*,QByteArray)));
+ connect(masterConnection, SIGNAL(signalIoError(SshProcess*,QString,QString)), this,SLOT(slotIOerr(SshProcess*,QString,QString)));
+ tunnel=false;
+ normalExited=true;
+
+}
+
+SshProcess::~SshProcess()
+{
+#ifdef DEBUG
+ qDebug()<<"ssh process destructor";
+#endif
+ if (serverSocket>0)
+ {
+#ifdef Q_OS_WIN
+ closesocket(serverSocket);
+ WSACleanup();
+
+#else
+ close(serverSocket);
+#endif
+ }
+}
+
+
+void SshProcess::startCommand(const QString& cmd)
+{
+ QString shcmd = "sh -c \""+cmd+"\"";
+ masterConnection->addChannelConnection(this, shcmd);
+ connect(masterConnection,SIGNAL(signalStdOut(SshProcess*,QByteArray)),this,SLOT(slotStdOut(SshProcess*,QByteArray)));
+ connect(masterConnection,SIGNAL(signalChannelClosed(SshProcess*)), this,SLOT(slotChannelClosed(SshProcess*)));
+}
+
+void SshProcess::startCopy(QString src, QString dst)
+{
+ connect(masterConnection, SIGNAL(signalCopyError(SshProcess*,QString,QString)), this,
+ SLOT(slotCopyErr(SshProcess*,QString,QString)));
+ connect(masterConnection, SIGNAL(signalCopyOk(SshProcess*)), this,SLOT(slotCopyOk(SshProcess*)));
+ scpSource=src;
+ masterConnection->addCopyRequest(this,src,dst);
+}
+
+void SshProcess::startTunnel(const QString& forwardHost, uint forwardPort, const QString& localHost, uint localPort, bool reverse)
+{
+ this->forwardHost=forwardHost;
+ this->forwardPort=forwardPort;
+ this->localHost=localHost;
+ this->localPort=localPort;
+ tunnel=true;
+ if (!reverse)
+ tunnelLoop();
+ else
+ {
+ connect(masterConnection, SIGNAL(signalReverseListenOk(SshProcess*)), this, SLOT(slotReverseTunnelOk(SshProcess*)));
+ tunnelConnection=masterConnection->reverseTunnelConnection(this, forwardPort, localHost, localPort);
+ }
+}
+
+void SshProcess::slotChannelClosed(SshProcess* creator)
+{
+ if (creator!=this)
+ return;
+ QString output;
+ if (!normalExited)
+ {
+ output=abortString;
+ }
+ else
+ {
+ if ( stdOutString.length()<=0 && stdErrString.length() >0 )
+ {
+ normalExited=false;
+ output=stdErrString;
+#ifdef DEBUG
+ qDebug()<<"have only stderr, something must be wrong"<<endl;
+#endif
+ }
+ else
+ output=stdOutString;
+ }
+#ifdef DEBUG
+ qDebug()<<"ssh finished:"<<normalExited<<" - "<<output<<endl;
+#endif
+ emit signalSshFinished(normalExited, output, pid);
+}
+
+void SshProcess::slotCheckNewConnection()
+{
+ fd_set rfds;
+ struct timeval tv;
+
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+
+ FD_ZERO(&rfds);
+ FD_SET(serverSocket, &rfds);
+
+ if (select(serverSocket+1,&rfds,NULL,NULL,&tv)<=0)
+ return;
+
+#ifdef DEBUG
+ qDebug()<<"new tcp connection\n";
+#endif
+ int tcpSocket=accept(serverSocket, (struct sockaddr*)&address,&addrlen);
+
+#ifdef DEBUG
+ qDebug()<<"new socket:"<<tcpSocket<<endl;
+#endif
+ masterConnection->addChannelConnection(this, tcpSocket, forwardHost, forwardPort, localHost,
+ ntohs(address.sin_port));
+}
+
+void SshProcess::slotCopyErr(SshProcess* creator, QString message, QString sshSessionErr)
+{
+ if (creator!=this)
+ return;
+ emit signalSshFinished(false, message+" - "+sshSessionErr, pid);
+
+}
+
+void SshProcess::slotCopyOk(SshProcess* creator)
+{
+ if (creator!=this)
+ return;
+ emit signalSshFinished(true,"", pid);
+}
+
+void SshProcess::slotIOerr(SshProcess* creator, QString message, QString sshSessionErr)
+{
+ if (creator!=this)
+ return;
+#ifdef DEBUG
+ qDebug()<<"io error:"<<message<<" - "<<sshSessionErr<<endl;
+#endif
+ normalExited=false;
+ abortString=message+" - "+sshSessionErr;
+}
+
+void SshProcess::slotReverseTunnelOk(SshProcess* creator)
+{
+ if (creator==this)
+ emit signalSshTunnelOk(pid);
+
+}
+
+void SshProcess::slotStdErr(SshProcess* creator, QByteArray data)
+{
+ if (creator!=this)
+ return;
+#ifdef DEBUG
+ qDebug()<<"new err data:"<<data<<endl;
+#endif
+ stdErrString+=data;
+}
+
+void SshProcess::slotStdOut(SshProcess* creator, QByteArray data)
+{
+ if (creator!=this)
+ return;
+#ifdef DEBUG
+ qDebug()<<"new data"<<data<<endl;
+#endif
+ stdOutString+=data;
+}
+
+void SshProcess::tunnelLoop()
+{
+ serverSocket=socket(AF_INET, SOCK_STREAM, 0);
+ if (serverSocket<=0)
+ {
+ QString err=tr("Error creating socket");
+ qDebug()<<err<<endl;
+ emit signalSshFinished(false,err,pid);
+ return;
+ }
+#ifndef Q_OS_WIN
+ const int y=1;
+#else
+ const char y=1;
+#endif
+ setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR,&y, sizeof(int));
+ setsockopt(serverSocket, IPPROTO_TCP, TCP_NODELAY,&y, sizeof(int));
+
+ address.sin_family=AF_INET;
+ address.sin_addr.s_addr=INADDR_ANY;
+ address.sin_port=htons(localPort);
+ if (bind(serverSocket,(struct sockaddr*) &address,sizeof(address))!=0)
+ {
+ QString err=tr("Error binding ")+localHost+":"+QString::number(localPort);
+ qDebug()<<err<<endl;
+ emit signalSshFinished(false,err,pid);
+ return;
+ }
+ listen(serverSocket,5);
+ addrlen=sizeof(struct sockaddr_in);
+ QTimer* timer=new QTimer();
+ connect(timer,SIGNAL(timeout()),this,SLOT(slotCheckNewConnection()));
+ timer->start(100);
+ emit signalSshTunnelOk(pid);
+#ifdef DEBUG
+ qDebug()<<"Direct tunnel: waiting for connections on "<<localHost<<":"<<localPort<<endl;
+#endif
+}
diff --git a/sshprocess.h b/sshprocess.h
new file mode 100644
index 0000000..5603f0c
--- /dev/null
+++ b/sshprocess.h
@@ -0,0 +1,84 @@
+/**************************************************************************
+* Copyright (C) 2005-2012 by Oleksandr Shneyder *
+* o.shneyder(a)phoca-gmbh.de *
+* *
+* This program is free software; you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License as published by *
+* the Free Software Foundation; either version 2 of the License, or *
+* (at your option) any later version. *
+* *
+* This program is distributed in the hope that it will be useful, *
+* but WITHOUT ANY WARRANTY; without even the implied warranty of *
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+* GNU General Public License for more details. *
+* *
+* You should have received a copy of the GNU General Public License *
+* along with this program; if not, write to the *
+* Free Software Foundation, Inc., *
+* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+***************************************************************************/
+
+
+#ifndef SSHPROCESS_H
+#define SSHPROCESS_H
+
+#include <QObject>
+
+#ifndef Q_OS_WIN
+#include <netinet/in.h>
+#endif
+
+#include "sshconnection.h"
+
+
+class SshProcess: public QObject
+{
+ Q_OBJECT
+ friend class SshConnection;
+private:
+ explicit SshProcess(SshConnection* masterConnection, int pid);
+ virtual ~SshProcess();
+ void startCommand(const QString& cmd);
+ void startTunnel(const QString& forwardHost, uint forwardPort, const QString& localHost,
+ uint localPort, bool reverse=false);
+ void startCopy(QString src, QString dst);
+ void tunnelLoop();
+
+private:
+ SshConnection* masterConnection;
+ SshConnection* tunnelConnection;
+ int pid;
+ QString forwardHost;
+ QString localHost;
+ QString command;
+ QString scpSource;
+ quint16 forwardPort;
+ quint16 localPort;
+ uint serverSocket;
+ struct sockaddr_in address;
+#ifndef Q_OS_WIN
+ socklen_t addrlen;
+#else
+ int addrlen;
+#endif
+ QString stdOutString;
+ QString stdErrString;
+ QString abortString;
+ bool tunnel;
+ bool normalExited;
+
+private slots:
+ void slotCheckNewConnection();
+ void slotStdErr(SshProcess* creator, QByteArray data);
+ void slotStdOut(SshProcess* creator, QByteArray data);
+ void slotIOerr(SshProcess* creator,QString message, QString sshSessionErr);
+ void slotChannelClosed(SshProcess* creator);
+ void slotReverseTunnelOk(SshProcess* creator);
+ void slotCopyOk(SshProcess* creator);
+ void slotCopyErr(SshProcess* creator,QString message, QString sshSessionErr);
+signals:
+ void signalSshFinished ( bool result, QString output, int processId);
+ void signalSshTunnelOk(int processId);
+};
+
+#endif // SSHPROCESS_H
diff --git a/x2goapplication.cpp b/x2goapplication.cpp
index 817f571..7ff0050 100644
--- a/x2goapplication.cpp
+++ b/x2goapplication.cpp
@@ -78,18 +78,21 @@ void X2GoApplication::slotInitApplication()
{
QMessageBox::critical(0,tr("Error"), tr("Error parsing command line arguments"));
exit(-1);
+ return;
}
if(clientConfig->get_showHelp().get_value().toBool())
{
HelpDialog dialog(0);
dialog.showHelp();
exit(-1);
+ return;
}
if(clientConfig->get_showHelpPack().get_value().toBool())
{
HelpDialog dialog(0);
dialog.showPacks();
exit(-1);
+ return;
}
if(clientConfig->get_brokerUrl().get_value().toString()==QString::null)
@@ -106,7 +109,7 @@ void X2GoApplication::slotInitApplication()
if(broker->get_brokerAbort())
return;
connect(broker, SIGNAL(signalSessionsLoaded()), this, SLOT(slotBrokerSessionsConfig()));
- broker->getUserSessions();
+ broker->slotGetUserSessions();
}
if(clientConfig->get_disallowSessionEdit().get_value().toBool())
{
diff --git a/x2gobroker.cpp b/x2gobroker.cpp
index cca32a7..ba34837 100644
--- a/x2gobroker.cpp
+++ b/x2gobroker.cpp
@@ -22,6 +22,7 @@
#include <QFile>
#include <QDir>
#include <QDebug>
+#include <QTimer>
#include "x2gobroker.h"
#include "x2goapplication.h"
#include "x2goclientconfig.h"
@@ -39,7 +40,7 @@ X2GoBroker::X2GoBroker(QObject* parent): QObject(parent)
url = QUrl( urlString);
if(url.userName().length()>0)
user=url.userName();
- if(!cfg->get_defaultNoBrockerAuth().get_value().toBool())
+ if(!cfg->get_defaultNoBrockerAuth().get_value().toBool() && brokerType==HTTP)
{
getLoginData();
}
@@ -47,10 +48,14 @@ X2GoBroker::X2GoBroker(QObject* parent): QObject(parent)
{
brokerType=SSH;
#warning search for default key hier
- SshConnection* con=new SshConnection(this, url.host(), url.port(), cfg->get_autoAddToKnownHosts().get_value().toBool(),
- user, pass, QString::null,
- cfg->get_defaultAutoLogin().get_value().toBool());
- con->start();
+
+ sshConnection=new SshConnection(this, url.host(), url.port(), cfg->get_autoAddToKnownHosts().get_value().toBool(),
+ user, pass, cfg->get_brokerSSHKey().get_value().toString(),
+ cfg->get_defaultBrockerAutoLogin().get_value().toBool());
+ connect(sshConnection, SIGNAL(signalConnectionOk(QString)), this, SLOT(slotSshConnectionOk()));
+ connect(sshConnection, SIGNAL(signalError(int,QString)), this,
+ SLOT(slotSshConnectionError(int,QString)));
+ sshConnection->start();
}
else
{
@@ -89,6 +94,7 @@ X2GoBroker::~X2GoBroker()
void X2GoBroker::getLoginData()
{
+ X2GoClientConfig* cfg=X2GoApplication::instance()->get_clientConfig();
if(url.userName().length()<=0)
{
MessageBox::Buttons res=MessageBox::input(tr("Enter user name for authentication on broker"),tr("User:"),user);
@@ -98,6 +104,13 @@ void X2GoBroker::getLoginData()
X2GoApplication::exit(-1);
}
}
+ if(brokerType==SSH)
+ {
+ if(cfg->get_defaultBrockerAutoLogin().get_value().toBool())
+ return;
+ if(cfg->get_brokerSSHKey().get_value().toString().length()>0)
+ return;
+ }
pass=QString::null;
MessageBox::Buttons res=MessageBox::input(tr("Enter password for authentication on broker"),tr("Password:"),pass, QLineEdit::Password);
if(res!=MessageBox::OK)
@@ -108,7 +121,7 @@ void X2GoBroker::getLoginData()
}
-void X2GoBroker::getUserSessions()
+void X2GoBroker::slotGetUserSessions()
{
if(brokerType==HTTP)
{
@@ -122,6 +135,19 @@ void X2GoBroker::getUserSessions()
httpSessionAnswer.setData ( 0,0 );
sessionsRequest=http->post ( url.path(),req.toUtf8(),&httpSessionAnswer );
}
+ if(brokerType==SSH)
+ {
+ if(!sshConnection->get_connected())
+ {
+ QTimer::singleShot(100, this, SLOT(slotGetUserSessions()));
+ return;
+ }
+ sshConnection->executeCommand ( url.path() +" --authid "+
+ X2GoApplication::instance()->get_clientConfig()->get_authId().get_value().toString()+
+ " --task listsessions",
+ this, SLOT ( slotListSessions ( bool, QString,int ) ));
+
+ }
}
void X2GoBroker::slotRequestFinished(int id, bool error)
@@ -155,7 +181,7 @@ void X2GoBroker::slotListSessions(bool success, QString answer, int)
if(!checkAccess(answer))
{
getLoginData();
- getUserSessions();
+ slotGetUserSessions();
return;
}
createIniFile(answer);
@@ -311,4 +337,14 @@ QString X2GoBroker::getHexVal(const QByteArray& ba)
}
+void X2GoBroker::slotSshConnectionError(int, QString message)
+{
+ X2GoApplication::exit(-1);
+}
+
+void X2GoBroker::slotSshConnectionOk()
+{
+
+}
+
diff --git a/x2gobroker.h b/x2gobroker.h
index 49e3248..a101f40 100644
--- a/x2gobroker.h
+++ b/x2gobroker.h
@@ -28,6 +28,7 @@
#include <QSslError>
#include <QTime>
#include "x2goapplication.h"
+#include "sshconnection.h"
class QHttp;
class X2GoBroker : public QObject
@@ -38,7 +39,6 @@ class X2GoBroker : public QObject
public:
explicit X2GoBroker(QObject* parent = 0);
virtual ~X2GoBroker();
- void getUserSessions();
private:
enum {SSH,HTTP} brokerType;
QString user;
@@ -51,6 +51,7 @@ private:
int sessionsRequest;
int selSessRequest;
QTime requestTime;
+ SshConnection* sshConnection;
private:
void getLoginData();
QString getHexVal ( const QByteArray& ba );
@@ -61,6 +62,12 @@ private slots:
void slotRequestFinished ( int id, bool error );
void slotSslErrors ( const QList<QSslError> & errors ) ;
void slotListSessions ( bool success, QString answer, int pid);
+ void slotSshConnectionError ( int error, QString message);
+ void slotSshConnectionOk ();
+
+public slots:
+ void slotGetUserSessions();
+
signals:
void signalSessionsLoaded();
};
diff --git a/x2goclient2.pro b/x2goclient2.pro
index 5f02ec9..6962eac 100755
--- a/x2goclient2.pro
+++ b/x2goclient2.pro
@@ -58,6 +58,7 @@ SOURCES += main.cpp \
x2gobroker.cpp \
sshconnection.cpp \
sshconnectionguiinteraction.cpp \
+ sshprocess.cpp \
profile.cpp
HEADERS += mainwindow.h \
@@ -88,6 +89,7 @@ HEADERS += mainwindow.h \
x2gobroker.h \
sshconnection.h \
sshconnectionguiinteraction.h \
+ sshprocess.h \
profile.h
LIBS += -lssh
hooks/post-receive
--
x2goclient2.git (X2Go Client 2 (rewrite of x2goclient.git))
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "x2goclient2.git" (X2Go Client 2 (rewrite of x2goclient.git)).