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