This is an automated email from the git hooks/post-receive script. x2go pushed a change to branch master in repository x2goclient. from f17597a src/onmainwindow.cpp: do not automatically set login user name to current system user if empty. new 68bbf32 Interaction with SSH server (for example for changing expired password). Fixes: #592. The 1 revisions listed above as "new" are entirely new to this repository and will be described in separate emails. The revisions listed as "adds" were already present in the repository and have only been added to this reference. Summary of changes: debian/changelog | 2 + src/InteractionDialog.cpp | 132 +++++++++++++++++++++++ src/{exportdialog.h => InteractionDialog.h} | 60 ++++++----- src/onmainwindow.cpp | 59 +++++++++- src/onmainwindow.h | 6 ++ src/onmainwindow_privat.h | 1 + src/sshmasterconnection.cpp | 160 +++++++++++++++++++++++++++- src/sshmasterconnection.h | 11 ++ src/x2goclient.cpp | 1 + x2goclient.pro | 2 + 10 files changed, 400 insertions(+), 34 deletions(-) create mode 100644 src/InteractionDialog.cpp copy src/{exportdialog.h => InteractionDialog.h} (65%) -- Alioth's /srv/git/code.x2go.org/x2goclient.git//..//_hooks_/post-receive-email on /srv/git/code.x2go.org/x2goclient.git
This is an automated email from the git hooks/post-receive script. x2go pushed a commit to branch master in repository x2goclient. commit 68bbf328132125eaad5c53b0ac82490bf818e42e Author: Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> Date: Wed May 10 15:22:11 2017 +0200 Interaction with SSH server (for example for changing expired password). Fixes: #592. --- debian/changelog | 2 + src/InteractionDialog.cpp | 132 ++++++++++++++++++++++++++++++++++++ src/InteractionDialog.h | 59 ++++++++++++++++ src/onmainwindow.cpp | 59 ++++++++++++++-- src/onmainwindow.h | 6 ++ src/onmainwindow_privat.h | 1 + src/sshmasterconnection.cpp | 160 +++++++++++++++++++++++++++++++++++++++++++- src/sshmasterconnection.h | 11 +++ src/x2goclient.cpp | 1 + x2goclient.pro | 2 + 10 files changed, 428 insertions(+), 5 deletions(-) diff --git a/debian/changelog b/debian/changelog index 57e48d8..40e262f 100644 --- a/debian/changelog +++ b/debian/changelog @@ -155,6 +155,8 @@ x2goclient (4.1.0.1-0x2go1) UNRELEASED; urgency=medium - Disable sound button on direct RDP and XDMCP sessions. Set for direct XDMCP session autologin=true. Set for direct XDMCP session username=XDM. + - Interaction with SSH server (for example for changing + expired password). Fixes: #592. [ Robert Parts ] * New upstream version (4.1.0.1): diff --git a/src/InteractionDialog.cpp b/src/InteractionDialog.cpp new file mode 100644 index 0000000..eac7a23 --- /dev/null +++ b/src/InteractionDialog.cpp @@ -0,0 +1,132 @@ +/************************************************************************** +* Copyright (C) 2005-2017 by Oleksandr Shneyder * +* o.shneyder@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, see <http://www.gnu.org/licenses/>. * +***************************************************************************/ + +#include "InteractionDialog.h" +#include "x2goclientconfig.h" +#include "onmainwindow.h" +#include <QTextEdit> +#include <QVBoxLayout> +#include <QPushButton> +#include <QLabel> +#include <QLineEdit> + +InteractionDialog::InteractionDialog(QWidget* parent): SVGFrame(":/img/svg/passform.svg", + false,parent ) +{ + mw=(ONMainWindow*)parent; + mw->setWidgetStyle(this); + + if ( !mw->retMiniMode() ) + setFixedSize ( this->sizeHint().width(),this->sizeHint().height()*1.5 ); + else + setFixedSize ( 310,280 ); + + + QPalette pal=this->palette(); + pal.setBrush ( QPalette::Window, QColor ( 255,255,255,0 ) ); + pal.setColor ( QPalette::Active, QPalette::WindowText, QPalette::Mid ); + pal.setColor ( QPalette::Active, QPalette::ButtonText, QPalette::Mid ); + pal.setColor ( QPalette::Active, QPalette::Text, QPalette::Mid ); + pal.setColor ( QPalette::Inactive, QPalette::WindowText, QPalette::Mid ); + pal.setColor ( QPalette::Inactive, QPalette::ButtonText, QPalette::Mid ); + pal.setColor ( QPalette::Inactive, QPalette::Text, QPalette::Mid ); + + this->setPalette ( pal ); + + pal.setColor ( QPalette::Button, QColor ( 255,255,255,0 ) ); + pal.setColor ( QPalette::Window, QColor ( 255,255,255,255 ) ); + pal.setColor ( QPalette::Base, QColor ( 255,255,255,255 ) ); + + QFont fnt=this->font(); + if ( mw->retMiniMode() ) +#ifdef Q_WS_HILDON + fnt.setPointSize ( 10 ); +#else + fnt.setPointSize ( 9 ); +#endif + this->setFont ( fnt ); + this->hide(); + + textEdit=new QTextEdit(this); + QVBoxLayout* lay=new QVBoxLayout(this); + lay->addWidget(new QLabel(tr("Terminal output:"))); + lay->addWidget(textEdit); + + textEntry=new QLineEdit(this); + textEntry->setEchoMode(QLineEdit::NoEcho); + lay->addWidget(textEntry); + mw->setWidgetStyle(textEntry); + + cancelButton=new QPushButton(tr("Cancel"),this); + lay->addWidget(cancelButton); + mw->setWidgetStyle(textEdit); + textEdit->setReadOnly(true); + mw->setWidgetStyle(textEdit->viewport()); + mw->setWidgetStyle((QWidget*)textEdit->verticalScrollBar()); + mw->setWidgetStyle(cancelButton); + connect(textEntry,SIGNAL(returnPressed()),this,SLOT(slotTextEntered())); + connect(cancelButton, SIGNAL(clicked(bool)),this,SLOT(slotButtonPressed())); +} + +InteractionDialog::~InteractionDialog() +{ +// qDebug()<<"Iter dlg destruct\n"; +} + +void InteractionDialog::appendText(QString txt) +{ + textEntry->setEnabled(true); + textEdit->append(txt); + textEntry->setFocus(); + interrupted=false; + display=false; + cancelButton->setText(tr("Cancel")); +} + +void InteractionDialog::reset() +{ + textEdit->clear(); +} + +void InteractionDialog::slotTextEntered() +{ + QString text=textEntry->text()+"\n"; + textEntry->clear(); + emit textEntered(text); +} + +void InteractionDialog::slotButtonPressed() +{ + if(!display) + { + emit interrupt(); + interrupted=true; + } + else + { + qDebug()<<"reconnect"; + emit closeInterractionDialog(); + } +} + +void InteractionDialog::setDisplayMode() +{ + cancelButton->setText(tr("Reconnect")); + textEntry->setEnabled(false); + display=true; +} + diff --git a/src/InteractionDialog.h b/src/InteractionDialog.h new file mode 100644 index 0000000..e2ddf43 --- /dev/null +++ b/src/InteractionDialog.h @@ -0,0 +1,59 @@ +/************************************************************************** +* Copyright (C) 2005-2017 by Oleksandr Shneyder * +* o.shneyder@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, see <http://www.gnu.org/licenses/>. * +***************************************************************************/ + +#ifndef INTERACTIONDIALOG_H +#define INTERACTIONDIALOG_H +#include "x2goclientconfig.h" + + +#include "SVGFrame.h" + +class ONMainWindow; +class QTextEdit; +class QLineEdit; +class QPushButton; +class InteractionDialog: public SVGFrame +{ + + Q_OBJECT +public: + InteractionDialog ( QWidget* parent=0); + virtual ~InteractionDialog(); + void reset(); + void appendText(QString txt); + bool isInterrupted() { + return interrupted; + } + void setDisplayMode(); +private: + ONMainWindow* mw; + QTextEdit* textEdit; + QPushButton* cancelButton; + QLineEdit* textEntry; + bool interrupted; + bool display; +private slots: + void slotTextEntered(); + void slotButtonPressed(); +signals: + void textEntered(QString text); + void interrupt(); + void closeInterractionDialog(); +}; + +#endif + diff --git a/src/onmainwindow.cpp b/src/onmainwindow.cpp index 6107c76..d346af3 100644 --- a/src/onmainwindow.cpp +++ b/src/onmainwindow.cpp @@ -446,6 +446,9 @@ ONMainWindow::ONMainWindow ( QWidget *parent ) :QMainWindow ( parent ) initPassDlg(); initSelectSessDlg(); initStatusDlg(); + interDlg=new InteractionDialog(bgFrame); + connect(interDlg, SIGNAL(closeInterractionDialog()), this, SLOT(slotCloseInteractionDialog())); + username->addWidget ( interDlg ); #if defined(CFGPLUGIN) && defined(Q_OS_LINUX) @@ -2920,6 +2923,13 @@ SshMasterConnection* ONMainWindow::startSshConnection ( QString host, QString po connect ( con, SIGNAL ( userAuthError ( QString ) ),this,SLOT ( slotSshUserAuthError ( QString ) ) ); connect ( con, SIGNAL ( connectionError ( QString,QString ) ), this, SLOT ( slotSshConnectionError ( QString,QString ) ) ); + connect ( con, SIGNAL(startInteraction(SshMasterConnection*,QString)),this, + SLOT(slotSshInteractionStart(SshMasterConnection*,QString)) ); + connect ( con, SIGNAL(updateInteraction(SshMasterConnection*,QString)),this, + SLOT(slotSshInteractionUpdate(SshMasterConnection*,QString)) ); + connect (con, SIGNAL(finishInteraction(SshMasterConnection*)),this, SLOT(slotSshInteractionFinish(SshMasterConnection*))); + connect ( interDlg, SIGNAL(textEntered(QString)), con, SLOT(interactionTextEnter(QString))); + connect ( interDlg, SIGNAL(interrupt()), con, SLOT(interactionInterruptSlot())); con->start(); return con; } @@ -3008,6 +3018,44 @@ void ONMainWindow::slotServSshConnectionOk(QString server) con->executeCommand( "export HOSTNAME && x2golistsessions", this, SLOT (slotListAllSessions ( bool,QString,int ) )); } +void ONMainWindow::slotSshInteractionFinish(SshMasterConnection* connection) +{ + if(interDlg->isInterrupted()) + { + slotCloseInteractionDialog(); + } + else + { + interDlg->setDisplayMode(); + } +} + +void ONMainWindow::slotCloseInteractionDialog() +{ + slotSshUserAuthError("NO_ERROR"); +} + + + +void ONMainWindow::slotSshInteractionStart(SshMasterConnection* connection, QString prompt) +{ + sessionStatusDlg->hide(); + interDlg->show(); + interDlg->reset(); + interDlg->appendText(prompt); + + setEnabled(true); + interDlg->setEnabled(true); + x2goDebug<<"SSH Session prompt:"<<prompt; + +} + +void ONMainWindow::slotSshInteractionUpdate(SshMasterConnection* connection, QString output) +{ + interDlg->appendText(output); + x2goDebug<<"SSH Interaction update:"<<output; +} + void ONMainWindow::slotSshServerAuthPassphrase(SshMasterConnection* connection, bool verificationCode) { bool ok; @@ -3069,6 +3117,7 @@ void ONMainWindow::slotSshServerAuthChallengeResponse(SshMasterConnection* conne void ONMainWindow::slotSshServerAuthError ( int error, QString sshMessage, SshMasterConnection* connection ) { + interDlg->hide(); if ( startHidden ) { startHidden=false; @@ -3179,6 +3228,7 @@ void ONMainWindow::slotSshServerAuthError ( int error, QString sshMessage, SshMa void ONMainWindow::slotSshUserAuthError ( QString error ) { + interDlg->hide(); if ( sshConnection ) { sshConnection->wait(); @@ -3201,9 +3251,10 @@ void ONMainWindow::slotSshUserAuthError ( QString error ) trayQuit(); } - QMessageBox::critical (0l, tr ("Authentication failed."), - error, QMessageBox::Ok, - QMessageBox::NoButton); + if(error != "NO_ERROR") + QMessageBox::critical (0l, tr ("Authentication failed."), + error, QMessageBox::Ok, + QMessageBox::NoButton); setEnabled ( true ); passForm->setEnabled ( true ); slotShowPassForm(); @@ -3752,6 +3803,7 @@ bool ONMainWindow::startSession ( const QString& sid ) void ONMainWindow::slotListSessions ( bool result,QString output, int ) { + interDlg->hide(); x2goDebug<<output; if ( result==false ) { @@ -12318,7 +12370,6 @@ void ONMainWindow::initSelectSessDlg() } - void ONMainWindow::printSshDError_startupFailure() { if ( closeEventSent ) diff --git a/src/onmainwindow.h b/src/onmainwindow.h index d2e5399..c38e50c 100644 --- a/src/onmainwindow.h +++ b/src/onmainwindow.h @@ -88,6 +88,7 @@ class QStandardItemModel; class HttpBrokerClient; class QMenu; class QComboBox; +class InteractionDialog; class SessionExplorer; struct user @@ -577,6 +578,7 @@ public: private: + InteractionDialog* interDlg; QString m_x2goconfig; QStringList _internApplicationsNames; QStringList _transApplicationsNames; @@ -1022,7 +1024,11 @@ private slots: void slotSshConnectionError ( QString message, QString lastSessionError ); void slotSshServerAuthError ( int error, QString sshMessage, SshMasterConnection* connection ); void slotSshServerAuthPassphrase ( SshMasterConnection* connection, bool verificationCode ); + void slotSshInteractionStart ( SshMasterConnection* connection, QString prompt ); + void slotSshInteractionUpdate ( SshMasterConnection* connection, QString output ); + void slotSshInteractionFinish ( SshMasterConnection* connection); void slotSshServerAuthChallengeResponse( SshMasterConnection* connection, QString Challenge ); + void slotCloseInteractionDialog(); void slotSshUserAuthError ( QString error ); void slotSshConnectionOk(); void slotServSshConnectionOk(QString server); diff --git a/src/onmainwindow_privat.h b/src/onmainwindow_privat.h index 817ee0b..92a3c36 100644 --- a/src/onmainwindow_privat.h +++ b/src/onmainwindow_privat.h @@ -33,6 +33,7 @@ #include "printprocess.h" #include "helpdialog.h" #include "appdialog.h" +#include "InteractionDialog.h" #include <QDesktopServices> #include <QApplication> #include <QScrollBar> diff --git a/src/sshmasterconnection.cpp b/src/sshmasterconnection.cpp index f2db295..e3ef249 100644 --- a/src/sshmasterconnection.cpp +++ b/src/sshmasterconnection.cpp @@ -724,7 +724,23 @@ void SshMasterConnection::run() #ifdef DEBUG x2goDebug<<"User authentication OK."; #endif - emit connectionOk(host); + if(checkLogin()) + { + x2goDebug<<"Login Check - OK"; + emit connectionOk(host); + } + else + { + x2goDebug<<"Login Check - Failed"; +// if(!interactionInterrupt) + { + emit finishInteraction(this); + } + ssh_disconnect ( my_ssh_session ); + ssh_free ( my_ssh_session ); + quit(); + return; + } } else { @@ -1502,6 +1518,145 @@ bool SshMasterConnection::userAuthKrb() } +void SshMasterConnection::interactionTextEnter(QString text) +{ + interactionInputMutex.lock(); + interactionInputText=text; + interactionInputMutex.unlock(); +} + +void SshMasterConnection::interactionInterruptSlot() +{ + interactionInputMutex.lock(); + interactionInterrupt=true; + interactionInputMutex.unlock(); +} + +bool SshMasterConnection::checkLogin() +{ + interactionInterrupt=false; + interactionInputText=QString::null; + + + ssh_channel channel = ssh_channel_new ( my_ssh_session ); + + if (!channel) { + QString err = ssh_get_error (my_ssh_session); + QString error_msg = tr ("%1 failed.").arg ("ssh_channel_new"); + +#ifdef DEBUG + x2goDebug << error_msg.left (error_msg.size () - 1) << ": " << err << endl; +#endif + return false; + } + if ( ssh_channel_open_session ( channel ) !=SSH_OK ) + { + QString err=ssh_get_error ( my_ssh_session ); + QString errorMsg=tr ( "%1 failed." ).arg ("ssh_channel_open_session"); +#ifdef DEBUG + x2goDebug<<errorMsg.left (errorMsg.size () - 1)<<": "<<err<<endl; +#endif + return false; + } + if (ssh_channel_request_pty(channel)!=SSH_OK) + { + QString err=ssh_get_error ( my_ssh_session ); + QString errorMsg=tr ( "%1 failed." ).arg ("ssh_channel_request_pty"); +#ifdef DEBUG + x2goDebug<<errorMsg.left (errorMsg.size () - 1)<<": "<<err<<endl; +#endif + return false; + } + if(ssh_channel_change_pty_size(channel, 80, 24)!=SSH_OK) + { + QString err=ssh_get_error ( my_ssh_session ); + QString errorMsg=tr ( "%1 failed." ).arg ("ssh_channel_change_pty_size"); +#ifdef DEBUG + x2goDebug<<errorMsg.left (errorMsg.size () - 1)<<": "<<err<<endl; +#endif + return false; + } + if ( ssh_channel_request_exec ( channel, "echo \"LOGIN OK\"" ) != SSH_OK ) + { + QString err=ssh_get_error ( my_ssh_session ); + QString errorMsg=tr ( "%1 failed." ).arg ("ssh_channel_request_exec"); +#ifdef DEBUG + x2goDebug<<errorMsg.left (errorMsg.size () - 1)<<": "<<err<<endl; +#endif + } + else + { + char buffer[1024*512]; //512K buffer + bool hasInterraction=true; + bool interactionStarted=false; +// x2goDebug<<"CHECK LOGIN channel created."<<endl; + while (ssh_channel_is_open(channel) && + !ssh_channel_is_eof(channel)) + { + int nbytes = ssh_channel_read_nonblocking(channel, buffer, sizeof(buffer), 0); + if (nbytes < 0) + return false; + if (nbytes > 0) + { + QString inf=QByteArray ( buffer,nbytes ); + x2goDebug<<"LOGIN CHECK:"<<inf; + if(inf.indexOf("LOGIN OK")!=-1) + { + x2goDebug<<"don't have interaction"; + hasInterraction=false; + break; + } + else + { + if(!interactionStarted) + { + interactionStarted=true; + emit startInteraction(this, inf); + } + else + emit updateInteraction(this,inf); + } + } + bool interrupt; + interactionInputMutex.lock(); + interrupt=interactionInterrupt; + QString textToSend=interactionInputText; + interactionInputText=QString::null; + interactionInputMutex.unlock(); + if(textToSend.length()>0) + { +// x2goDebug<<"SEND Input to SERVER"; + ssh_channel_write(channel, textToSend.toLocal8Bit().constData(), textToSend.length()); + } + if(interrupt) + { + break; + } + this->usleep(30); + } + + x2goDebug<<"LOOP FINISHED"; + bool retVal=false; + if(!hasInterraction) + { + x2goDebug<<"No interaction needed, continue session"; + retVal=true; + } + else + { + sshProcErrString=tr("Reconnect session"); + x2goDebug<<"Reconnect session"; + } + ssh_channel_close(channel); + ssh_channel_send_eof(channel); + ssh_channel_free(channel); + return retVal; + + } + return false; + +} + bool SshMasterConnection::userAuth() { if (kerberos) @@ -2059,3 +2214,6 @@ void SshMasterConnection::finalize ( int item ) emit channelClosed ( proc, uuid ); } + + + diff --git a/src/sshmasterconnection.h b/src/sshmasterconnection.h index 13499e6..f95f653 100644 --- a/src/sshmasterconnection.h +++ b/src/sshmasterconnection.h @@ -122,6 +122,7 @@ private: bool userAuthAuto(); bool userAuthWithKey(); bool userChallengeAuth(); + bool checkLogin(); bool userAuth(); bool userAuthKrb(); void channelLoop(); @@ -147,6 +148,9 @@ private slots: void slotSshProxyTunnelOk(int); void slotSshProxyTunnelFailed(bool result, QString output, int); +public slots: + void interactionTextEnter(QString text); + void interactionInterruptSlot(); private: ssh_session my_ssh_session; @@ -158,6 +162,9 @@ private: QMutex disconnectFlagMutex; QMutex writeHostKeyMutex; QMutex reverseTunnelRequestMutex; + QMutex interactionInputMutex; + QString interactionInputText; + bool interactionInterrupt; bool writeHostKey; bool writeHostKeyReady; int nextPid; @@ -219,7 +226,11 @@ signals: void needPassPhrase(SshMasterConnection*, bool verificationCode); void needChallengeResponse(SshMasterConnection*, QString Challenge); + void startInteraction(SshMasterConnection*, QString prompt); + void finishInteraction(SshMasterConnection*); + void updateInteraction(SshMasterConnection*, QString output); }; #endif // SSHMASTERCONNECTION_H + diff --git a/src/x2goclient.cpp b/src/x2goclient.cpp index 9879142..0aea78f 100644 --- a/src/x2goclient.cpp +++ b/src/x2goclient.cpp @@ -92,6 +92,7 @@ int fork_helper (int argc, char **argv) { #endif /* defined (Q_OS_UNIX) */ int main (int argc, char **argv) { + return (x2goMain(argc, argv)); #ifdef Q_OS_UNIX /* Scan program arguments for --unixhelper flag. */ bool unix_helper_request = 0; diff --git a/x2goclient.pro b/x2goclient.pro index 6cc8fd5..a1174f2 100644 --- a/x2goclient.pro +++ b/x2goclient.pro @@ -47,6 +47,7 @@ HEADERS += src/configdialog.h \ src/sshmasterconnection.h \ src/sshprocess.h \ src/SVGFrame.h \ + src/InteractionDialog.h \ src/userbutton.h \ src/x2goclientconfig.h \ src/x2gologdebug.h \ @@ -101,6 +102,7 @@ SOURCES += src/sharewidget.cpp \ src/sshmasterconnection.cpp \ src/sshprocess.cpp \ src/SVGFrame.cpp \ + src/InteractionDialog.cpp \ src/userbutton.cpp \ src/x2gologdebug.cpp \ src/printprocess.cpp \ -- Alioth's /srv/git/code.x2go.org/x2goclient.git//..//_hooks_/post-receive-email on /srv/git/code.x2go.org/x2goclient.git