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 #include "httpbrokerclient.h"
19 #include <QNetworkAccessManager>
20 #include <QUrl>
21 #include <QNetworkRequest>
22 #include <QNetworkReply>
23 #include <QUuid>
24 #include <QTextStream>
25 #include <QFile>
26 #include <QDir>
27 #include <QSslSocket>
28 #include "x2gologdebug.h"
29 #include <QMessageBox>
30 #include <QDateTime>
31 #include "onmainwindow.h"
32 #include "x2gosettings.h"
33 #include <QDesktopWidget>
34 #include <QTimer>
35 #include "SVGFrame.h"
36 #include "onmainwindow.h"
37 #include <QTemporaryFile>
38 #include <QInputDialog>
39 #include "InteractionDialog.h"
40
41
HttpBrokerClient(ONMainWindow * wnd,ConfigFile * cfg)42 HttpBrokerClient::HttpBrokerClient ( ONMainWindow* wnd, ConfigFile* cfg )
43 {
44 config=cfg;
45 mainWindow=wnd;
46 sshConnection=0;
47 sessionsRequest=0l;
48 selSessRequest=0l;
49 chPassRequest=0l;
50 testConRequest=0l;
51 eventRequest=0l;
52 QUrl lurl ( config->brokerurl );
53 if(lurl.userName().length()>0)
54 config->brokerUser=lurl.userName();
55 nextAuthId=config->brokerUserId;
56
57 if(config->brokerurl.indexOf("ssh://")==0)
58 {
59 sshBroker=true;
60 x2goDebug<<"host:"<<lurl.host();
61 x2goDebug<<"port:"<<lurl.port(22);
62 x2goDebug<<"uname:"<<lurl.userName();
63 x2goDebug<<"path:"<<lurl.path();
64 config->sshBrokerBin=lurl.path();
65 }
66 else
67 {
68 sshBroker=false;
69
70 if ((config->brokerCaCertFile.length() >0) && (QFile::exists(config->brokerCaCertFile))) {
71 QSslSocket::addDefaultCaCertificates(config->brokerCaCertFile, QSsl::Pem);
72 x2goDebug<<"Custom CA certificate file loaded into HTTPS broker client: "<<config->brokerCaCertFile;
73 }
74
75 http=new QNetworkAccessManager ( this );
76 x2goDebug<<"Setting up connection to broker: "<<config->brokerurl;
77
78 connect ( http, SIGNAL ( sslErrors ( QNetworkReply*, const QList<QSslError>& ) ),this,
79 SLOT ( slotSslErrors ( QNetworkReply*, const QList<QSslError>& ) ) );
80
81 connect ( http,SIGNAL ( finished (QNetworkReply*) ),this,
82 SLOT ( slotRequestFinished (QNetworkReply*) ) );
83 }
84 }
85
86
~HttpBrokerClient()87 HttpBrokerClient::~HttpBrokerClient()
88 {
89 }
90
createSshConnection()91 void HttpBrokerClient::createSshConnection()
92 {
93 QUrl lurl ( config->brokerurl );
94 sshConnection=new SshMasterConnection (this, lurl.host(), lurl.port(22),mainWindow->getAcceptRSA(),
95 config->brokerUser, config->brokerPass,config->brokerSshKey,config->brokerAutologin,
96 config->brokerKrbLogin, false);
97
98 qRegisterMetaType<SshMasterConnection::passphrase_types> ("SshMasterConnection::passphrase_types");
99
100 connect ( sshConnection, SIGNAL ( connectionOk(QString)), this, SLOT ( slotSshConnectionOk() ) );
101 connect ( sshConnection, SIGNAL ( serverAuthError ( int,QString, SshMasterConnection* ) ),this,
102 SLOT ( slotSshServerAuthError ( int,QString, SshMasterConnection* ) ) );
103 connect ( sshConnection, SIGNAL ( needPassPhrase(SshMasterConnection*, SshMasterConnection::passphrase_types)),this,
104 SLOT ( slotSshServerAuthPassphrase(SshMasterConnection*, SshMasterConnection::passphrase_types)) );
105 connect ( sshConnection, SIGNAL ( userAuthError ( QString ) ),this,SLOT ( slotSshUserAuthError ( QString ) ) );
106 connect ( sshConnection, SIGNAL ( connectionError(QString,QString)), this,
107 SLOT ( slotSshConnectionError ( QString,QString ) ) );
108 connect ( sshConnection, SIGNAL(ioErr(SshProcess*,QString,QString)), this,
109 SLOT(slotSshIoErr(SshProcess*,QString,QString)));
110
111
112 connect ( sshConnection, SIGNAL(startInteraction(SshMasterConnection*,QString)),mainWindow,
113 SLOT(slotSshInteractionStart(SshMasterConnection*,QString)) );
114 connect ( sshConnection, SIGNAL(updateInteraction(SshMasterConnection*,QString)),mainWindow,
115 SLOT(slotSshInteractionUpdate(SshMasterConnection*,QString)) );
116 connect ( sshConnection, SIGNAL(finishInteraction(SshMasterConnection*)),mainWindow,
117 SLOT(slotSshInteractionFinish(SshMasterConnection*)));
118 connect ( mainWindow->getInteractionDialog(), SIGNAL(textEntered(QString)), sshConnection,
119 SLOT(interactionTextEnter(QString)));
120 connect ( mainWindow->getInteractionDialog(), SIGNAL(interrupt()), sshConnection, SLOT(interactionInterruptSlot()));
121
122 sshConnection->start();
123 }
124
slotSshConnectionError(QString message,QString lastSessionError)125 void HttpBrokerClient::slotSshConnectionError(QString message, QString lastSessionError)
126 {
127 if ( sshConnection )
128 {
129 sshConnection->wait();
130 delete sshConnection;
131 sshConnection=0l;
132 }
133
134 QMessageBox::critical ( 0l,message,lastSessionError,
135 QMessageBox::Ok,
136 QMessageBox::NoButton );
137 }
138
slotSshConnectionOk()139 void HttpBrokerClient::slotSshConnectionOk()
140 {
141 mainWindow->getInteractionDialog()->hide();
142 getUserSessions();
143 }
144
slotSshServerAuthError(int error,QString sshMessage,SshMasterConnection * connection)145 void HttpBrokerClient::slotSshServerAuthError(int error, QString sshMessage, SshMasterConnection* connection)
146 {
147 QString errMsg;
148 switch ( error )
149 {
150 case SSH_SERVER_KNOWN_CHANGED:
151 errMsg=tr ( "Host key for server changed.\nIt is now: " ) +sshMessage+"\n"+
152 tr ( "For security reasons, the connection attempt will be aborted." );
153 connection->writeKnownHosts(false);
154 connection->wait();
155 if(sshConnection && sshConnection !=connection)
156 {
157 sshConnection->wait();
158 delete sshConnection;
159 }
160 sshConnection=0;
161 slotSshUserAuthError ( errMsg );
162 return;
163
164 case SSH_SERVER_FOUND_OTHER:
165 errMsg=tr ( "The host key for this server was not found but another "
166 "type of key exists. An attacker might have changed the default server key to "
167 "trick your client into thinking the key does not exist yet." );
168 connection->writeKnownHosts(false);
169 connection->wait();
170 if(sshConnection && sshConnection !=connection)
171 {
172 sshConnection->wait();
173 delete sshConnection;
174 }
175 sshConnection=0;
176 slotSshUserAuthError ( errMsg );
177 return ;
178
179 case SSH_SERVER_ERROR:
180 connection->writeKnownHosts(false);
181 connection->wait();
182 if(sshConnection && sshConnection !=connection)
183 {
184 sshConnection->wait();
185 delete sshConnection;
186 }
187 sshConnection=0;
188 slotSshUserAuthError ( sshMessage );
189 return ;
190 case SSH_SERVER_FILE_NOT_FOUND:
191 errMsg=tr ( "Could not find known hosts file. "
192 "If you accept the host key here, the file will be automatically created." );
193 break;
194
195 case SSH_SERVER_NOT_KNOWN:
196 errMsg=tr ( "The server is unknown. Do you trust the host key?\nPublic key hash: " ) +sshMessage;
197 break;
198 }
199
200 if ( QMessageBox::warning ( 0, tr ( "Host key verification failed." ),errMsg,tr ( "Yes" ), tr ( "No" ) ) !=0 )
201 {
202 connection->writeKnownHosts(false);
203 connection->wait();
204 if(sshConnection && sshConnection !=connection)
205 {
206 sshConnection->wait();
207 delete sshConnection;
208 }
209 sshConnection=0;
210 slotSshUserAuthError ( tr ( "Host key verification failed." ) );
211 return;
212 }
213 connection->writeKnownHosts(true);
214 connection->wait();
215 connection->start();
216
217 }
218
slotSshServerAuthPassphrase(SshMasterConnection * connection,SshMasterConnection::passphrase_types passphrase_type)219 void HttpBrokerClient::slotSshServerAuthPassphrase(SshMasterConnection* connection, SshMasterConnection::passphrase_types passphrase_type)
220 {
221 bool ok;
222 QString message;
223
224 switch (passphrase_type) {
225 case SshMasterConnection::PASSPHRASE_PRIVKEY:
226 message = tr ("Enter passphrase to decrypt a key");
227 ok = true;
228 break;
229 case SshMasterConnection::PASSPHRASE_CHALLENGE:
230 message = tr ("Verification code:");
231 ok = true;
232 break;
233 case SshMasterConnection::PASSPHRASE_PASSWORD:
234 message = tr ("Enter user account password:");
235 ok = true;
236 break;
237 default:
238 x2goDebug << "Unknown passphrase type requested! Was: " << passphrase_type << endl;
239 ok = false;
240 break;
241 }
242
243 if (ok) {
244 QString phrase = QInputDialog::getText (0, connection->getUser () + "@" + connection->getHost () + ":" + QString::number (connection->getPort ()),
245 message, QLineEdit::Password, QString (""), &ok);
246 if (!ok) {
247 phrase = QString ("");
248 }
249 connection->setKeyPhrase (phrase);
250 }
251 }
252
closeSSHInteractionDialog()253 void HttpBrokerClient::closeSSHInteractionDialog()
254 {
255 slotSshUserAuthError("NO_ERROR");
256 }
257
258
slotSshUserAuthError(QString error)259 void HttpBrokerClient::slotSshUserAuthError(QString error)
260 {
261 if ( sshConnection )
262 {
263 sshConnection->wait();
264 delete sshConnection;
265 sshConnection=0l;
266 }
267 mainWindow->getInteractionDialog()->hide();
268
269 if(error!="NO_ERROR")
270
271 QMessageBox::critical ( 0l,tr ( "Authentication failed." ),error,
272 QMessageBox::Ok,
273 QMessageBox::NoButton );
274 emit authFailed();
275 return;
276 }
277
278
getUserSessions()279 void HttpBrokerClient::getUserSessions()
280 {
281 QString brokerUser=config->brokerUser;
282 // Otherwise, after logout from the session, we will be connected by a previous user without a password by authid.
283 if (config->brokerAutologoff) {
284 nextAuthId=config->brokerUserId;
285 }
286 x2goDebug<<"Called getUserSessions: brokeruser: "<<brokerUser<<" authid: "<<nextAuthId;
287 if(mainWindow->getUsePGPCard())
288 brokerUser=mainWindow->getCardLogin();
289 config->sessiondata=QString::null;
290 if(!sshBroker)
291 {
292 QString req;
293 QTextStream ( &req ) <<
294 "task=listsessions&"<<
295 "user="<<QUrl::toPercentEncoding(brokerUser)<<"&"<<
296 "password="<<QUrl::toPercentEncoding(config->brokerPass)<<"&"<<
297 "authid="<<nextAuthId;
298
299 x2goDebug << "sending request: "<< scramblePwd(req.toUtf8());
300 QNetworkRequest request(QUrl(config->brokerurl));
301 request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
302 sessionsRequest=http->post (request, req.toUtf8() );
303 }
304 else
305 {
306 if(!sshConnection)
307 {
308 createSshConnection();
309 return;
310 }
311 if (nextAuthId.length() > 0) {
312 sshConnection->executeCommand ( config->sshBrokerBin+" --user "+ brokerUser +" --authid "+nextAuthId+ " --task listsessions",
313 this, SLOT ( slotListSessions ( bool, QString,int ) ));
314 } else {
315 sshConnection->executeCommand ( config->sshBrokerBin+" --user "+ brokerUser +" --task listsessions",
316 this, SLOT ( slotListSessions ( bool, QString,int ) ));
317 }
318 }
319 }
320
selectUserSession(const QString & session,const QString & loginName)321 void HttpBrokerClient::selectUserSession(const QString& session, const QString& loginName)
322 {
323 x2goDebug<<"Called selectUserSession for session "<<session<<", "<<"loginName "<<loginName;
324 QString brokerUser=config->brokerUser;
325 if(mainWindow->getUsePGPCard())
326 brokerUser=mainWindow->getCardLogin();
327
328 if(!sshBroker)
329 {
330 QString req;
331 QTextStream ( &req ) <<
332 "task=selectsession&"<<
333 "sid="<<session<<"&"<<
334 "user="<<QUrl::toPercentEncoding(brokerUser)<<"&"<<
335 "password="<<QUrl::toPercentEncoding(config->brokerPass)<<"&"<<
336 "authid="<<nextAuthId;
337 if(loginName.length()>0)
338 {
339 QTextStream ( &req ) <<"&login="<<QUrl::toPercentEncoding(loginName);
340 }
341 x2goDebug << "sending request: "<< scramblePwd(req.toUtf8());
342 QNetworkRequest request(QUrl(config->brokerurl));
343 request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
344 selSessRequest=http->post (request, req.toUtf8() );
345
346 }
347 else
348 {
349 QString sshCmd=config->sshBrokerBin+" --user "+ brokerUser + " --task selectsession --sid \""+session+"\"";
350 if(nextAuthId.length() > 0)
351 {
352 sshCmd+=" --authid "+nextAuthId;
353 }
354 if(loginName.length() > 0)
355 {
356 sshCmd+=" --login " + loginName;
357 }
358 sshConnection->executeCommand (sshCmd, this,SLOT ( slotSelectSession(bool,QString,int)));
359 }
360
361 }
362
sendEvent(const QString & ev,const QString & id,const QString & server,const QString & client,const QString & login,const QString & cmd,const QString & display,const QString & start,uint connectionTime)363 void HttpBrokerClient::sendEvent(const QString& ev, const QString& id, const QString& server, const QString& client,
364 const QString& login, const QString& cmd,
365 const QString& display, const QString& start, uint connectionTime)
366 {
367 x2goDebug<<"Called sendEvent.";
368 QString brokerUser=config->brokerUser;
369 if(mainWindow->getUsePGPCard())
370 brokerUser=mainWindow->getCardLogin();
371
372 if(!sshBroker)
373 {
374 QString req;
375 QTextStream ( &req ) <<
376 "task=clientevent&"<<
377 "user="<<QUrl::toPercentEncoding(brokerUser)<<"&"<<
378 "password="<<QUrl::toPercentEncoding(config->brokerPass)<<"&"<<
379 "sid="<<id<<"&"<<
380 "event="<<ev<<"&"<<
381 "server="<<QUrl::toPercentEncoding(server)<<"&"<<
382 "client="<<QUrl::toPercentEncoding(client)<<"&"<<
383 "login="<<QUrl::toPercentEncoding(login)<<"&"<<
384 "cmd="<<QUrl::toPercentEncoding(cmd)<<"&"<<
385 "display="<<QUrl::toPercentEncoding(display)<<"&"<<
386 "start="<<QUrl::toPercentEncoding(start)<<"&"<<
387 "elapsed="<<QString::number(connectionTime)<<"&"<<
388 "authid="<<nextAuthId;
389 x2goDebug << "sending request: "<< scramblePwd(req.toUtf8());
390 QNetworkRequest request(QUrl(config->brokerurl));
391 request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
392 eventRequest=http->post (request, req.toUtf8() );
393
394 }
395 else
396 {
397 if (nextAuthId.length() > 0) {
398 sshConnection->executeCommand ( config->sshBrokerBin+" --user "+ brokerUser +" --authid "+nextAuthId+
399 " --task clientevent --sid \""+id+"\" --event "+ev+" --server \""+server+"\" --client \""+client+"\" --login "+"\""+
400 login+"\" --cmd \""+cmd+"\" --display \""+display+"\" --start \""+start+"\" --elapsed "+QString::number(connectionTime),
401 this,SLOT ( slotEventSent(bool,QString,int)));
402 } else {
403 sshConnection->executeCommand ( config->sshBrokerBin+" --user "+ brokerUser +
404 " --task clientevent --sid \""+id+"\" --event "+ev+" --server \""+server+"\" --client \""+client+"\" --login "+"\""+
405 login+"\" --cmd \""+cmd+"\" --display \""+display+"\" --start \""+start+"\" --elapsed "+QString::number(connectionTime),
406 this,SLOT ( slotEventSent(bool,QString,int)));
407 }
408 }
409 }
410
411
slotEventSent(bool success,QString answer,int)412 void HttpBrokerClient::slotEventSent(bool success, QString answer, int)
413 {
414 if(!success)
415 {
416 x2goDebug<<answer;
417 QMessageBox::critical(0,tr("Error"),answer);
418 emit fatalHttpError();
419 return;
420 }
421 if(!checkAccess(answer))
422 return;
423 x2goDebug<<"event sent:"<<answer;
424 if(answer.indexOf("SUSPEND")!=-1)
425 {
426 QString sid=answer.split("SUSPEND ")[1].simplified();
427 x2goDebug<<"broker asks to suspend "<<sid;
428 mainWindow->suspendFromBroker(sid);
429 }
430 if(answer.indexOf("TERMINATE")!=-1)
431 {
432 QString sid=answer.split("TERMINATE ")[1].simplified();
433 x2goDebug<<"broker asks to terminate "<<sid;
434 mainWindow->terminateFromBroker(sid);
435 }
436 }
437
438
changePassword(QString newPass)439 void HttpBrokerClient::changePassword(QString newPass)
440 {
441 newBrokerPass=newPass;
442 QString brokerUser=config->brokerUser;
443 if(mainWindow->getUsePGPCard())
444 brokerUser=mainWindow->getCardLogin();
445
446 if(!sshBroker)
447 {
448 QString req;
449 QTextStream ( &req ) <<
450 "task=setpass&"<<
451 "newpass="<<QUrl::toPercentEncoding(newPass)<<"&"<<
452 "user="<<QUrl::toPercentEncoding(brokerUser)<<"&"<<
453 "password="<<QUrl::toPercentEncoding(config->brokerPass)<<"&"<<
454 "authid="<<nextAuthId;
455 x2goDebug << "sending request: "<< scramblePwd(req.toUtf8());
456 QNetworkRequest request(QUrl(config->brokerurl));
457 request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
458 chPassRequest=http->post (request, req.toUtf8() );
459 }
460 else
461 {
462 if (nextAuthId.length() > 0) {
463 sshConnection->executeCommand ( config->sshBrokerBin+" --user "+ brokerUser +" --authid "+nextAuthId+ " --task setpass --newpass "+newPass, this,
464 SLOT ( slotPassChanged(bool,QString,int)));
465 } else {
466 sshConnection->executeCommand ( config->sshBrokerBin+" --user "+ brokerUser +" --task setpass --newpass "+newPass, this,
467 SLOT ( slotPassChanged(bool,QString,int)));
468 }
469 }
470 }
471
testConnection()472 void HttpBrokerClient::testConnection()
473 {
474 x2goDebug<<"Called testConnection.";
475 if(!sshBroker)
476 {
477 QString req;
478 QTextStream ( &req ) <<
479 "task=testcon";
480 x2goDebug << "sending request: "<< scramblePwd(req.toUtf8());
481 QNetworkRequest request(QUrl(config->brokerurl));
482 request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
483 testConRequest=http->post (request, req.toUtf8() );
484 }
485 else
486 {
487 if (nextAuthId.length() > 0) {
488 sshConnection->executeCommand(config->sshBrokerBin+" --authid "+nextAuthId+ " --task testcon",
489 this, SLOT ( slotSelectSession(bool,QString,int)));
490 } else {
491 sshConnection->executeCommand(config->sshBrokerBin+" --task testcon",
492 this, SLOT ( slotSelectSession(bool,QString,int)));
493 }
494 }
495 }
496
processClientConfig(const QString & raw_content)497 void HttpBrokerClient::processClientConfig(const QString& raw_content)
498 {
499 X2goSettings st(raw_content, QSettings::IniFormat);
500 mainWindow->config.brokerEvents=st.setting()->value("events",false).toBool();
501 mainWindow->config.brokerLiveEventsTimeout=st.setting()->value("liveevent",false).toUInt();
502 if(mainWindow->config.brokerEvents)
503 {
504 x2goDebug<<"sending client events to broker";
505 if(mainWindow->config.brokerLiveEventsTimeout)
506 {
507 x2goDebug<<"sending alive events to broker every "<<mainWindow->config.brokerLiveEventsTimeout<<" seconds";
508 }
509 }
510 }
511
512
createIniFile(const QString & raw_content)513 void HttpBrokerClient::createIniFile(const QString& raw_content)
514 {
515 QString content;
516 content = raw_content;
517 content.replace("<br>","\n");
518 x2goDebug<<"Inifile content: "<<content<<endl;
519 QString cont;
520 QStringList lines=content.split("START_USER_SESSIONS\n");
521 if (lines.count()>1)
522 {
523 cont=lines[1];
524 cont=cont.split("END_USER_SESSIONS\n")[0];
525 }
526 mainWindow->config.iniFile=cont;
527 lines=content.split("START_CLIENT_CONFIG\n");
528 if (lines.count()>1)
529 {
530 cont=lines[1];
531 cont=cont.split("END_CLIENT_CONFIG\n")[0];
532 processClientConfig(cont);
533 }
534 else
535 {
536 x2goDebug<<"no client config from broker";
537 }
538 }
539
540
checkAccess(QString answer)541 bool HttpBrokerClient::checkAccess(QString answer )
542 {
543 x2goDebug<<"Called checkAccess - answer was: "<<answer;
544 if (answer.indexOf("Access granted")==-1)
545 {
546 QMessageBox::critical (
547 0,tr ( "Error" ),
548 tr ( "Login failed!<br>"
549 "Please try again." ) );
550 emit authFailed();
551 return false;
552 }
553 config->brokerAuthenticated=true;
554 emit (enableBrokerLogoutButton ());
555 int authBegin=answer.indexOf("AUTHID:");
556 if (authBegin!=-1)
557 {
558 nextAuthId=answer.mid(authBegin+7, answer.indexOf("\n",authBegin)-authBegin-7);
559 }
560 return true;
561 }
562
563
slotConnectionTest(bool success,QString answer,int)564 void HttpBrokerClient::slotConnectionTest(bool success, QString answer, int)
565 {
566 x2goDebug<<"Called slotConnectionTest.";
567 if(!success)
568 {
569 x2goDebug<<answer;
570 QMessageBox::critical(0,tr("Error"),answer);
571 emit fatalHttpError();
572 return;
573 }
574 if(!checkAccess(answer))
575 return;
576 if(!sshBroker)
577 {
578 x2goDebug<<"Elapsed: "<<requestTime.elapsed()<<"; received:"<<answer.size()<<endl;
579 emit connectionTime(requestTime.elapsed(),answer.size());
580 }
581 return;
582
583 }
584
slotListSessions(bool success,QString answer,int)585 void HttpBrokerClient::slotListSessions(bool success, QString answer, int)
586 {
587 if(!success)
588 {
589 x2goDebug<<answer;
590 QMessageBox::critical(0,tr("Error"),answer);
591 emit fatalHttpError();
592 return;
593 }
594 if(!checkAccess(answer))
595 return;
596 createIniFile(answer);
597 emit sessionsLoaded();
598 }
599
slotPassChanged(bool success,QString answer,int)600 void HttpBrokerClient::slotPassChanged(bool success, QString answer, int)
601 {
602 if(!success)
603 {
604 x2goDebug<<answer;
605 QMessageBox::critical(0,tr("Error"),answer);
606 emit fatalHttpError();
607 return;
608 }
609 if(!checkAccess(answer))
610 return;
611
612 }
613
slotSelectSession(bool success,QString answer,int)614 void HttpBrokerClient::slotSelectSession(bool success, QString answer, int)
615 {
616 if(!success)
617 {
618 x2goDebug<<answer;
619 QMessageBox::critical(0,tr("Error"),answer);
620 emit fatalHttpError();
621 return;
622 }
623 if(!checkAccess(answer))
624 return;
625 x2goDebug<<"parsing "<<answer;
626 parseSession(answer);
627 }
628
629
slotRequestFinished(QNetworkReply * reply)630 void HttpBrokerClient::slotRequestFinished ( QNetworkReply* reply )
631 {
632 if(reply->error() != QNetworkReply::NoError)
633 {
634 x2goDebug<<"Broker HTTP request failed with error: "<<reply->errorString();
635 if(reply == eventRequest)
636 {
637 reply->deleteLater();
638 eventRequest=0l;
639 //do not exit, just return the function
640 return;
641 }
642 QMessageBox::critical(0,tr("Error"),reply->errorString());
643 emit fatalHttpError();
644 return;
645 }
646
647 QString answer ( reply->readAll() );
648 x2goDebug<<"A http request returned. Result was: "<<answer;
649 if (reply == testConRequest)
650 {
651 testConRequest=0l;
652 slotConnectionTest(true,answer,0);
653 }
654 else if (reply == sessionsRequest)
655 {
656 sessionsRequest=0l;
657 slotListSessions(true, answer,0);
658 }
659 else if (reply == selSessRequest)
660 {
661 selSessRequest=0l;
662 slotSelectSession(true,answer,0);
663 }
664 else if (reply == chPassRequest)
665 {
666 chPassRequest=0l;
667 slotPassChanged(true,answer,0);
668 }
669 else if (reply == eventRequest)
670 {
671 eventRequest=0l;
672 slotEventSent(true,answer,0);
673 }
674
675 // We receive ownership of the reply object
676 // and therefore need to handle deletion.
677 reply->deleteLater();
678 }
679
parseSession(QString sinfo)680 void HttpBrokerClient::parseSession(QString sinfo)
681 {
682 config->sessiondata="";
683 suspendedSession.clear();
684 x2goDebug<<"Starting parser.";
685 QStringList lst=sinfo.split("SERVER:",QString::SkipEmptyParts);
686 int keyStartPos=sinfo.indexOf("-----BEGIN DSA PRIVATE KEY-----");
687 if(keyStartPos==-1)
688 keyStartPos=sinfo.indexOf("-----BEGIN RSA PRIVATE KEY-----");
689 QString endStr="-----END DSA PRIVATE KEY-----";
690 int keyEndPos=sinfo.indexOf(endStr);
691 if(keyEndPos==-1)
692 {
693 endStr="-----END RSA PRIVATE KEY-----";
694 keyEndPos=sinfo.indexOf(endStr);
695 }
696 if (! (keyEndPos == -1 || keyStartPos == -1 || lst.size()==0))
697 config->key=sinfo.mid(keyStartPos, keyEndPos+endStr.length()-keyStartPos);
698 QString serverLine=(lst[1].split("\n"))[0];
699 QStringList words=serverLine.split(":",QString::SkipEmptyParts);
700 config->serverIp=words[0];
701 if (words.count()>1)
702 config->sshport=words[1];
703 x2goDebug<<"Server IP address: "<<config->serverIp;
704 x2goDebug<<"Server port: "<<config->sshport;
705 if (sinfo.indexOf("SESSION_INFO")!=-1)
706 {
707 QStringList lst=sinfo.split("SESSION_INFO:",QString::SkipEmptyParts);
708 //config->sessiondata=lst[1];
709 x2goDebug<<"Session data: "<<lst[1]<<"\n";
710 suspendedSession=lst[1].trimmed().split ( '\n', QString::SkipEmptyParts );
711 mainWindow->selectSession(suspendedSession);
712 }
713 else
714 {
715 emit sessionSelected();
716 }
717 x2goDebug<<"Parsing has finished.";
718 }
719
resumeSession(const QString & id,const QString & server)720 void HttpBrokerClient::resumeSession(const QString& id, const QString& server)
721 {
722 x2goDebug<<"Resuming session with id:"<<id<<"on:"<<server;
723 foreach (QString sline, suspendedSession)
724 {
725 if(sline.indexOf(id)!=-1)
726 {
727 config->sessiondata=sline;
728 config->serverIp=server;
729 emit sessionSelected();
730 break;
731 }
732 }
733 }
734
735
slotSslErrors(QNetworkReply * netReply,const QList<QSslError> & errors)736 void HttpBrokerClient::slotSslErrors ( QNetworkReply* netReply, const QList<QSslError> & errors )
737 {
738 QStringList err;
739 QSslCertificate cert;
740 for ( int i=0; i<errors.count(); ++i )
741 {
742 x2goDebug<<"sslError, code:"<<errors[i].error() <<":";
743 err<<errors[i].errorString();
744 if ( !errors[i].certificate().isNull() )
745 cert=errors[i].certificate();
746 }
747
748
749 QString md5=getHexVal ( cert.digest() );
750 QString fname=md5;
751 fname=fname.replace(":","_");
752 QUrl lurl ( config->brokerurl );
753 QString homeDir=mainWindow->getHomeDirectory();
754 if ( QFile::exists ( homeDir+"/.x2go/ssl/exceptions/"+
755 lurl.host() +"/"+fname ) )
756 {
757 QFile fl ( homeDir+"/.x2go/ssl/exceptions/"+
758 lurl.host() +"/"+fname );
759 fl.open ( QIODevice::ReadOnly | QIODevice::Text );
760 QSslCertificate mcert ( &fl );
761 if ( mcert==cert )
762 {
763 netReply->ignoreSslErrors();
764 requestTime.restart();
765 return;
766 }
767 }
768
769 QString text=tr ( "<br><b>Server uses an invalid "
770 "security certificate.</b><br><br>" );
771 text+=err.join ( "<br>" );
772 text+=tr ( "<p style='background:#FFFFDC;'>"
773 "You should not add an exception "
774 "if you are using an internet connection "
775 "that you do not trust completely or if you are "
776 "not used to seeing a warning for this server.</p>" );
777 QMessageBox mb ( QMessageBox::Warning,tr ( "Secure connection failed." ),
778 text );
779 text=QString::null;
780 QTextStream ( &text ) <<err.join ( "\n" ) <<"\n"<<
781 "------------\n"<<
782 tr ( "Issued to:\n" ) <<
783 tr ( "Common Name(CN)\t" ) <<
784 #if QT_VERSION >= 0x050000
785 cert.issuerInfo ( QSslCertificate::CommonName ).join("; ")
786 #else
787 cert.issuerInfo ( QSslCertificate::CommonName )
788 #endif
789 <<endl<<
790 tr ( "Organization(O)\t" ) <<
791 #if QT_VERSION >= 0x050000
792 cert.issuerInfo ( QSslCertificate::Organization ).join("; ")
793 #else
794 cert.issuerInfo ( QSslCertificate::Organization )
795 #endif
796 <<endl<<
797 tr ( "Organizational Unit(OU)\t" ) <<
798 #if QT_VERSION >= 0x050000
799 cert.issuerInfo ( QSslCertificate::OrganizationalUnitName ).join("; ")
800 #else
801 cert.issuerInfo ( QSslCertificate::OrganizationalUnitName )
802 #endif
803 <<endl<<
804 tr ( "Serial Number\t" ) <<getHexVal ( cert.serialNumber() )
805 <<endl<<endl<<
806 tr ( "Issued by:\n" ) <<
807 tr ( "Common Name(CN)\t" ) <<
808 #if QT_VERSION >= 0x050000
809 cert.subjectInfo ( QSslCertificate::CommonName ).join("; ")
810 #else
811 cert.subjectInfo ( QSslCertificate::CommonName )
812 #endif
813 <<endl<<
814 tr ( "Organization(O)\t" ) <<
815 #if QT_VERSION >= 0x050000
816 cert.subjectInfo ( QSslCertificate::Organization ).join("; ")
817 #else
818 cert.subjectInfo ( QSslCertificate::Organization )
819 #endif
820 <<endl<<
821 tr ( "Organizational Unit(OU)\t" ) <<
822 #if QT_VERSION >= 0x050000
823 cert.subjectInfo ( QSslCertificate::OrganizationalUnitName ).join("; ")
824 #else
825 cert.subjectInfo ( QSslCertificate::OrganizationalUnitName )
826 #endif
827 <<endl<<endl<<
828
829 tr ( "Validity:\n" ) <<
830 tr ( "Issued on\t" ) <<cert.effectiveDate().toString() <<endl<<
831 tr ( "expires on\t" ) <<cert.expiryDate().toString() <<endl<<endl<<
832 tr ( "Fingerprints:\n" ) <<
833 tr ( "SHA1\t" ) <<
834 getHexVal ( cert.digest ( QCryptographicHash::Sha1 ) ) <<endl<<
835 tr ( "MD5\t" ) <<md5;
836
837
838
839 mb.setDetailedText ( text );
840 mb.setEscapeButton (
841 ( QAbstractButton* ) mb.addButton ( tr ( "Exit X2Go Client" ),
842 QMessageBox::RejectRole ) );
843 QPushButton *okButton=mb.addButton ( tr ( "Add exception" ),
844 QMessageBox::AcceptRole );
845 mb.setDefaultButton ( okButton );
846
847 mb.exec();
848 if ( mb.clickedButton() == ( QAbstractButton* ) okButton )
849 {
850 x2goDebug<<"User accepted certificate.";
851 QDir dr;
852 dr.mkpath ( homeDir+"/.x2go/ssl/exceptions/"+lurl.host() +"/" );
853 QFile fl ( homeDir+"/.x2go/ssl/exceptions/"+
854 lurl.host() +"/"+fname );
855 fl.open ( QIODevice::WriteOnly | QIODevice::Text );
856 QTextStream ( &fl ) <<cert.toPem();
857 fl.close();
858 netReply->ignoreSslErrors();
859 x2goDebug<<"Storing certificate in "<<homeDir+"/.x2go/ssl/exceptions/"+
860 lurl.host() +"/"+fname;
861 requestTime.restart();
862 }
863 else
864 emit fatalHttpError();
865 }
866
867
getHexVal(const QByteArray & ba)868 QString HttpBrokerClient::getHexVal ( const QByteArray& ba )
869 {
870 QStringList val;
871 for ( int i=0; i<ba.size(); ++i )
872 {
873 QString bt;
874 bt.sprintf ( "%02X", ( unsigned char ) ba[i] );
875 val<<bt;
876 }
877 return val.join ( ":" );
878 }
879
slotSshIoErr(SshProcess * caller,QString error,QString lastSessionError)880 void HttpBrokerClient::slotSshIoErr(SshProcess* caller, QString error, QString lastSessionError)
881 {
882 x2goDebug<<"Brocker SSH Connection IO Error, reconnect session\n";
883 if ( sshConnection )
884 {
885 delete sshConnection;
886 sshConnection=0l;
887 }
888 createSshConnection();
889 }
890
scramblePwd(const QString & req)891 QString HttpBrokerClient::scramblePwd(const QString& req)
892 {
893 QString scrambled=req;
894 int startPos=scrambled.indexOf("password=");
895 if(startPos!=-1)
896 {
897 startPos+=9;
898 int endPos=scrambled.indexOf("&",startPos);
899 int plength;
900 if(endPos==-1)
901 {
902 plength=scrambled.length()-startPos;
903 }
904 else
905 {
906 plength=endPos-startPos;
907 }
908 scrambled.remove(startPos, plength);
909 // Hardcode a value of 8 here - the length of the string "password".
910 scrambled.insert(startPos, QString ('*').repeated (8));
911 }
912 return scrambled;
913 }
914