[X2Go-Commits] [x2goclient] 01/01: Interaction with SSH server (for example for changing expired password). Fixes: #592.
git-admin at x2go.org
git-admin at x2go.org
Wed May 10 15:23:10 CEST 2017
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 at 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 at 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 at 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
More information about the x2go-commits
mailing list