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