00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
#ifdef HAVE_CONFIG_H
00027
#include <config.h>
00028
#endif
00029
00030
#include <sys/types.h>
00031
#include <sys/uio.h>
00032
#include <sys/time.h>
00033
#include <sys/socket.h>
00034
00035
#include <netinet/in.h>
00036
00037
#include <time.h>
00038
#include <netdb.h>
00039
#include <unistd.h>
00040
#include <errno.h>
00041
00042
#include <ksocks.h>
00043
#include <kdebug.h>
00044
#include <ksslall.h>
00045
#include <ksslcertdlg.h>
00046
#include <kmessagebox.h>
00047
00048
#include <klocale.h>
00049
#include <dcopclient.h>
00050
#include <qcstring.h>
00051
#include <qdatastream.h>
00052
00053
#include <kapplication.h>
00054
00055
#include <kprotocolmanager.h>
00056
#include <kde_file.h>
00057
00058
#include "kio/tcpslavebase.h"
00059
00060
using namespace KIO;
00061
00062
class TCPSlaveBase::TcpSlaveBasePrivate
00063 {
00064
public:
00065
00066 TcpSlaveBasePrivate() : rblockSz(256), militantSSL(false), userAborted(false) {}
00067 ~TcpSlaveBasePrivate() {}
00068
00069
KSSL *kssl;
00070
bool usingTLS;
00071 KSSLCertificateCache *cc;
00072
QString host;
00073
QString realHost;
00074
QString ip;
00075
DCOPClient *dcc;
00076
KSSLPKCS12 *pkcs;
00077
00078
int status;
00079
int timeout;
00080
int rblockSz;
00081
bool block;
00082
bool useSSLTunneling;
00083
bool needSSLHandShake;
00084
bool militantSSL;
00085
00086
bool userAborted;
00087
MetaData savedMetaData;
00088 };
00089
00090
00091 TCPSlaveBase::TCPSlaveBase(
unsigned short int defaultPort,
00092
const QCString &protocol,
00093
const QCString &poolSocket,
00094
const QCString &appSocket)
00095 :
SlaveBase (protocol, poolSocket, appSocket),
00096 m_iSock(-1),
00097 m_iDefaultPort(defaultPort),
00098 m_sServiceName(protocol),
00099 fp(0)
00100 {
00101
00102
00103 doConstructorStuff();
00104 m_bIsSSL =
false;
00105 }
00106
00107 TCPSlaveBase::TCPSlaveBase(
unsigned short int defaultPort,
00108
const QCString &protocol,
00109
const QCString &poolSocket,
00110
const QCString &appSocket,
00111
bool useSSL)
00112 :
SlaveBase (protocol, poolSocket, appSocket),
00113 m_iSock(-1),
00114 m_bIsSSL(useSSL),
00115 m_iDefaultPort(defaultPort),
00116 m_sServiceName(protocol),
00117 fp(0)
00118 {
00119 doConstructorStuff();
00120
if (useSSL)
00121 m_bIsSSL = initializeSSL();
00122 }
00123
00124
00125
void TCPSlaveBase::doConstructorStuff()
00126 {
00127 d =
new TcpSlaveBasePrivate;
00128 d->kssl = 0L;
00129 d->ip =
"";
00130 d->cc = 0L;
00131 d->usingTLS =
false;
00132 d->dcc = 0L;
00133 d->pkcs = 0L;
00134 d->status = -1;
00135 d->timeout =
KProtocolManager::connectTimeout();
00136 d->block =
false;
00137 d->useSSLTunneling =
false;
00138 }
00139
00140 TCPSlaveBase::~TCPSlaveBase()
00141 {
00142 cleanSSL();
00143
if (d->usingTLS)
delete d->kssl;
00144
if (d->dcc)
delete d->dcc;
00145
if (d->pkcs)
delete d->pkcs;
00146
delete d;
00147 }
00148
00149 ssize_t TCPSlaveBase::write(
const void *data, ssize_t len)
00150 {
00151
#ifdef Q_OS_UNIX
00152
if ( (m_bIsSSL || d->usingTLS) && !d->useSSLTunneling )
00153 {
00154
if ( d->needSSLHandShake )
00155 (
void) doSSLHandShake(
true );
00156
return d->kssl->write(data, len);
00157 }
00158
return KSocks::self()->write(m_iSock, data, len);
00159
#else
00160
return 0;
00161
#endif
00162
}
00163
00164 ssize_t TCPSlaveBase::read(
void *data, ssize_t len)
00165 {
00166
#ifdef Q_OS_UNIX
00167
if ( (m_bIsSSL || d->usingTLS) && !d->useSSLTunneling )
00168 {
00169
if ( d->needSSLHandShake )
00170 (
void) doSSLHandShake(
true );
00171
return d->kssl->read(data, len);
00172 }
00173
return KSocks::self()->read(m_iSock, data, len);
00174
#else
00175
return 0;
00176
#endif
00177
}
00178
00179
00180
void TCPSlaveBase::setBlockSize(
int sz)
00181 {
00182
if (sz <= 0)
00183 sz = 1;
00184
00185 d->rblockSz = sz;
00186 }
00187
00188
00189 ssize_t TCPSlaveBase::readLine(
char *data, ssize_t len)
00190 {
00191
00192
00193
00194
00195
00196
00197
if (!data)
00198
return -1;
00199
00200
char tmpbuf[1024];
00201 *data = 0;
00202 ssize_t clen = 0;
00203
char *buf = data;
00204
int rc = 0;
00205
00206
if ((m_bIsSSL || d->usingTLS) && !d->useSSLTunneling) {
00207
if ( d->needSSLHandShake )
00208 (
void) doSSLHandShake(
true );
00209
00210
while (clen < len-1) {
00211 rc = d->kssl->pending();
00212
if (rc > 0) {
00213
int bytes = rc;
00214
if (bytes > d->rblockSz)
00215 bytes = d->rblockSz;
00216
00217 rc = d->kssl->peek(tmpbuf, bytes);
00218
if (rc <= 0) {
00219
00220
return -1;
00221 }
00222
00223 bytes = rc;
00224
for (
int i = 0; i < rc; i++) {
00225
if (tmpbuf[i] ==
'\n') {
00226 bytes = i+1;
00227
break;
00228 }
00229 }
00230
00231
if (bytes+clen >= len)
00232 bytes = len - clen - 1;
00233
00234 rc = d->kssl->read(buf, bytes);
00235
if (rc > 0) {
00236 clen += rc;
00237 buf += (rc-1);
00238
if (*buf++ ==
'\n')
00239
break;
00240 }
else {
00241
00242
return -1;
00243 }
00244 }
else {
00245 rc = d->kssl->read(buf, 1);
00246
if (rc <= 0) {
00247
return -1;
00248
00249
00250
00251 }
else {
00252 clen++;
00253
if (*buf++ ==
'\n')
00254
break;
00255 }
00256 }
00257 }
00258 }
else {
00259
while (clen < len-1) {
00260
#ifdef Q_OS_UNIX
00261
rc = KSocks::self()->read(m_iSock, buf, 1);
00262
#else
00263
rc = 0;
00264
#endif
00265
if (rc <= 0) {
00266
00267
return -1;
00268 }
else {
00269 clen++;
00270
if (*buf++ ==
'\n')
00271
break;
00272 }
00273 }
00274 }
00275
00276
00277 *buf = 0;
00278
return clen;
00279 }
00280
00281
unsigned short int TCPSlaveBase::port(
unsigned short int _p)
00282 {
00283
unsigned short int p = _p;
00284
00285
if (_p <= 0)
00286 {
00287 p = m_iDefaultPort;
00288 }
00289
00290
return p;
00291 }
00292
00293
00294
00295
00296
00297
00298
00299
bool TCPSlaveBase::connectToHost(
const QString &host,
00300
unsigned int _port,
00301
bool sendError )
00302 {
00303
#ifdef Q_OS_UNIX
00304
unsigned short int p;
00305 KExtendedSocket ks;
00306
00307 d->userAborted =
false;
00308
00309
00310
if (metaData(
"main_frame_request") ==
"TRUE" &&
00311 metaData(
"ssl_activate_warnings") ==
"TRUE" &&
00312 metaData(
"ssl_was_in_use") ==
"TRUE" &&
00313 !m_bIsSSL) {
00314
KSSLSettings kss;
00315
if (kss.
warnOnLeave()) {
00316
int result = messageBox( i18n(
"You are about to leave secure "
00317
"mode. Transmissions will no "
00318
"longer be encrypted.\nThis "
00319
"means that a third party could "
00320
"observe your data in transit."),
00321 WarningContinueCancel,
00322 i18n(
"Security Information"),
00323 i18n(
"C&ontinue Loading"), QString::null,
00324
"WarnOnLeaveSSLMode" );
00325
00326
00327
KConfig *config =
new KConfig(
"kioslaverc");
00328 config->
setGroup(
"Notification Messages");
00329
00330
if (!config->
readBoolEntry(
"WarnOnLeaveSSLMode",
true)) {
00331 config->
deleteEntry(
"WarnOnLeaveSSLMode");
00332 config->
sync();
00333 kss.
setWarnOnLeave(
false);
00334 kss.
save();
00335 }
00336
delete config;
00337
00338
if ( result == KMessageBox::Cancel ) {
00339 d->userAborted =
true;
00340
return false;
00341 }
00342 }
00343 }
00344
00345 d->status = -1;
00346 d->host = host;
00347 d->needSSLHandShake = m_bIsSSL;
00348 p = port(_port);
00349 ks.setAddress(host, p);
00350
if ( d->timeout > -1 )
00351 ks.setTimeout( d->timeout );
00352
00353
if (ks.connect() < 0)
00354 {
00355 d->status = ks.status();
00356
if ( sendError )
00357 {
00358
if (d->status == IO_LookupError)
00359 error( ERR_UNKNOWN_HOST, host);
00360
else if ( d->status != -1 )
00361 error( ERR_COULD_NOT_CONNECT, host);
00362 }
00363
return false;
00364 }
00365
00366 m_iSock = ks.fd();
00367
00368
00369
const KSocketAddress *sa = ks.peerAddress();
00370
if (sa)
00371 d->ip = sa->
nodeName();
00372
else
00373 d->ip =
"";
00374
00375 ks.release();
00376
00377
if ( d->block != ks.blockingMode() )
00378 ks.setBlockingMode( d->block );
00379
00380 m_iPort=p;
00381
00382
if (m_bIsSSL && !d->useSSLTunneling) {
00383
if ( !doSSLHandShake( sendError ) )
00384
return false;
00385 }
00386
else
00387 setMetaData(
"ssl_in_use",
"FALSE");
00388
00389
00390
00391
00392
if ((fp = KDE_fdopen(m_iSock,
"w+")) == 0) {
00393 closeDescriptor();
00394
return false;
00395 }
00396
00397
return true;
00398
#else
00399
return false;
00400
#endif //Q_OS_UNIX
00401
}
00402
00403
void TCPSlaveBase::closeDescriptor()
00404 {
00405 stopTLS();
00406
if (fp) {
00407 fclose(fp);
00408 fp=0;
00409 m_iSock=-1;
00410
if (m_bIsSSL)
00411 d->kssl->close();
00412 }
00413
if (m_iSock != -1) {
00414
close(m_iSock);
00415 m_iSock=-1;
00416 }
00417 d->ip =
"";
00418 d->host =
"";
00419 }
00420
00421
bool TCPSlaveBase::initializeSSL()
00422 {
00423
if (m_bIsSSL) {
00424
if (
KSSL::doesSSLWork()) {
00425 d->kssl =
new KSSL;
00426
return true;
00427 }
00428 }
00429
return false;
00430 }
00431
00432
void TCPSlaveBase::cleanSSL()
00433 {
00434
delete d->cc;
00435
00436
if (m_bIsSSL) {
00437
delete d->kssl;
00438 d->kssl = 0;
00439 }
00440 d->militantSSL =
false;
00441 }
00442
00443
bool TCPSlaveBase::atEnd()
00444 {
00445
return feof(fp);
00446 }
00447
00448
int TCPSlaveBase::startTLS()
00449 {
00450
if (d->usingTLS || d->useSSLTunneling || m_bIsSSL || !
KSSL::doesSSLWork())
00451
return false;
00452
00453 d->kssl =
new KSSL(
false);
00454
if (!d->kssl->TLSInit()) {
00455
delete d->kssl;
00456
return -1;
00457 }
00458
00459
if ( !d->realHost.isEmpty() )
00460 {
00461
kdDebug(7029) <<
"Setting real hostname: " << d->realHost <<
endl;
00462 d->kssl->setPeerHost(d->realHost);
00463 }
else {
00464
kdDebug(7029) <<
"Setting real hostname: " << d->host <<
endl;
00465 d->kssl->setPeerHost(d->host);
00466 }
00467
00468
if (hasMetaData(
"ssl_session_id")) {
00469
KSSLSession *s =
KSSLSession::fromString(metaData(
"ssl_session_id"));
00470
if (s) {
00471 d->kssl->setSession(s);
00472
delete s;
00473 }
00474 }
00475 certificatePrompt();
00476
00477
int rc = d->kssl->connect(m_iSock);
00478
if (rc < 0) {
00479
delete d->kssl;
00480
return -2;
00481 }
00482
00483 setMetaData(
"ssl_session_id", d->kssl->session()->toString());
00484
00485 d->usingTLS =
true;
00486 setMetaData(
"ssl_in_use",
"TRUE");
00487
00488
if (!d->kssl->reusingSession()) {
00489 rc = verifyCertificate();
00490
if (rc != 1) {
00491 setMetaData(
"ssl_in_use",
"FALSE");
00492 d->usingTLS =
false;
00493
delete d->kssl;
00494
return -3;
00495 }
00496 }
00497
00498 d->savedMetaData = mOutgoingMetaData;
00499
return (d->usingTLS ? 1 : 0);
00500 }
00501
00502
00503
void TCPSlaveBase::stopTLS()
00504 {
00505
if (d->usingTLS) {
00506
delete d->kssl;
00507 d->usingTLS =
false;
00508 setMetaData(
"ssl_in_use",
"FALSE");
00509 }
00510 }
00511
00512
00513
void TCPSlaveBase::setSSLMetaData() {
00514
if (!(d->usingTLS || d->useSSLTunneling || m_bIsSSL))
00515
return;
00516
00517 mOutgoingMetaData = d->savedMetaData;
00518 }
00519
00520
00521
bool TCPSlaveBase::canUseTLS()
00522 {
00523
if (m_bIsSSL || d->needSSLHandShake || !
KSSL::doesSSLWork())
00524
return false;
00525
00526
KSSLSettings kss;
00527
return kss.
tlsv1();
00528 }
00529
00530
00531
void TCPSlaveBase::certificatePrompt()
00532 {
00533
QString certname;
00534
bool send =
false, prompt =
false,
save =
false, forcePrompt =
false;
00535 KSSLCertificateHome::KSSLAuthAction aa;
00536
00537 setMetaData(
"ssl_using_client_cert",
"FALSE");
00538
00539
if (metaData(
"ssl_no_client_cert") ==
"TRUE")
return;
00540 forcePrompt = (metaData(
"ssl_force_cert_prompt") ==
"TRUE");
00541
00542
00543
if (d->pkcs) {
00544
delete d->pkcs;
00545 d->pkcs = NULL;
00546 }
00547
00548
if (!d->kssl)
return;
00549
00550
00551
if (!forcePrompt) {
00552 certname = KSSLCertificateHome::getDefaultCertificateName(&aa);
00553
switch(aa) {
00554
case KSSLCertificateHome::AuthSend:
00555 send =
true; prompt =
false;
00556
break;
00557
case KSSLCertificateHome::AuthDont:
00558 send =
false; prompt =
false;
00559 certname = QString::null;
00560
break;
00561
case KSSLCertificateHome::AuthPrompt:
00562 send =
false; prompt =
true;
00563
break;
00564
default:
00565
break;
00566 }
00567 }
00568
00569
QString ourHost;
00570
if (!d->realHost.isEmpty()) {
00571 ourHost = d->realHost;
00572 }
else {
00573 ourHost = d->host;
00574 }
00575
00576
00577
QString tmpcn = KSSLCertificateHome::getDefaultCertificateName(ourHost, &aa);
00578
if (aa != KSSLCertificateHome::AuthNone) {
00579
switch (aa) {
00580
case KSSLCertificateHome::AuthSend:
00581 send =
true;
00582 prompt =
false;
00583 certname = tmpcn;
00584
break;
00585
case KSSLCertificateHome::AuthDont:
00586 send =
false;
00587 prompt =
false;
00588 certname = QString::null;
00589
break;
00590
case KSSLCertificateHome::AuthPrompt:
00591 send =
false;
00592 prompt =
true;
00593 certname = tmpcn;
00594
break;
00595
default:
00596
break;
00597 }
00598 }
00599
00600
00601
if (hasMetaData(
"ssl_demand_certificate")) {
00602 certname = metaData(
"ssl_demand_certificate");
00603
if (!certname.
isEmpty()) {
00604 forcePrompt =
false;
00605 prompt =
false;
00606 send =
true;
00607 }
00608 }
00609
00610
if (certname.
isEmpty() && !prompt && !forcePrompt)
return;
00611
00612
00613
if (prompt || forcePrompt) {
00614
QStringList certs = KSSLCertificateHome::getCertificateList();
00615
00616
for (QStringList::Iterator it = certs.begin(); it != certs.end(); ++it) {
00617
KSSLPKCS12 *pkcs = KSSLCertificateHome::getCertificateByName(*it);
00618
if (pkcs && (!pkcs->
getCertificate() ||
00619 !pkcs->
getCertificate()->
x509V3Extensions().
certTypeSSLClient())) {
00620 certs.remove(*it);
00621 }
00622 }
00623
00624
if (certs.isEmpty())
return;
00625
00626
if (!d->dcc) {
00627 d->dcc =
new DCOPClient;
00628 d->dcc->attach();
00629
if (!d->dcc->isApplicationRegistered(
"kio_uiserver")) {
00630
KApplication::startServiceByDesktopPath(
"kio_uiserver.desktop",
00631
QStringList() );
00632 }
00633 }
00634
00635
QByteArray data, retval;
00636
QCString rettype;
00637
QDataStream arg(data, IO_WriteOnly);
00638 arg << ourHost;
00639 arg << certs;
00640 arg << metaData(
"window-id").toInt();
00641
bool rc = d->dcc->call(
"kio_uiserver",
"UIServer",
00642
"showSSLCertDialog(QString, QStringList,int)",
00643 data, rettype, retval);
00644
00645
if (rc && rettype ==
"KSSLCertDlgRet") {
00646
QDataStream retStream(retval, IO_ReadOnly);
00647 KSSLCertDlgRet drc;
00648 retStream >> drc;
00649
if (drc.ok) {
00650 send = drc.send;
00651
save = drc.save;
00652 certname = drc.choice;
00653 }
00654 }
00655 }
00656
00657
00658
00659
if (!send) {
00660
if (
save) {
00661 KSSLCertificateHome::setDefaultCertificate(certname, ourHost,
00662
false,
false);
00663 }
00664
return;
00665 }
00666
00667
00668
KSSLPKCS12 *pkcs = KSSLCertificateHome::getCertificateByName(certname);
00669
if (!pkcs && KSSLCertificateHome::hasCertificateByName(certname)) {
00670
KIO::AuthInfo ai;
00671
bool showprompt = !checkCachedAuthentication(ai);
00672
do {
00673
QString pass;
00674
QByteArray authdata, authval;
00675
QCString rettype;
00676
QDataStream qds(authdata, IO_WriteOnly);
00677 ai.
prompt = i18n(
"Enter the certificate password:");
00678 ai.
caption = i18n(
"SSL Certificate Password");
00679 ai.
setModified(
true);
00680 ai.
username = certname;
00681 ai.
keepPassword =
true;
00682
if (showprompt) {
00683 qds << ai;
00684
00685
if (!d->dcc) {
00686 d->dcc =
new DCOPClient;
00687 d->dcc->attach();
00688
if (!d->dcc->isApplicationRegistered(
"kio_uiserver")) {
00689
KApplication::startServiceByDesktopPath(
"kio_uiserver.desktop",
00690
QStringList() );
00691 }
00692 }
00693
00694
bool rc = d->dcc->call(
"kio_uiserver",
"UIServer",
00695
"openPassDlg(KIO::AuthInfo)",
00696 authdata, rettype, authval);
00697
if (!rc) {
00698
break;
00699 }
00700
if (rettype !=
"QByteArray") {
00701
continue;
00702 }
00703
00704
QDataStream qdret(authval, IO_ReadOnly);
00705
QByteArray authdecode;
00706 qdret >> authdecode;
00707
QDataStream qdtoo(authdecode, IO_ReadOnly);
00708 qdtoo >> ai;
00709
if (!ai.isModified()) {
00710
break;
00711 }
00712 }
00713 pass = ai.password;
00714 pkcs = KSSLCertificateHome::getCertificateByName(certname, pass);
00715
00716
if (!pkcs) {
00717
int rc = messageBox(WarningYesNo, i18n(
"Unable to open the "
00718
"certificate. Try a "
00719
"new password?"),
00720 i18n(
"SSL"));
00721
if (rc == KMessageBox::No) {
00722
break;
00723 }
00724 showprompt =
true;
00725 }
00726 }
while (!pkcs);
00727
if (pkcs) {
00728 cacheAuthentication(ai);
00729 }
00730 }
00731
00732
00733
if (pkcs) {
00734
if (!d->kssl->setClientCertificate(pkcs)) {
00735 messageBox(Information, i18n(
"The procedure to set the "
00736
"client certificate for the session "
00737
"failed."), i18n(
"SSL"));
00738
delete pkcs;
00739 pkcs = 0L;
00740 }
else {
00741
kdDebug(7029) <<
"Client SSL certificate is being used." <<
endl;
00742 setMetaData(
"ssl_using_client_cert",
"TRUE");
00743
if (
save) {
00744 KSSLCertificateHome::setDefaultCertificate(certname, ourHost,
00745
true,
false);
00746 }
00747 }
00748 d->pkcs = pkcs;
00749 }
00750 }
00751
00752
00753
00754
bool TCPSlaveBase::usingTLS()
const
00755
{
00756
return d->usingTLS;
00757 }
00758
00759
00760
bool TCPSlaveBase::usingTLS()
00761 {
00762
return d->usingTLS;
00763 }
00764
00765
00766
00767
int TCPSlaveBase::verifyCertificate()
00768 {
00769
int rc = 0;
00770
bool permacache =
false;
00771
bool isChild =
false;
00772
bool _IPmatchesCN =
false;
00773
int result;
00774
bool doAddHost =
false;
00775
QString ourHost;
00776
00777
if (!d->realHost.isEmpty())
00778 ourHost = d->realHost;
00779
else ourHost = d->host;
00780
00781
QString theurl =
QString(m_sServiceName)+
"://"+ourHost+
":"+
QString::number(m_iPort);
00782
00783
if (!hasMetaData(
"ssl_militant") || metaData(
"ssl_militant") ==
"FALSE")
00784 d->militantSSL =
false;
00785
else if (metaData(
"ssl_militant") ==
"TRUE")
00786 d->militantSSL =
true;
00787
00788
if (!d->cc) d->cc =
new KSSLCertificateCache;
00789
00790
KSSLCertificate& pc = d->kssl->peerInfo().getPeerCertificate();
00791
00792
KSSLCertificate::KSSLValidationList ksvl = pc.
validateVerbose(KSSLCertificate::SSLServer);
00793
00794 _IPmatchesCN = d->kssl->peerInfo().certMatchesAddress();
00795
if (!_IPmatchesCN && !d->militantSSL) {
00796
if (d->cc->getHostList(pc).contains(ourHost))
00797 _IPmatchesCN =
true;
00798 }
00799
00800
if (!_IPmatchesCN)
00801 {
00802 ksvl << KSSLCertificate::InvalidHost;
00803 }
00804
00805
KSSLCertificate::KSSLValidation ksv = KSSLCertificate::Ok;
00806
if (!ksvl.
isEmpty())
00807 ksv = ksvl.
first();
00808
00809
00810 setMetaData(
"ssl_cipher", d->kssl->connectionInfo().getCipher());
00811 setMetaData(
"ssl_cipher_desc",
00812 d->kssl->connectionInfo().getCipherDescription());
00813 setMetaData(
"ssl_cipher_version",
00814 d->kssl->connectionInfo().getCipherVersion());
00815 setMetaData(
"ssl_cipher_used_bits",
00816 QString::number(d->kssl->connectionInfo().getCipherUsedBits()));
00817 setMetaData(
"ssl_cipher_bits",
00818 QString::number(d->kssl->connectionInfo().getCipherBits()));
00819 setMetaData(
"ssl_peer_ip", d->ip);
00820
00821 QString errorStr;
00822
for(KSSLCertificate::KSSLValidationList::ConstIterator it = ksvl.
begin();
00823 it != ksvl.
end(); ++it)
00824 {
00825 errorStr +=
QString::number(*it)+
":";
00826 }
00827 setMetaData(
"ssl_cert_errors", errorStr);
00828 setMetaData(
"ssl_peer_certificate", pc.
toString());
00829
00830
if (pc.
chain().
isValid() && pc.
chain().
depth() > 1) {
00831 QString theChain;
00832
QPtrList<KSSLCertificate> chain = pc.
chain().
getChain();
00833
for (
KSSLCertificate *c = chain.
first(); c; c = chain.
next()) {
00834 theChain += c->
toString();
00835 theChain +=
"\n";
00836 }
00837 setMetaData(
"ssl_peer_chain", theChain);
00838 }
else setMetaData(
"ssl_peer_chain",
"");
00839
00840 setMetaData(
"ssl_cert_state", QString::number(ksv));
00841
00842
if (ksv == KSSLCertificate::Ok) {
00843 rc = 1;
00844 setMetaData(
"ssl_action",
"accept");
00845 }
00846
00847
kdDebug(7029) <<
"SSL HTTP frame the parent? " << metaData(
"main_frame_request") <<
endl;
00848
if (!hasMetaData(
"main_frame_request") || metaData(
"main_frame_request") ==
"TRUE") {
00849
00850 setMetaData(
"ssl_parent_ip", d->ip);
00851 setMetaData(
"ssl_parent_cert", pc.
toString());
00852
00853 KSSLCertificateCache::KSSLCertificatePolicy cp =
00854 d->cc->getPolicyByCertificate(pc);
00855
00856
00857
if (ksv != KSSLCertificate::Ok) {
00858
if (d->militantSSL) {
00859
return -1;
00860 }
00861
00862
if (cp == KSSLCertificateCache::Unknown ||
00863 cp == KSSLCertificateCache::Ambiguous) {
00864 cp = KSSLCertificateCache::Prompt;
00865 }
else {
00866
00867 permacache = d->cc->isPermanent(pc);
00868 }
00869
00870
if (!_IPmatchesCN && cp == KSSLCertificateCache::Accept) {
00871 cp = KSSLCertificateCache::Prompt;
00872
00873 }
00874
00875
00876
switch (cp) {
00877
case KSSLCertificateCache::Accept:
00878 rc = 1;
00879 setMetaData(
"ssl_action",
"accept");
00880
break;
00881
case KSSLCertificateCache::Reject:
00882 rc = -1;
00883 setMetaData(
"ssl_action",
"reject");
00884
break;
00885
case KSSLCertificateCache::Prompt:
00886 {
00887
do {
00888
if (ksv == KSSLCertificate::InvalidHost) {
00889 QString msg = i18n(
"The IP address of the host %1 "
00890
"does not match the one the "
00891
"certificate was issued to.");
00892 result = messageBox( WarningYesNoCancel,
00893 msg.
arg(ourHost),
00894 i18n(
"Server Authentication"),
00895 i18n(
"&Details"),
00896 i18n(
"Co&ntinue") );
00897 }
else {
00898 QString msg = i18n(
"The server certificate failed the "
00899
"authenticity test (%1).");
00900 result = messageBox( WarningYesNoCancel,
00901 msg.
arg(ourHost),
00902 i18n(
"Server Authentication"),
00903 i18n(
"&Details"),
00904 i18n(
"Co&ntinue") );
00905 }
00906
00907
if (result == KMessageBox::Yes) {
00908
if (!d->dcc) {
00909 d->dcc =
new DCOPClient;
00910 d->dcc->attach();
00911
if (!d->dcc->isApplicationRegistered(
"kio_uiserver")) {
00912
KApplication::startServiceByDesktopPath(
"kio_uiserver.desktop",
00913
QStringList() );
00914 }
00915
00916 }
00917
QByteArray data, ignore;
00918
QCString ignoretype;
00919
QDataStream arg(data, IO_WriteOnly);
00920 arg << theurl << mOutgoingMetaData;
00921 arg << metaData(
"window-id").toInt();
00922 d->dcc->call(
"kio_uiserver",
"UIServer",
00923
"showSSLInfoDialog(QString,KIO::MetaData,int)",
00924 data, ignoretype, ignore);
00925 }
00926 }
while (result == KMessageBox::Yes);
00927
00928
if (result == KMessageBox::No) {
00929 setMetaData(
"ssl_action",
"accept");
00930 rc = 1;
00931 cp = KSSLCertificateCache::Accept;
00932 doAddHost =
true;
00933 result = messageBox( WarningYesNo,
00934 i18n(
"Would you like to accept this "
00935
"certificate forever without "
00936
"being prompted?"),
00937 i18n(
"Server Authentication"),
00938 i18n(
"&Forever"),
00939 i18n(
"&Current Sessions Only"));
00940
if (result == KMessageBox::Yes)
00941 permacache =
true;
00942
else
00943 permacache =
false;
00944 }
else {
00945 setMetaData(
"ssl_action",
"reject");
00946 rc = -1;
00947 cp = KSSLCertificateCache::Prompt;
00948 }
00949
break;
00950 }
00951
default:
00952
kdDebug(7029) <<
"TCPSlaveBase/SSL error in cert code."
00953 <<
"Please report this to kfm-devel@kde.org."
00954 <<
endl;
00955
break;
00956 }
00957 }
00958
00959
00960
00961 d->cc->addCertificate(pc, cp, permacache);
00962
if (doAddHost) d->cc->addHost(pc, ourHost);
00963 }
else {
00964
00965 KSSLCertificateCache::KSSLCertificatePolicy cp =
00966 d->cc->getPolicyByCertificate(pc);
00967 isChild =
true;
00968
00969
00970
00971
bool certAndIPTheSame = (d->ip == metaData(
"ssl_parent_ip") &&
00972 pc.
toString() == metaData(
"ssl_parent_cert"));
00973
00974
if (ksv == KSSLCertificate::Ok) {
00975
if (certAndIPTheSame) {
00976 rc = 1;
00977 setMetaData(
"ssl_action",
"accept");
00978 }
else {
00979
00980
00981
00982
00983
00984
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994 setMetaData(
"ssl_action",
"accept");
00995 rc = 1;
00996
00997
00998 }
00999 }
else {
01000
if (d->militantSSL) {
01001
return -1;
01002 }
01003
01004
if (cp == KSSLCertificateCache::Accept) {
01005
if (certAndIPTheSame) {
01006 rc = 1;
01007 setMetaData(
"ssl_action",
"accept");
01008 }
else {
01009 result = messageBox(WarningYesNo,
01010 i18n(
"You have indicated that you wish to accept this certificate, but it is not issued to the server who is presenting it. Do you wish to continue loading?"),
01011 i18n(
"Server Authentication"));
01012
if (result == KMessageBox::Yes) {
01013 rc = 1;
01014 setMetaData(
"ssl_action",
"accept");
01015 d->cc->addHost(pc, ourHost);
01016 }
else {
01017 rc = -1;
01018 setMetaData(
"ssl_action",
"reject");
01019 }
01020 }
01021 }
else if (cp == KSSLCertificateCache::Reject) {
01022 messageBox(Information, i18n(
"SSL certificate is being rejected as requested. You can disable this in the KDE Control Center."),
01023 i18n(
"Server Authentication"));
01024 rc = -1;
01025 setMetaData(
"ssl_action",
"reject");
01026 }
else {
01027
do {
01028 QString msg = i18n(
"The server certificate failed the "
01029
"authenticity test (%1).");
01030 result = messageBox(WarningYesNoCancel,
01031 msg.
arg(ourHost),
01032 i18n(
"Server Authentication"),
01033 i18n(
"&Details"),
01034 i18n(
"Co&nnect"));
01035
if (result == KMessageBox::Yes) {
01036
if (!d->dcc) {
01037 d->dcc =
new DCOPClient;
01038 d->dcc->attach();
01039
if (!d->dcc->isApplicationRegistered(
"kio_uiserver")) {
01040
KApplication::startServiceByDesktopPath(
"kio_uiserver.desktop",
01041
QStringList() );
01042 }
01043 }
01044
QByteArray data, ignore;
01045
QCString ignoretype;
01046
QDataStream arg(data, IO_WriteOnly);
01047 arg << theurl << mOutgoingMetaData;
01048 arg << metaData(
"window-id").toInt();
01049 d->dcc->call(
"kio_uiserver",
"UIServer",
01050
"showSSLInfoDialog(QString,KIO::MetaData,int)",
01051 data, ignoretype, ignore);
01052 }
01053 }
while (result == KMessageBox::Yes);
01054
01055
if (result == KMessageBox::No) {
01056 setMetaData(
"ssl_action",
"accept");
01057 rc = 1;
01058 cp = KSSLCertificateCache::Accept;
01059 result = messageBox(WarningYesNo,
01060 i18n(
"Would you like to accept this "
01061
"certificate forever without "
01062
"being prompted?"),
01063 i18n(
"Server Authentication"),
01064 i18n(
"&Forever"),
01065 i18n(
"&Current Sessions Only"));
01066 permacache = (result == KMessageBox::Yes);
01067 d->cc->addCertificate(pc, cp, permacache);
01068 d->cc->addHost(pc, ourHost);
01069 }
else {
01070 setMetaData(
"ssl_action",
"reject");
01071 rc = -1;
01072 cp = KSSLCertificateCache::Prompt;
01073 d->cc->addCertificate(pc, cp, permacache);
01074 }
01075 }
01076 }
01077 }
01078
01079
01080
if (rc == -1) {
01081
return rc;
01082 }
01083
01084
if (metaData(
"ssl_activate_warnings") ==
"TRUE") {
01085
01086
if (!isChild && metaData(
"ssl_was_in_use") ==
"FALSE" &&
01087 d->kssl->settings()->warnOnEnter()) {
01088
int result;
01089
do {
01090 result = messageBox( i18n(
"You are about to "
01091
"enter secure mode. "
01092
"All transmissions "
01093
"will be encrypted "
01094
"unless otherwise "
01095
"noted.\nThis means "
01096
"that no third party "
01097
"will be able to "
01098
"easily observe your "
01099
"data in transit."),
01100 WarningYesNo,
01101 i18n(
"Security Information"),
01102 i18n(
"Display SSL "
01103
"&Information"),
01104 i18n(
"C&onnect"),
01105
"WarnOnEnterSSLMode" );
01106
01107
KConfig *config =
new KConfig(
"kioslaverc");
01108 config->
setGroup(
"Notification Messages");
01109
01110
if (!config->
readBoolEntry(
"WarnOnEnterSSLMode",
true)) {
01111 config->
deleteEntry(
"WarnOnEnterSSLMode");
01112 config->
sync();
01113 d->kssl->settings()->setWarnOnEnter(
false);
01114 d->kssl->settings()->save();
01115 }
01116
delete config;
01117
01118
if ( result == KMessageBox::Yes )
01119 {
01120
if (!d->dcc) {
01121 d->dcc =
new DCOPClient;
01122 d->dcc->attach();
01123
if (!d->dcc->isApplicationRegistered(
"kio_uiserver")) {
01124
KApplication::startServiceByDesktopPath(
"kio_uiserver.desktop",
01125
QStringList() );
01126 }
01127 }
01128
QByteArray data, ignore;
01129
QCString ignoretype;
01130
QDataStream arg(data, IO_WriteOnly);
01131 arg << theurl << mOutgoingMetaData;
01132 arg << metaData(
"window-id").toInt();
01133 d->dcc->call(
"kio_uiserver",
"UIServer",
01134
"showSSLInfoDialog(QString,KIO::MetaData,int)",
01135 data, ignoretype, ignore);
01136 }
01137 }
while (result != KMessageBox::No);
01138 }
01139
01140 }
01141
01142
01143
kdDebug(7029) <<
"SSL connection information follows:" <<
endl
01144 <<
"+-----------------------------------------------" <<
endl
01145 <<
"| Cipher: " << d->kssl->connectionInfo().getCipher() <<
endl
01146 <<
"| Description: " << d->kssl->connectionInfo().getCipherDescription() <<
endl
01147 <<
"| Version: " << d->kssl->connectionInfo().getCipherVersion() <<
endl
01148 <<
"| Strength: " << d->kssl->connectionInfo().getCipherUsedBits()
01149 <<
" of " << d->kssl->connectionInfo().getCipherBits()
01150 <<
" bits used." <<
endl
01151 <<
"| PEER:" <<
endl
01152 <<
"| Subject: " << d->kssl->peerInfo().getPeerCertificate().getSubject() <<
endl
01153 <<
"| Issuer: " << d->kssl->peerInfo().getPeerCertificate().getIssuer() <<
endl
01154 <<
"| Validation: " << (
int)ksv <<
endl
01155 <<
"| Certificate matches IP: " << _IPmatchesCN <<
endl
01156 <<
"+-----------------------------------------------"
01157 <<
endl;
01158
01159
01160
return rc;
01161 }
01162
01163
01164
bool TCPSlaveBase::isConnectionValid()
01165 {
01166
if ( m_iSock == -1 )
01167
return false;
01168
01169 fd_set rdfs;
01170 FD_ZERO(&rdfs);
01171 FD_SET(m_iSock , &rdfs);
01172
01173
struct timeval tv;
01174 tv.tv_usec = 0;
01175 tv.tv_sec = 0;
01176
int retval;
01177
#ifdef Q_OS_UNIX
01178
do {
01179 retval = KSocks::self()->select(m_iSock+1, &rdfs, NULL, NULL, &tv);
01180
if (wasKilled())
01181
return false;
01182 }
while ((retval == -1) && (errno == EAGAIN));
01183
#else
01184
retval = -1;
01185
#endif
01186
01187
01188
01189
01190
01191
01192
if (retval == -1)
01193
return false;
01194
01195
if (retval == 0)
01196
return true;
01197
01198
01199
char buffer[100];
01200
#ifdef Q_OS_UNIX
01201
do {
01202 retval = KSocks::self()->recv(m_iSock, buffer, 80, MSG_PEEK);
01203
01204 }
while ((retval == -1) && (errno == EAGAIN));
01205
#else
01206
retval = -1;
01207
#endif
01208
01209
01210
if (retval <= 0)
01211
return false;
01212
01213
return true;
01214 }
01215
01216
01217
bool TCPSlaveBase::waitForResponse(
int t )
01218 {
01219 fd_set rd;
01220
struct timeval timeout;
01221
01222
if ( (m_bIsSSL || d->usingTLS) && !d->useSSLTunneling && d->kssl )
01223
if (d->kssl->pending() > 0)
01224
return true;
01225
01226 FD_ZERO(&rd);
01227 FD_SET(m_iSock, &rd);
01228
01229 timeout.tv_usec = 0;
01230 timeout.tv_sec = t;
01231 time_t startTime;
01232
01233
int rc;
01234
int n = t;
01235
01236 reSelect:
01237 startTime = time(NULL);
01238
#ifdef Q_OS_UNIX
01239
rc = KSocks::self()->select(m_iSock+1, &rd, NULL, NULL, &timeout);
01240
#else
01241
rc = -1;
01242
#endif
01243
if (wasKilled())
01244
return false;
01245
01246
if (rc == -1)
01247
return false;
01248
01249
if (FD_ISSET(m_iSock, &rd))
01250
return true;
01251
01252
01253
01254
01255
int timeDone = time(NULL) - startTime;
01256
if (timeDone < n)
01257 {
01258 n -= timeDone;
01259 timeout.tv_sec = n;
01260
goto reSelect;
01261 }
01262
01263
return false;
01264 }
01265
01266
int TCPSlaveBase::connectResult()
01267 {
01268
return d->status;
01269 }
01270
01271
void TCPSlaveBase::setBlockConnection(
bool b )
01272 {
01273 d->block = b;
01274 }
01275
01276
void TCPSlaveBase::setConnectTimeout(
int t )
01277 {
01278 d->timeout = t;
01279 }
01280
01281
bool TCPSlaveBase::isSSLTunnelEnabled()
01282 {
01283
return d->useSSLTunneling;
01284 }
01285
01286
void TCPSlaveBase::setEnableSSLTunnel(
bool enable )
01287 {
01288 d->useSSLTunneling = enable;
01289 }
01290
01291
void TCPSlaveBase::setRealHost(
const QString& realHost )
01292 {
01293 d->realHost = realHost;
01294 }
01295
01296
bool TCPSlaveBase::doSSLHandShake(
bool sendError )
01297 {
01298
kdDebug(7029) <<
"TCPSlaveBase::doSSLHandShake: " <<
endl;
01299 QString msgHost = d->host;
01300
01301 d->kssl->reInitialize();
01302
01303
if (hasMetaData(
"ssl_session_id")) {
01304
KSSLSession *s =
KSSLSession::fromString(metaData(
"ssl_session_id"));
01305
if (s) {
01306 d->kssl->setSession(s);
01307
delete s;
01308 }
01309 }
01310 certificatePrompt();
01311
01312
if ( !d->realHost.isEmpty() )
01313 {
01314 msgHost = d->realHost;
01315 }
01316
01317
kdDebug(7029) <<
"Setting real hostname: " << msgHost <<
endl;
01318 d->kssl->setPeerHost(msgHost);
01319
01320 d->status = d->kssl->connect(m_iSock);
01321
if (d->status < 0)
01322 {
01323 closeDescriptor();
01324
if ( sendError )
01325 error( ERR_COULD_NOT_CONNECT, msgHost);
01326
return false;
01327 }
01328
01329 setMetaData(
"ssl_session_id", d->kssl->session()->toString());
01330 setMetaData(
"ssl_in_use",
"TRUE");
01331
01332
if (!d->kssl->reusingSession()) {
01333
int rc = verifyCertificate();
01334
if ( rc != 1 ) {
01335 d->status = -1;
01336 closeDescriptor();
01337
if ( sendError )
01338 error( ERR_COULD_NOT_CONNECT, msgHost);
01339
return false;
01340 }
01341 }
01342
01343 d->needSSLHandShake =
false;
01344
01345 d->savedMetaData = mOutgoingMetaData;
01346
return true;
01347 }
01348
01349
01350
bool TCPSlaveBase::userAborted()
const
01351
{
01352
return d->userAborted;
01353 }
01354
01355
void TCPSlaveBase::virtual_hook(
int id,
void* data )
01356 { SlaveBase::virtual_hook(
id, data ); }
01357