1 /**************************************************************************
2 *   Copyright (C) 2005-2020 by Oleksandr Shneyder                         *
3 *                              <o.shneyder@phoca-gmbh.de>                 *
4 *                                                                         *
5 *   This program is free software; you can redistribute it and/or modify  *
6 *   it under the terms of the GNU General Public License as published by  *
7 *   the Free Software Foundation; either version 2 of the License, or     *
8 *   (at your option) any later version.                                   *
9 *   This program is distributed in the hope that it will be useful,       *
10 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
11 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
12 *   GNU General Public License for more details.                          *
13 *                                                                         *
14 *   You should have received a copy of the GNU General Public License     *
15 *   along with this program.  If not, see <https://www.gnu.org/licenses/>. *
16 ***************************************************************************/
17 
18 #ifndef SSHMASTERCONNECTION_H
19 #define SSHMASTERCONNECTION_H
20 
21 #include <libssh/libssh.h>
22 #include <QString>
23 #include <QList>
24 #include <QMutex>
25 #include <QThread>
26 #include <QStringList>
27 #include <QTcpSocket>
28 #include <QNetworkProxy>
29 
30 
31 #define PROPERTY(TYPE,NAME)  private: TYPE NAME; \
32 public: TYPE get_##NAME(){return NAME;} \
33 void set_##NAME(TYPE VAL){NAME=VAL;}
34 
35 
36 class ONMainWindow;
37 class SshProcess;
38 struct ChannelConnection
39 {
40     ssh_channel channel;
41     int sock;
42     SshProcess* creator;
43     int forwardPort;
44     int localPort;
45     QString forwardHost;
46     QString localHost;
47     QString command;
48     QString uuid;
49     bool operator==(ChannelConnection& t)
50     {
51         return (channel==t.channel);
52     }
53 };
54 
55 struct ReverseTunnelRequest
56 {
57     uint localPort;
58     uint forwardPort;
59     QString localHost;
60     SshProcess* creator;
61     bool listen;
62 };
63 
64 struct CopyRequest
65 {
66     SshProcess* creator;
67     QString src;
68     QString dst;
69 };
70 
71 class SshMasterConnection: public QThread
72 {
73     Q_OBJECT
74     PROPERTY(bool, kerberosDelegation)
75 public:
76     enum ProxyType {PROXYSSH, PROXYHTTP};
77 
78     enum passphrase_types {
79         PASSPHRASE_PRIVKEY,
80         PASSPHRASE_CHALLENGE,
81         PASSPHRASE_PASSWORD,
82         PASSPHRASE_UNKNOWN
83     };
84 
85     void run();
86     SshMasterConnection(QObject* parent, QString host, int port, bool acceptUnknownServers, QString user,
87                         QString pass, QString key, bool autologin, bool krblogin=false,
88                         bool useproxy=false, ProxyType type=PROXYSSH, QString proxyserver=QString::null, quint16 proxyport=0,
89                         QString proxylogin=QString::null, QString proxypassword=QString::null, QString proxyKey=QString::null,
90                         bool proxyAutologin=false, bool proxyKrbLogin=false);
91     ~SshMasterConnection();
92     void addChannelConnection(SshProcess* creator, int sock, QString forwardHost,
93                               int forwardPort, QString localHost, int localPort, void* channel=0l);
94     void addChannelConnection(SshProcess* creator, QString uuid, QString cmd);
95     void addCopyRequest(SshProcess* creator, QString src, QString dst);
96     void writeKnownHosts(bool);
97     void setKeyPhrase(QString);
98 
99     int executeCommand(const QString& command, QObject* receiver=0, const char* slotFinished=0, bool overridePath=true);
100     int startTunnel(const QString& forwardHost, uint forwardPort, const QString& localHost,
101                     uint localPort, bool reverse=false, QObject* receiver=0, const char* slotTunnelOk=0, const char* slotFinished=0);
102     int copyFile(const QString& src, const QString dst, QObject* receiver=0, const char* slotFinished=0);
103     QString getSourceFile(int pid);
104 
setAcceptUnknownServers(bool accept)105     void setAcceptUnknownServers(bool accept)
106     {
107         acceptUnknownServers=accept;
108     }
getHost()109     QString getHost()
110     {
111         return host;
112     }
getUser()113     QString getUser()
114     {
115         return user;
116     }
getPort()117     int getPort()
118     {
119         return port;
120     }
useKerberos()121     bool useKerberos()
122     {
123         return kerberos;
124     };
125 
126 private:
127     bool sshConnect();
128     bool userAuthWithPass();
129     bool userAuthAuto();
130     bool userAuthWithKey();
131     bool userChallengeAuth();
132     bool checkLogin();
133     bool userAuth();
134     bool userAuthKrb();
135     bool userAuthKeyboardInteractive(QString prompt);
136     void channelLoop();
137     void finalize(int arg1);
138     void copy();
139     int serverAuth(QString& errorMsg);
140     void setVerficationCode(QString code);
141     void checkReverseTunnelConnections();
142     void addReverseTunnelConnections();
143 #ifdef Q_OS_WIN
144     void parseKnownHosts();
145 #endif
146 
147 private slots:
148 
149     void slotSshProxyServerAuthError ( int,QString, SshMasterConnection* );
150     void slotSshProxyServerAuthAborted ();
151     void slotSshProxyUserAuthError ( QString );
152     void slotSshProxyConnectionError ( QString,QString );
153 
154 
155     void slotSshProxyConnectionOk();
156     void slotSshProxyTunnelOk(int);
157     void slotSshProxyTunnelFailed(bool result,  QString output,
158                                   int);
159     void slotSshProxyInteractionStart ( SshMasterConnection* connection, QString prompt );
160     void slotSshProxyInteractionUpdate ( SshMasterConnection* connection, QString output );
161     void slotSshProxyInteractionFinish ( SshMasterConnection* connection);
162 
163 public slots:
164     void interactionTextEnter(QString text);
165     void interactionInterruptSlot();
166 
167 private:
168     ssh_session my_ssh_session;
169     QList<ChannelConnection> channelConnections;
170     QList<CopyRequest> copyRequests;
171     QList<ReverseTunnelRequest> reverseTunnelRequest;
172     QMutex channelConnectionsMutex;
173     QMutex copyRequestMutex;
174     QMutex disconnectFlagMutex;
175     QMutex writeHostKeyMutex;
176     QMutex reverseTunnelRequestMutex;
177     QMutex interactionInputMutex;
178     QString interactionInputText;
179     bool interactionInterrupt;
180     bool writeHostKey;
181     bool writeHostKeyReady;
182     int nextPid;
183     QList<SshProcess*> processes;
184 
185     QString keyPhrase;
186     bool keyPhraseReady;
187     QMutex keyPhraseMutex;
188 
189     QString host;
190     int port;
191     QString user;
192     QString pass;
193     QString key;
194     bool useproxy;
195     QString proxyserver;
196     quint16 proxyport;
197     QString proxylogin;
198     QString proxypassword;
199     ProxyType proxytype;
200     bool proxyautologin;
201     bool proxyKrbLogin;
202     QString proxykey;
203     QStringList authErrors;
204     bool autologin;
205     bool disconnectSessionFlag;
206     int localProxyPort;
207     bool acceptUnknownServers;
208     ONMainWindow* mainWnd;
209     bool kerberos;
210     QString sshProcErrString;
211     QTcpSocket *tcpProxySocket;
212     QNetworkProxy *tcpNetworkProxy;
213     SshMasterConnection* sshProxy;
214     bool sshProxyReady;
215     bool breakLoop;
216     bool loginCheck;
217 
218     bool challengeAuthPasswordAccepted;
219     QString challengeAuthVerificationCode;
220 
221     static const QString challenge_auth_code_prompts_[];
222 
223 signals:
224     void stdErr(SshProcess* caller, QByteArray data);
225     void stdOut(SshProcess* caller, QByteArray data);
226     void ioErr(SshProcess* caller, QString error, QString lastSessionError);
227     void copyErr(SshProcess* caller, QString error, QString lastSessionError);
228     void copyOk(SshProcess* caller);
229     void channelClosed(SshProcess* caller, QString uuid);
230     void reverseTunnelOk(SshProcess* caller);
231     void reverseTunnelFailed(SshProcess* caller, QString error);
232 
233     void connectionError(QString message, QString lastSessionError);
234     void serverAuthError(int errCode, QString lastSessionError, SshMasterConnection*);
235     void serverAuthAborted();
236     void userAuthError(QString error);
237 
238     void connectionOk( QString host);
239 
240     void needPassPhrase(SshMasterConnection*, SshMasterConnection::passphrase_types);
241     void needChallengeResponse(SshMasterConnection*, QString Challenge);
242     void startInteraction(SshMasterConnection*, QString prompt);
243     void finishInteraction(SshMasterConnection*);
244     void updateInteraction(SshMasterConnection*, QString output);
245 };
246 
247 Q_DECLARE_METATYPE (SshMasterConnection::passphrase_types)
248 
249 #endif // SSHMASTERCONNECTION_H
250 
251