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