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