The branch, build-baikal has been updated via a77d761dbb16d28206e7c2446654539935746e4e (commit) from 1c7a4f1aa2694eec916fe1e35998b931cd089f8f (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 ----------------------------------------------------------------- ----------------------------------------------------------------------- Summary of changes: debian/changelog | 2 + onmainwindow.cpp | 11 +- sessionwidget.cpp | 2 - sharewidget.cpp | 450 +++++++++++++++++++++++------------------------ sshmasterconnection.cpp | 163 ++++++++++++++++- sshmasterconnection.h | 1 + sshprocess.cpp | 203 +++++++++++++++++++-- sshprocess.h | 12 +- 8 files changed, 588 insertions(+), 256 deletions(-) The diff of changes is: diff --git a/debian/changelog b/debian/changelog index 5b02cb9..f8d5a5b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -58,6 +58,8 @@ x2goclient (4.0.1.2-0x2go2) UNRELEASED; urgency=low - Support for keys "shadowuser" "shadowdisplay" and "shadowmode" in config file. This allows choosing the default display for shadow sessions. + - Support for GSSApi(Kerberos 5) authentication. Using ssh/scp commands + on Linux and Mac and plink/pscp on Windows. [ Heinrich Schuchardt ] * New upstream version (4.0.1.2): diff --git a/onmainwindow.cpp b/onmainwindow.cpp index 3b5b319..7a0a2a8 100644 --- a/onmainwindow.cpp +++ b/onmainwindow.cpp @@ -2989,8 +2989,8 @@ void ONMainWindow::slotSshServerAuthError ( int error, QString sshMessage, SshMa "For security reasons, it is recommended to stop the connection.\n" "Do you want to terminate the connection?\n" ); if ( !QMessageBox::warning( 0, tr( "Host key verification failed" ), - errMsg, tr( "Yes" ), tr( "No" ) ) != 0) - { + errMsg, tr( "Yes" ), tr( "No" ) ) != 0) + { connection->writeKnownHosts(false); connection->wait(); if(sshConnection && sshConnection !=connection) @@ -3016,8 +3016,8 @@ void ONMainWindow::slotSshServerAuthError ( int error, QString sshMessage, SshMa "For security reasons, it is recommended to stop the connection.\n" "Do you want to terminate the connection?\n"); if ( !QMessageBox::warning( 0, tr( "Host key verification failed" ), - errMsg, tr( "Yes" ), tr( "No" ) ) != 0) - { + errMsg, tr( "Yes" ), tr( "No" ) ) != 0) + { connection->writeKnownHosts(false); connection->wait(); if(sshConnection && sshConnection !=connection) @@ -3493,6 +3493,7 @@ bool ONMainWindow::startSession ( const QString& sid ) void ONMainWindow::slotListSessions ( bool result,QString output, int ) { + x2goDebug<<output; if ( result==false ) { cardReady=false; @@ -4406,7 +4407,7 @@ void ONMainWindow::selectSession ( QStringList& sessions ) else shadowMode=SHADOW_VIEWONLY; startNewSession(); - return; + return; } } } diff --git a/sessionwidget.cpp b/sessionwidget.cpp index 9e54d19..179e6da 100644 --- a/sessionwidget.cpp +++ b/sessionwidget.cpp @@ -267,8 +267,6 @@ SessionWidget::SessionWidget ( QString id, ONMainWindow * mw, connect (cbProxySameUser, SIGNAL(clicked(bool)), this, SLOT(slot_proxySameLogin())); readConfig(); - cbKrbLogin->setChecked(false); - cbKrbLogin->setVisible(false); } diff --git a/sharewidget.cpp b/sharewidget.cpp index 22b9380..1c24191 100644 --- a/sharewidget.cpp +++ b/sharewidget.cpp @@ -38,109 +38,109 @@ ShareWidget::ShareWidget ( QString id, ONMainWindow * mw, QWidget * parent, Qt::WindowFlags f ) - : ConfigWidget ( id,mw,parent,f ) + : ConfigWidget ( id,mw,parent,f ) { - QGroupBox *egb=new QGroupBox ( tr ( "&Folders" ),this ); - expTv=new QTreeView ( egb ); - expTv->setItemsExpandable ( false ); - expTv->setRootIsDecorated ( false ); + QGroupBox *egb=new QGroupBox ( tr ( "&Folders" ),this ); + expTv=new QTreeView ( egb ); + expTv->setItemsExpandable ( false ); + expTv->setRootIsDecorated ( false ); - model=new QStandardItemModel ( 0,2 ); - ldir=new QLabel ( egb ); + model=new QStandardItemModel ( 0,2 ); + ldir=new QLabel ( egb ); - model->setHeaderData ( 0,Qt::Horizontal,QVariant ( - ( QString ) tr ( "Path" ) ) ); - model->setHeaderData ( 1,Qt::Horizontal,QVariant ( - ( QString ) tr ( "Automount" ) ) ); - expTv->setEditTriggers ( QAbstractItemView::NoEditTriggers ); + model->setHeaderData ( 0,Qt::Horizontal,QVariant ( + ( QString ) tr ( "Path" ) ) ); + model->setHeaderData ( 1,Qt::Horizontal,QVariant ( + ( QString ) tr ( "Automount" ) ) ); + expTv->setEditTriggers ( QAbstractItemView::NoEditTriggers ); - QPushButton* openDir=new QPushButton ( - QIcon ( mainWindow->iconsPath ( "/16x16/file-open.png" ) ), - QString::null,egb ); + QPushButton* openDir=new QPushButton ( + QIcon ( mainWindow->iconsPath ( "/16x16/file-open.png" ) ), + QString::null,egb ); - QPushButton* addDir=new QPushButton ( tr ( "Add" ),egb ); - QPushButton* delDir=new QPushButton ( tr ( "Delete" ),egb ); + QPushButton* addDir=new QPushButton ( tr ( "Add" ),egb ); + QPushButton* delDir=new QPushButton ( tr ( "Delete" ),egb ); #ifdef Q_WS_HILDON - QSize sz=addDir->sizeHint(); - sz.setHeight ( ( int ) ( sz.height() /1.5 ) ); - addDir->setFixedSize ( sz ); - sz=delDir->sizeHint(); - sz.setHeight ( ( int ) ( sz.height() /1.5 ) ); - delDir->setFixedSize ( sz ); + QSize sz=addDir->sizeHint(); + sz.setHeight ( ( int ) ( sz.height() /1.5 ) ); + addDir->setFixedSize ( sz ); + sz=delDir->sizeHint(); + sz.setHeight ( ( int ) ( sz.height() /1.5 ) ); + delDir->setFixedSize ( sz ); #endif - QLabel *dirPrompt=new QLabel ( tr ( "Path:" ),egb ); - dirPrompt->setFixedSize ( dirPrompt->sizeHint() ); - openDir->setFixedSize ( openDir->sizeHint() ); - - ldir->setFrameStyle ( QFrame::StyledPanel|QFrame::Sunken ); - - cbFsConv=new QCheckBox ( - tr ( "Filename encoding" - ),egb ); - - QHBoxLayout* enclay=new QHBoxLayout; - cbFrom=new QComboBox ( egb ); - cbTo=new QComboBox ( egb ); - lFrom=new QLabel ( tr ( "local:" ),egb ); - lTo=new QLabel ( tr ( "remote:" ),egb ); - - enclay->addWidget ( cbFsConv ); - enclay->addWidget ( lFrom ); - enclay->addWidget ( cbFrom ); - enclay->addWidget ( lTo ); - enclay->addWidget ( cbTo ); - enclay->addStretch(); - loadEnc ( cbFrom ); - loadEnc ( cbTo ); - - cbFsSshTun=new QCheckBox ( - tr ( "Use ssh port forwarding to tunnel file system " - "connections through firewalls" ),egb ); - - QVBoxLayout* expLay=new QVBoxLayout ( this ); - expLay->addWidget ( egb ); - - QHBoxLayout *tvLay=new QHBoxLayout ( egb ); - - QHBoxLayout *dirLAy=new QHBoxLayout(); - dirLAy->addWidget ( dirPrompt ); - dirLAy->addWidget ( ldir ); - dirLAy->addWidget ( openDir ); - - QVBoxLayout* leftLay=new QVBoxLayout(); - leftLay->addLayout ( dirLAy ); - leftLay->addSpacing ( 10 ); - leftLay->addWidget ( expTv ); - expLay->addLayout ( enclay ); - expLay->addWidget ( cbFsSshTun ); - - QVBoxLayout* rightLay=new QVBoxLayout(); - rightLay->addWidget ( addDir ); - rightLay->addStretch(); - rightLay->addWidget ( delDir ); - rightLay->addStretch(); - - - tvLay->addLayout ( leftLay ); - tvLay->addSpacing ( 10 ); - tvLay->addLayout ( rightLay ); - - - - expTv->setModel ( ( QAbstractItemModel* ) model ); - QFontMetrics fm1 ( expTv->font() ); - expTv->header()->resizeSection ( 1, - fm1.width ( tr ( "Automount" ) ) +10 ); - connect ( openDir,SIGNAL ( clicked() ),this,SLOT ( slot_openDir() ) ); - connect ( addDir,SIGNAL ( clicked() ),this,SLOT ( slot_addDir() ) ); - connect ( delDir,SIGNAL ( clicked() ),this,SLOT ( slot_delDir() ) ); - connect ( cbFsConv,SIGNAL ( clicked() ),this - ,SLOT ( slot_convClicked() ) ); - readConfig(); + QLabel *dirPrompt=new QLabel ( tr ( "Path:" ),egb ); + dirPrompt->setFixedSize ( dirPrompt->sizeHint() ); + openDir->setFixedSize ( openDir->sizeHint() ); + + ldir->setFrameStyle ( QFrame::StyledPanel|QFrame::Sunken ); + + cbFsConv=new QCheckBox ( + tr ( "Filename encoding" + ),egb ); + + QHBoxLayout* enclay=new QHBoxLayout; + cbFrom=new QComboBox ( egb ); + cbTo=new QComboBox ( egb ); + lFrom=new QLabel ( tr ( "local:" ),egb ); + lTo=new QLabel ( tr ( "remote:" ),egb ); + + enclay->addWidget ( cbFsConv ); + enclay->addWidget ( lFrom ); + enclay->addWidget ( cbFrom ); + enclay->addWidget ( lTo ); + enclay->addWidget ( cbTo ); + enclay->addStretch(); + loadEnc ( cbFrom ); + loadEnc ( cbTo ); + + cbFsSshTun=new QCheckBox ( + tr ( "Use ssh port forwarding to tunnel file system " + "connections through firewalls" ),egb ); + + QVBoxLayout* expLay=new QVBoxLayout ( this ); + expLay->addWidget ( egb ); + + QHBoxLayout *tvLay=new QHBoxLayout ( egb ); + + QHBoxLayout *dirLAy=new QHBoxLayout(); + dirLAy->addWidget ( dirPrompt ); + dirLAy->addWidget ( ldir ); + dirLAy->addWidget ( openDir ); + + QVBoxLayout* leftLay=new QVBoxLayout(); + leftLay->addLayout ( dirLAy ); + leftLay->addSpacing ( 10 ); + leftLay->addWidget ( expTv ); + expLay->addLayout ( enclay ); + expLay->addWidget ( cbFsSshTun ); + + QVBoxLayout* rightLay=new QVBoxLayout(); + rightLay->addWidget ( addDir ); + rightLay->addStretch(); + rightLay->addWidget ( delDir ); + rightLay->addStretch(); + + + tvLay->addLayout ( leftLay ); + tvLay->addSpacing ( 10 ); + tvLay->addLayout ( rightLay ); + + + + expTv->setModel ( ( QAbstractItemModel* ) model ); + QFontMetrics fm1 ( expTv->font() ); + expTv->header()->resizeSection ( 1, + fm1.width ( tr ( "Automount" ) ) +10 ); + connect ( openDir,SIGNAL ( clicked() ),this,SLOT ( slot_openDir() ) ); + connect ( addDir,SIGNAL ( clicked() ),this,SLOT ( slot_addDir() ) ); + connect ( delDir,SIGNAL ( clicked() ),this,SLOT ( slot_delDir() ) ); + connect ( cbFsConv,SIGNAL ( clicked() ),this + ,SLOT ( slot_convClicked() ) ); + readConfig(); } @@ -150,211 +150,211 @@ ShareWidget::~ShareWidget() void ShareWidget::slot_openDir() { - QString startDir=ONMainWindow::getHomeDirectory(); + QString startDir=ONMainWindow::getHomeDirectory(); #ifdef Q_OS_WIN - if ( ONMainWindow::getPortable() && - ONMainWindow::U3DevicePath().length() >0 ) - { - startDir=ONMainWindow::U3DevicePath() +"/"; - } + if ( ONMainWindow::getPortable() && + ONMainWindow::U3DevicePath().length() >0 ) + { + startDir=ONMainWindow::U3DevicePath() +"/"; + } #endif - QString path= QFileDialog::getExistingDirectory ( - this, - tr ( "Select folder" ), - startDir ); - if ( path!=QString::null ) - { + QString path= QFileDialog::getExistingDirectory ( + this, + tr ( "Select folder" ), + startDir ); + if ( path!=QString::null ) + { #ifdef Q_OS_WIN - if ( ONMainWindow::getPortable() && - ONMainWindow::U3DevicePath().length() >0 ) - { - if ( path.indexOf ( ONMainWindow::U3DevicePath() ) !=0 ) - { - QMessageBox::critical ( - 0l,tr ( "Error" ), - tr ( "x2goclient is running in " - "portable mode. You should " - "use a path on your usb device " - "to be able to access your data " - "whereever you are" ), - QMessageBox::Ok,QMessageBox::NoButton ); - slot_openDir(); - return; - } - path.replace ( ONMainWindow::U3DevicePath(), - "(U3)" ); - } + if ( ONMainWindow::getPortable() && + ONMainWindow::U3DevicePath().length() >0 ) + { + if ( path.indexOf ( ONMainWindow::U3DevicePath() ) !=0 ) + { + QMessageBox::critical ( + 0l,tr ( "Error" ), + tr ( "x2goclient is running in " + "portable mode. You should " + "use a path on your usb device " + "to be able to access your data " + "whereever you are" ), + QMessageBox::Ok,QMessageBox::NoButton ); + slot_openDir(); + return; + } + path.replace ( ONMainWindow::U3DevicePath(), + "(U3)" ); + } #endif - ldir->setText ( path ); - } + ldir->setText ( path ); + } } void ShareWidget::slot_addDir() { - QString path=ldir->text(); - if ( path.length() <1 ) - return; - for ( int i=0;i<model->rowCount();++i ) - if ( model->index ( i,0 ).data().toString() ==path ) - return; - QStandardItem *item; - item= new QStandardItem ( path ); - model->setItem ( model->rowCount(),0,item ); - item= new QStandardItem(); - item->setCheckable ( true ); - model->setItem ( model->rowCount()-1,1,item ); - ldir->setText ( QString::null ); + QString path=ldir->text(); + if ( path.length() <1 ) + return; + for ( int i=0; i<model->rowCount(); ++i ) + if ( model->index ( i,0 ).data().toString() ==path ) + return; + QStandardItem *item; + item= new QStandardItem ( path ); + model->setItem ( model->rowCount(),0,item ); + item= new QStandardItem(); + item->setCheckable ( true ); + model->setItem ( model->rowCount()-1,1,item ); + ldir->setText ( QString::null ); } void ShareWidget::slot_delDir() { - model->removeRow ( expTv->currentIndex().row() ); + model->removeRow ( expTv->currentIndex().row() ); } void ShareWidget::readConfig() { - X2goSettings st ( "sessions" ); + X2goSettings st ( "sessions" ); - QString exportDir=st.setting()->value ( sessionId+"/export", - ( QVariant ) QString::null ).toString(); + QString exportDir=st.setting()->value ( sessionId+"/export", + ( QVariant ) QString::null ).toString(); - cbFsSshTun->setChecked ( st.setting()->value ( sessionId+"/fstunnel", - true ).toBool() ); - QStringList lst=exportDir.split ( ";",QString::SkipEmptyParts ); + cbFsSshTun->setChecked ( st.setting()->value ( sessionId+"/fstunnel", + true ).toBool() ); + QStringList lst=exportDir.split ( ";",QString::SkipEmptyParts ); - QString toCode=st.setting()->value ( sessionId+"/iconvto", - ( QVariant ) "UTF-8" ).toString(); + QString toCode=st.setting()->value ( sessionId+"/iconvto", + ( QVariant ) "UTF-8" ).toString(); #ifdef Q_OS_WIN - QString fromCode=st.setting()->value ( sessionId+"/iconvfrom", - ( QVariant ) tr ( - "WINDOWS-1252" ) ).toString(); + QString fromCode=st.setting()->value ( sessionId+"/iconvfrom", + ( QVariant ) tr ( + "WINDOWS-1252" ) ).toString(); #endif #ifdef Q_OS_DARWIN - QString fromCode=st.setting()->value ( sessionId+"/iconvfrom", - ( QVariant ) - "UTF-8" ).toString(); + QString fromCode=st.setting()->value ( sessionId+"/iconvfrom", + ( QVariant ) + "UTF-8" ).toString(); #endif #ifdef Q_OS_LINUX - QString fromCode=st.setting()->value ( sessionId+"/iconvfrom", - ( QVariant ) tr ( - "ISO8859-1" ) ).toString(); + QString fromCode=st.setting()->value ( sessionId+"/iconvfrom", + ( QVariant ) tr ( + "ISO8859-1" ) ).toString(); #endif - cbFsConv->setChecked ( st.setting()->value ( sessionId+"/useiconv", - ( QVariant ) false ).toBool() ); - slot_convClicked(); + cbFsConv->setChecked ( st.setting()->value ( sessionId+"/useiconv", + ( QVariant ) false ).toBool() ); + slot_convClicked(); - int ind=cbFrom->findText ( fromCode ); - if ( ind !=-1 ) - cbFrom->setCurrentIndex ( ind ); + int ind=cbFrom->findText ( fromCode ); + if ( ind !=-1 ) + cbFrom->setCurrentIndex ( ind ); - ind=cbTo->findText ( toCode ); - if ( ind !=-1 ) - cbTo->setCurrentIndex ( ind ); + ind=cbTo->findText ( toCode ); + if ( ind !=-1 ) + cbTo->setCurrentIndex ( ind ); - for ( int i=0;i<lst.size();++i ) - { + for ( int i=0; i<lst.size(); ++i ) + { #ifndef Q_OS_WIN - QStringList tails=lst[i].split ( ":",QString::SkipEmptyParts ); + QStringList tails=lst[i].split ( ":",QString::SkipEmptyParts ); #else - QStringList tails=lst[i].split ( "#",QString::SkipEmptyParts ); + QStringList tails=lst[i].split ( "#",QString::SkipEmptyParts ); #endif - QStandardItem *item; - item= new QStandardItem ( tails[0] ); - model->setItem ( model->rowCount(),0,item ); - item= new QStandardItem(); - item->setCheckable ( true ); - if ( tails[1]=="1" ) - item->setCheckState ( Qt::Checked ); - model->setItem ( model->rowCount()-1,1,item ); - } + QStandardItem *item; + item= new QStandardItem ( tails[0] ); + model->setItem ( model->rowCount(),0,item ); + item= new QStandardItem(); + item->setCheckable ( true ); + if ( tails[1]=="1" ) + item->setCheckState ( Qt::Checked ); + model->setItem ( model->rowCount()-1,1,item ); + } } void ShareWidget::setDefaults() { - cbFsSshTun->setChecked ( true ); + cbFsSshTun->setChecked ( true ); - QString toCode="UTF-8"; + QString toCode="UTF-8"; #ifdef Q_OS_WIN - QString fromCode=tr ( "WINDOWS-1252" ); + QString fromCode=tr ( "WINDOWS-1252" ); #endif #ifdef Q_OS_DARWIN - QString fromCode="UTF-8"; + QString fromCode="UTF-8"; #endif #ifdef Q_OS_LINUX - QString fromCode=tr ( "ISO8859-1" ); + QString fromCode=tr ( "ISO8859-1" ); #endif - cbFsConv->setChecked ( false ); - slot_convClicked(); + cbFsConv->setChecked ( false ); + slot_convClicked(); - int ind=cbFrom->findText ( fromCode ); - if ( ind !=-1 ) - cbFrom->setCurrentIndex ( ind ); - ind=cbTo->findText ( toCode ); - if ( ind !=-1 ) - cbTo->setCurrentIndex ( ind ); + int ind=cbFrom->findText ( fromCode ); + if ( ind !=-1 ) + cbFrom->setCurrentIndex ( ind ); + ind=cbTo->findText ( toCode ); + if ( ind !=-1 ) + cbTo->setCurrentIndex ( ind ); } void ShareWidget::saveSettings() { - X2goSettings st ( "sessions" ); - st.setting()->setValue ( sessionId+"/fstunnel", - ( QVariant ) cbFsSshTun->isChecked() ); + X2goSettings st ( "sessions" ); + st.setting()->setValue ( sessionId+"/fstunnel", + ( QVariant ) cbFsSshTun->isChecked() ); - QString exportDirs; - for ( int i=0;i<model->rowCount();++i ) - { + QString exportDirs; + for ( int i=0; i<model->rowCount(); ++i ) + { #ifndef Q_OS_WIN - exportDirs+=model->index ( i,0 ).data().toString() +":"; + exportDirs+=model->index ( i,0 ).data().toString() +":"; #else - exportDirs+=model->index ( i,0 ).data().toString() +"#"; + exportDirs+=model->index ( i,0 ).data().toString() +"#"; #endif - if ( model->item ( i,1 )->checkState() ==Qt::Checked ) - exportDirs+="1;"; - else - exportDirs+="0;"; - } - st.setting()->setValue ( sessionId+"/export", ( QVariant ) exportDirs ); + if ( model->item ( i,1 )->checkState() ==Qt::Checked ) + exportDirs+="1;"; + else + exportDirs+="0;"; + } + st.setting()->setValue ( sessionId+"/export", ( QVariant ) exportDirs ); - st.setting()->setValue ( sessionId+"/iconvto",cbTo->currentText() ); - st.setting()->setValue ( sessionId+"/iconvfrom",cbFrom->currentText() ); - st.setting()->setValue ( sessionId+"/useiconv",cbFsConv->isChecked() ); - st.setting()->sync(); + st.setting()->setValue ( sessionId+"/iconvto",cbTo->currentText() ); + st.setting()->setValue ( sessionId+"/iconvfrom",cbFrom->currentText() ); + st.setting()->setValue ( sessionId+"/useiconv",cbFsConv->isChecked() ); + st.setting()->sync(); } void ShareWidget::loadEnc ( QComboBox* cb ) { - QFile file ( ":/txt/encodings" ); - if ( !file.open ( QIODevice::ReadOnly | QIODevice::Text ) ) - return; - - QTextStream in ( &file ); - while ( !in.atEnd() ) - { - QString line = in.readLine(); - line=line.replace ( "//","" ); - cb->addItem ( line ); - } + QFile file ( ":/txt/encodings" ); + if ( !file.open ( QIODevice::ReadOnly | QIODevice::Text ) ) + return; + + QTextStream in ( &file ); + while ( !in.atEnd() ) + { + QString line = in.readLine(); + line=line.replace ( "//","" ); + cb->addItem ( line ); + } } void ShareWidget::slot_convClicked() { - bool val=cbFsConv->isChecked(); - cbTo->setEnabled ( val ); - cbFrom->setEnabled ( val ); - lTo->setEnabled ( val ); - lFrom->setEnabled ( val ); + bool val=cbFsConv->isChecked(); + cbTo->setEnabled ( val ); + cbFrom->setEnabled ( val ); + lTo->setEnabled ( val ); + lFrom->setEnabled ( val ); } diff --git a/sshmasterconnection.cpp b/sshmasterconnection.cpp index 0672eb0..9a81853 100644 --- a/sshmasterconnection.cpp +++ b/sshmasterconnection.cpp @@ -47,13 +47,104 @@ #define PROXYTUNNELPORT 44444 #undef DEBUG -// #define DEBUG +#define DEBUG #undef SSH_DEBUG // #define SSH_DEBUG static bool isLibSshInited=false; + +#ifdef Q_OS_WIN +#include <QSettings> +// parse known_hosts file from libssh and export keys in registry to use with plink.exe +void SshMasterConnection::parseKnownHosts() +{ + QFile fl(mainWnd->getHomeDirectory()+"/ssh/known_hosts"); + if (!fl.open(QFile::ReadOnly)) + return; + QSettings settings("HKEY_CURRENT_USER\\Software\\SimonTatham\\PuTTY\\SshHostKeys", + QSettings::NativeFormat); + while (!fl.atEnd()) + { + QString line=fl.readLine(); + QStringList parts=line.split(' ',QString::SkipEmptyParts); + if (parts.count()!=3) + continue; + + //lines in known_hosts have format: + //[host]:port <ssh-rsa|ssh-dss> <key> + //we proceeding only lines from libssh - no hashed hostnames + //or patterns are allowed + + QString type="unknown"; + QString port="22"; + if (parts[1]=="ssh-dss") + type="dss"; + if (parts[1]=="ssh-rsa") + type="rsa2"; + + + QStringList hostParts=parts[0].split(":",QString::SkipEmptyParts); + if (hostParts.count()>1) + port=hostParts[1]; + hostParts[0].replace("[",""); + hostParts[0].replace("]",""); + + QString keyName=type+"@"+port+":"+hostParts[0]; + + QByteArray bytes=QByteArray::fromBase64(parts[2].toAscii()); + QStringList fields; + + //key is a set of data fields: + //[size][data][size][data].....[size][data] + + for (int i=0; i<bytes.count();) + { + int size=0; + //first 4 bytes are for size of data fild (big-endian) + for (int j=0; j<4; ++j) + { + size+=((uchar)(bytes[i])) * pow(256,3-j); + i++; + } + QByteArray data; + data=bytes.mid(i,size); + QString hex; + + for (int j=0; j<data.count(); ++j) + { + QString byte; + byte.sprintf("%02x",(uchar)(data[j])); + hex+=byte; + } + //remove leading '0' + for (;;) + { + if (hex.length()==0) + break; + if (hex[0]=='0') + hex.remove(0,1); + else + break; + } + hex="0x"+hex; + fields<<hex; + i+=size; + } + //first element is a type of key, we don't need it + fields.removeFirst(); + settings.setValue(keyName,fields.join(",")); +#ifdef DEBUG + x2goDebug<<"writing key in registry: HKEY_CURRENT_USER\\Software\\SimonTatham\\PuTTY\\SshHostKeys"<<endl; + x2goDebug<<keyName<<"="<<fields.join(",")<<endl; +#endif + } + settings.sync(); +} +#endif + + SshMasterConnection::SshMasterConnection (QObject* parent, QString host, int port, bool acceptUnknownServers, QString user, QString pass, QString key, bool autologin, bool krblogin, bool useproxy, ProxyType type, QString proxyserver, quint16 proxyport, @@ -92,11 +183,14 @@ SshMasterConnection::SshMasterConnection (QObject* parent, QString host, int por kerberos=krblogin; #ifdef DEBUG if (kerberos) + { x2goDebug<<"starting ssh connection with kerberos authentication"<<endl; + } else + { x2goDebug<<"starting ssh connection without kerberos authentication"<<endl; + } #endif - kerberos=false; #ifdef DEBUG x2goDebug<<"SshMasterConnection, instance "<<this<<" created"; #endif @@ -359,6 +453,11 @@ void SshMasterConnection::run() #ifdef Q_OS_WIN ssh_options_set ( my_ssh_session, SSH_OPTIONS_SSH_DIR, (mainWnd->getHomeDirectory()+"/ssh").toAscii()); + if (kerberos) + { + parseKnownHosts(); + } + #endif ssh_options_set(my_ssh_session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity); @@ -496,7 +595,13 @@ void SshMasterConnection::run() } QString err; if (!kerberos) + { err=ssh_get_error ( my_ssh_session ); + } + else + { + err=sshProcErrString; + } QString message=tr ( "Authentication failed" ); #ifdef DEBUG x2goDebug<<message<<" - "<<err; @@ -870,9 +975,63 @@ bool SshMasterConnection::userAuthWithKey() return true; } +bool SshMasterConnection::userAuthKrb() +{ + QProcess ssh; + QString sshCmd; + +#ifdef Q_OS_WIN + sshCmd="plink -batch "+user+"@"+host+" -P "+ + QString::number(port)+ " whoami"; +#else + sshCmd="ssh -o GSSApiAuthentication=yes "+user+"@"+host+" -p "+ + QString::number(port)+ " -o PasswordAuthentication=no whoami"; +#endif + +#ifdef DEBUG + x2goDebug<<"starting ssh:" <<sshCmd<<endl; +#endif + ssh.start(sshCmd); + + + if (!ssh.waitForStarted(5000)) + { + sshProcErrString=ssh.errorString(); + authErrors<<sshProcErrString; +#ifdef DEBUG + x2goDebug<<"ssh start failed:" <<sshProcErrString<<endl; +#endif + return false; + } + if (!ssh.waitForFinished(20000)) + { + sshProcErrString=ssh.errorString(); + authErrors<<sshProcErrString; +#ifdef DEBUG + x2goDebug<<"ssh not finished:" <<sshProcErrString<<endl; +#endif + return false; + } + QString outp=ssh.readAllStandardOutput(); + QString err=ssh.readAllStandardError(); +#ifdef DEBUG + x2goDebug<<"ssh exited\n"; + x2goDebug<<"stdout - "<<outp<<endl; + x2goDebug<<"stderr - "<<err<<endl; + x2goDebug<<"code - "<<ssh.exitCode()<<", status - "<<ssh.exitStatus()<<endl; +#endif + if (ssh.exitCode() == 0 && ssh.exitStatus() == 0) + return true; + sshProcErrString=err; + authErrors<<sshProcErrString; + return false; +} + bool SshMasterConnection::userAuth() { + if (kerberos) + return userAuthKrb(); if ( autologin && key=="" ) if ( userAuthAuto() ) return true; diff --git a/sshmasterconnection.h b/sshmasterconnection.h index 43ad7f6..dda9772 100644 --- a/sshmasterconnection.h +++ b/sshmasterconnection.h @@ -114,6 +114,7 @@ private: bool userAuthAuto(); bool userAuthWithKey(); bool userAuth(); + bool userAuthKrb(); void channelLoop(); void finalize(int arg1); void copy(); diff --git a/sshprocess.cpp b/sshprocess.cpp index 1813142..69a057e 100644 --- a/sshprocess.cpp +++ b/sshprocess.cpp @@ -22,14 +22,20 @@ #include <QTimer> #include <QUuid> +#include <QProcess> #ifndef Q_OS_WIN #include <arpa/inet.h> #include <netinet/tcp.h> #endif #undef DEBUG -// #define DEBUG +#define DEBUG +#ifdef Q_OS_DARWIN +#define KEEPALIVE_OPTION " -o ServerAliveInterval=60 " +#else +#define KEEPALIVE_OPTION " -o ProtocolKeepAlives=60 " +#endif SshProcess::SshProcess(SshMasterConnection* master, int pid): QObject(0) { @@ -40,6 +46,8 @@ SshProcess::SshProcess(SshMasterConnection* master, int pid): QObject(0) tunnel=false; normalExited=true; this->pid=pid; + proc=0l; + execProcess=false; } SshProcess::~SshProcess() @@ -47,6 +55,25 @@ SshProcess::~SshProcess() #ifdef DEBUG x2goDebug<<"ssh process destructor"; #endif + + if (proc) + { + if (tunnel) + { + disconnect(proc,SIGNAL(finished(int,QProcess::ExitStatus)),this, + SLOT(slotSshProcFinished(int,QProcess::ExitStatus))); + disconnect(proc,SIGNAL(readyReadStandardError()),this,SLOT(slotSshProcStdErr())); + disconnect(proc,SIGNAL(readyReadStandardOutput()),this,SLOT(slotSshProcStdOut())); + } + if (proc->state()==QProcess::Running && execProcess) + { + if(!proc->waitForFinished(3000)) + { + proc->terminate(); + } + } + delete proc; + } if (serverSocket>0) { #ifdef Q_OS_WIN @@ -131,41 +158,153 @@ void SshProcess::startNormal(const QString& cmd) { QUuid uuid = QUuid::createUuid(); QString uuidStr = uuid.toString().mid(1, 36).toLower(); + execProcess=true; - QString shcmd = "sh -c \"echo X2GODATABEGIN:" + uuidStr + "; "+cmd+"; echo X2GODATAEND:" + uuidStr +"\";"; //#ifdef DEBUG // ONLY UNCOMMENT FOR TESTING, MIGHT REVEAL PASSWORD WHEN command=RDP // x2goDebug<<"executing remote command: "<<shcmd<<endl; // #endif - masterCon->addChannelConnection(this, uuidStr, shcmd); - connect(masterCon,SIGNAL(stdOut(SshProcess*,QByteArray)),this,SLOT(slotStdOut(SshProcess*,QByteArray))); - connect(masterCon,SIGNAL(channelClosed(SshProcess*,QString)), this,SLOT(slotChannelClosed(SshProcess*,QString))); + if(!masterCon->useKerberos()) + { + QString shcmd = "sh -c \"echo X2GODATABEGIN:" + uuidStr + "; "+cmd+"; echo X2GODATAEND:" + uuidStr +"\";"; + masterCon->addChannelConnection(this, uuidStr, shcmd); + connect(masterCon,SIGNAL(stdOut(SshProcess*,QByteArray)),this,SLOT(slotStdOut(SshProcess*,QByteArray))); + connect(masterCon,SIGNAL(channelClosed(SshProcess*,QString)), this,SLOT(slotChannelClosed(SshProcess*,QString))); + } + else + { + QString shcmd = "echo X2GODATABEGIN:" + uuidStr + "; "+cmd+"; echo X2GODATAEND:" + uuidStr; + proc=new QProcess(this); +#ifdef Q_OS_WIN + QString sshString="plink -batch -P "+ +#else + QString sshString=QString::null+"ssh"+ KEEPALIVE_OPTION +"-o GSSApiAuthentication=yes -o PasswordAuthentication=no -p "+ +#endif + QString::number(masterCon->getPort())+" "+ + masterCon->getUser()+"@"+ masterCon->getHost() + " \""+shcmd+"\""; +#ifdef DEBUG + x2goDebug<<"running ssh:" <<sshString<<endl; +#endif + procUuid=uuidStr; + proc->start(sshString); + + if (!proc->waitForStarted(5000)) + { + stdErrString=proc->errorString(); +#ifdef DEBUG + x2goDebug<<"ssh start failed:" <<stdErrString<<endl; +#endif + slotChannelClosed(this, uuidStr); + return; + } + connect(proc,SIGNAL(finished(int,QProcess::ExitStatus)),this, + SLOT(slotSshProcFinished(int,QProcess::ExitStatus))); + connect(proc,SIGNAL(readyReadStandardError()),this,SLOT(slotSshProcStdErr())); + connect(proc,SIGNAL(readyReadStandardOutput()),this,SLOT(slotSshProcStdOut())); + } + } void SshProcess::start_cp(QString src, QString dst) { - connect(masterCon, SIGNAL(copyErr(SshProcess*,QString,QString)), this, - SLOT(slotCopyErr(SshProcess*,QString,QString))); - connect(masterCon, SIGNAL(copyOk(SshProcess*)), this,SLOT(slotCopyOk(SshProcess*))); scpSource=src; - masterCon->addCopyRequest(this,src,dst); + if(!masterCon->useKerberos()) + { + connect(masterCon, SIGNAL(copyErr(SshProcess*,QString,QString)), this, + SLOT(slotCopyErr(SshProcess*,QString,QString))); + connect(masterCon, SIGNAL(copyOk(SshProcess*)), this,SLOT(slotCopyOk(SshProcess*))); + masterCon->addCopyRequest(this,src,dst); + } + else + { + proc=new QProcess(this); +#ifdef Q_OS_WIN +//pscp don't working with paths like "~user" +//I hope a home directories of your users are in /home/ + dst.replace("~"+masterCon->getUser(),"/home/"+masterCon->getUser()); + dst.replace("~","/home/"+masterCon->getUser()); + + QString sshString="pscp -batch -P "+ +#else + QString sshString="scp -o GSSApiAuthentication=yes -o PasswordAuthentication=no -P "+ +#endif + QString::number(masterCon->getPort())+" "+src+" "+ + masterCon->getUser()+"@"+ masterCon->getHost()+":"+dst; +#ifdef DEBUG + x2goDebug<<"running scp:" <<sshString<<endl; +#endif + proc->start(sshString); + + if (!proc->waitForStarted(5000)) + { + stdErrString=proc->errorString(); +#ifdef DEBUG + x2goDebug<<"ssh start failed:" <<stdErrString<<endl; +#endif + slotChannelClosed(this,""); + return; + } + connect(proc,SIGNAL(finished(int,QProcess::ExitStatus)),this, + SLOT(slotSshProcFinished(int,QProcess::ExitStatus))); + connect(proc,SIGNAL(readyReadStandardError()),this,SLOT(slotSshProcStdErr())); + connect(proc,SIGNAL(readyReadStandardOutput()),this,SLOT(slotSshProcStdOut())); + } } 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(); + if(!masterCon->useKerberos()) + { + this->forwardHost=forwardHost; + this->forwardPort=forwardPort; + this->localHost=localHost; + this->localPort=localPort; + if (!reverse) + tunnelLoop(); + else + { + connect(masterCon, SIGNAL(reverseListenOk(SshProcess*)), this, SLOT(slotReverseTunnelOk(SshProcess*))); + tunnelConnection=masterCon->reverseTunnelConnection(this, forwardPort, localHost, localPort); + } + } else { - connect(masterCon, SIGNAL(reverseListenOk(SshProcess*)), this, SLOT(slotReverseTunnelOk(SshProcess*))); - tunnelConnection=masterCon->reverseTunnelConnection(this, forwardPort, localHost, localPort); + proc=new QProcess(this); +#ifdef Q_OS_WIN + QString sshString="plink -batch -P "+ +#else + QString sshString=QString::null+"ssh"+ KEEPALIVE_OPTION +"-o GSSApiAuthentication=yes -o PasswordAuthentication=no -p "+ +#endif + QString::number(masterCon->getPort())+" "+ + masterCon->getUser()+"@"+ + masterCon->getHost() + " -N "; + if (!reverse) + sshString+=" -L " + QString::number(localPort)+":"+forwardHost+":"+QString::number(forwardPort); + else + sshString+=" -R "+ QString::number(forwardPort)+":"+forwardHost+":"+QString::number(localPort); + +#ifdef DEBUG + x2goDebug<<"running ssh:" <<sshString<<endl; +#endif + proc->start(sshString); + + if (!proc->waitForStarted(5000)) + { + stdErrString=proc->errorString(); +#ifdef DEBUG + x2goDebug<<"ssh start failed:" <<stdErrString<<endl; +#endif + slotChannelClosed(this,""); + return; + } + connect(proc,SIGNAL(finished(int,QProcess::ExitStatus)),this, + SLOT(slotSshProcFinished(int,QProcess::ExitStatus))); + connect(proc,SIGNAL(readyReadStandardError()),this,SLOT(slotSshProcStdErr())); + connect(proc,SIGNAL(readyReadStandardOutput()),this,SLOT(slotSshProcStdOut())); + emit sshTunnelOk(pid); } } @@ -228,6 +367,10 @@ void SshProcess::slotChannelClosed(SshProcess* creator, QString uuid) if (!normalExited) { output=abortString; + if (output.length()<5) + { + output=stdErrString; + } } else { @@ -239,7 +382,8 @@ void SshProcess::slotChannelClosed(SshProcess* creator, QString uuid) x2goDebug<<"have only stderr, something must be wrong"<<endl; #endif } - else { + else + { QString begin_marker = "X2GODATABEGIN:"+uuid+"\n"; QString end_marker = "X2GODATAEND:"+uuid+"\n"; int output_begin=stdOutString.indexOf(begin_marker) + begin_marker.length(); @@ -248,7 +392,28 @@ void SshProcess::slotChannelClosed(SshProcess* creator, QString uuid) } } #ifdef DEBUG - x2goDebug<<"ssh finished:"<<normalExited<<" - "<<output<<endl; + x2goDebug<<"ssh finished:"<<normalExited<<" - "<<output<<uuid<<endl; #endif emit sshFinished(normalExited, output, pid); } + +void SshProcess::slotSshProcFinished(int exitCode, QProcess::ExitStatus exitStatus) +{ + normalExited=false; + if (exitCode==0 && exitStatus==QProcess::NormalExit) + normalExited=true; +#ifdef DEBUG + x2goDebug<<"ssh process exit code :"<<exitStatus; +#endif + slotChannelClosed(this,procUuid); +} + +void SshProcess::slotSshProcStdErr() +{ + slotStdErr(this, proc->readAllStandardError()); +} + +void SshProcess::slotSshProcStdOut() +{ + slotStdOut(this, proc->readAllStandardOutput()); +} diff --git a/sshprocess.h b/sshprocess.h index caddb3f..d1e05bf 100644 --- a/sshprocess.h +++ b/sshprocess.h @@ -20,14 +20,13 @@ #include <libssh/libssh.h> #include <QObject> - +#include <QProcess> #ifndef Q_OS_WIN #include <netinet/in.h> #endif #include "sshmasterconnection.h" - class SshProcess : public QObject { Q_OBJECT @@ -70,7 +69,10 @@ private: QString abortString; bool tunnel; bool normalExited; - +//only to use with krb (until no GSSAPI support in libssh) + QProcess* proc; + QString procUuid; + bool execProcess; private slots: void slotCheckNewConnection(); @@ -81,6 +83,10 @@ private slots: void slotReverseTunnelOk(SshProcess* creator); void slotCopyOk(SshProcess* creator); void slotCopyErr(SshProcess* creator,QString message, QString sshSessionErr); + //krb stuff + void slotSshProcFinished( int exitCode, QProcess::ExitStatus exitStatus); + void slotSshProcStdErr(); + void slotSshProcStdOut(); signals: void sshFinished ( bool result, QString output, int processId); void sshTunnelOk(int processId); hooks/post-receive -- x2goclient.git (X2Go Client) 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 "x2goclient.git" (X2Go Client).