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 delete pkcs;
00626 }
00627
00628 if (certs.isEmpty()) return;
00629
00630 if (!d->dcc) {
00631 d->dcc = new DCOPClient;
00632 d->dcc->attach();
00633 if (!d->dcc->isApplicationRegistered("kio_uiserver")) {
00634 KApplication::startServiceByDesktopPath("kio_uiserver.desktop",
00635 QStringList() );
00636 }
00637 }
00638
00639 QByteArray data, retval;
00640 QCString rettype;
00641 QDataStream arg(data, IO_WriteOnly);
00642 arg << ourHost;
00643 arg << certs;
00644 arg << metaData("window-id").toInt();
00645 bool rc = d->dcc->call("kio_uiserver", "UIServer",
00646 "showSSLCertDialog(QString, QStringList,int)",
00647 data, rettype, retval);
00648
00649 if (rc && rettype == "KSSLCertDlgRet") {
00650 QDataStream retStream(retval, IO_ReadOnly);
00651 KSSLCertDlgRet drc;
00652 retStream >> drc;
00653 if (drc.ok) {
00654 send = drc.send;
00655 save = drc.save;
00656 certname = drc.choice;
00657 }
00658 }
00659 }
00660
00661
00662
00663 if (!send) {
00664 if (save) {
00665 KSSLCertificateHome::setDefaultCertificate(certname, ourHost,
00666 false, false);
00667 }
00668 return;
00669 }
00670
00671
00672 KSSLPKCS12 *pkcs = KSSLCertificateHome::getCertificateByName(certname);
00673 if (!pkcs && KSSLCertificateHome::hasCertificateByName(certname)) {
00674 KIO::AuthInfo ai;
00675 bool first = true;
00676 do {
00677 ai.prompt = i18n("Enter the certificate password:");
00678 ai.caption = i18n("SSL Certificate Password");
00679 ai.url.setProtocol("kssl");
00680 ai.url.setHost(certname);
00681 ai.username = certname;
00682 ai.keepPassword = true;
00683
00684 bool showprompt;
00685 if (first)
00686 showprompt = !checkCachedAuthentication(ai);
00687 else
00688 showprompt = true;
00689 if (showprompt) {
00690 if (!openPassDlg(ai, first ? QString::null :
00691 i18n("Unable to open the certificate. Try a new password?")))
00692 break;
00693 }
00694
00695 first = false;
00696 pkcs = KSSLCertificateHome::getCertificateByName(certname, ai.password);
00697 } while (!pkcs);
00698
00699 }
00700
00701
00702 if (pkcs) {
00703 if (!d->kssl->setClientCertificate(pkcs)) {
00704 messageBox(Information, i18n("The procedure to set the "
00705 "client certificate for the session "
00706 "failed."), i18n("SSL"));
00707 delete pkcs;
00708 pkcs = 0L;
00709 } else {
00710 kdDebug(7029) << "Client SSL certificate is being used." << endl;
00711 setMetaData("ssl_using_client_cert", "TRUE");
00712 if (save) {
00713 KSSLCertificateHome::setDefaultCertificate(certname, ourHost,
00714 true, false);
00715 }
00716 }
00717 d->pkcs = pkcs;
00718 }
00719 }
00720
00721
00722
00723 bool TCPSlaveBase::usingTLS() const
00724 {
00725 return d->usingTLS;
00726 }
00727
00728
00729 bool TCPSlaveBase::usingTLS()
00730 {
00731 return d->usingTLS;
00732 }
00733
00734
00735
00736 int TCPSlaveBase::verifyCertificate()
00737 {
00738 int rc = 0;
00739 bool permacache = false;
00740 bool isChild = false;
00741 bool _IPmatchesCN = false;
00742 int result;
00743 bool doAddHost = false;
00744 QString ourHost;
00745
00746 if (!d->realHost.isEmpty())
00747 ourHost = d->realHost;
00748 else ourHost = d->host;
00749
00750 QString theurl = QString(m_sServiceName)+"://"+ourHost+":"+QString::number(m_iPort);
00751
00752 if (!hasMetaData("ssl_militant") || metaData("ssl_militant") == "FALSE")
00753 d->militantSSL = false;
00754 else if (metaData("ssl_militant") == "TRUE")
00755 d->militantSSL = true;
00756
00757 if (!d->cc) d->cc = new KSSLCertificateCache;
00758
00759 KSSLCertificate& pc = d->kssl->peerInfo().getPeerCertificate();
00760
00761 KSSLCertificate::KSSLValidationList ksvl = pc.validateVerbose(KSSLCertificate::SSLServer);
00762
00763 _IPmatchesCN = d->kssl->peerInfo().certMatchesAddress();
00764 if (!_IPmatchesCN) {
00765 #ifndef Q_WS_WIN //temporary
00766 KNetwork::KResolverResults res = KNetwork::KResolver::resolve(d->kssl->peerInfo().peerHost(), "80", KNetwork::KResolver::CanonName);
00767 if (!res.isEmpty()) {
00768 QString old = d->kssl->peerInfo().peerHost();
00769 d->kssl->peerInfo().setPeerHost(res[0].canonicalName());
00770 _IPmatchesCN = d->kssl->peerInfo().certMatchesAddress();
00771 if (!_IPmatchesCN) {
00772 d->kssl->peerInfo().setPeerHost(old);
00773 }
00774 }
00775 #endif
00776 if (!_IPmatchesCN && !d->militantSSL) {
00777 if (d->cc->getHostList(pc).contains(ourHost)) {
00778 _IPmatchesCN = true;
00779 }
00780 }
00781 }
00782
00783 if (!_IPmatchesCN) {
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 if (!d->realHost.isEmpty()) {
00803 setMetaData("ssl_proxied", "true");
00804 }
00805
00806 QString errorStr;
00807 for(KSSLCertificate::KSSLValidationList::ConstIterator it = ksvl.begin();
00808 it != ksvl.end(); ++it)
00809 {
00810 errorStr += QString::number(*it)+":";
00811 }
00812 setMetaData("ssl_cert_errors", errorStr);
00813 setMetaData("ssl_peer_certificate", pc.toString());
00814
00815 if (pc.chain().isValid() && pc.chain().depth() > 1) {
00816 QString theChain;
00817 QPtrList<KSSLCertificate> chain = pc.chain().getChain();
00818 for (KSSLCertificate *c = chain.first(); c; c = chain.next()) {
00819 theChain += c->toString();
00820 theChain += "\n";
00821 }
00822 setMetaData("ssl_peer_chain", theChain);
00823 } else setMetaData("ssl_peer_chain", "");
00824
00825 setMetaData("ssl_cert_state", QString::number(ksv));
00826
00827 if (ksv == KSSLCertificate::Ok) {
00828 rc = 1;
00829 setMetaData("ssl_action", "accept");
00830 }
00831
00832 kdDebug(7029) << "SSL HTTP frame the parent? " << metaData("main_frame_request") << endl;
00833 if (!hasMetaData("main_frame_request") || metaData("main_frame_request") == "TRUE") {
00834
00835 setMetaData("ssl_parent_ip", d->ip);
00836 setMetaData("ssl_parent_cert", pc.toString());
00837
00838 KSSLCertificateCache::KSSLCertificatePolicy cp =
00839 d->cc->getPolicyByCertificate(pc);
00840
00841
00842 if (ksv != KSSLCertificate::Ok) {
00843 if (d->militantSSL) {
00844 return -1;
00845 }
00846
00847 if (cp == KSSLCertificateCache::Unknown ||
00848 cp == KSSLCertificateCache::Ambiguous) {
00849 cp = KSSLCertificateCache::Prompt;
00850 } else {
00851
00852 permacache = d->cc->isPermanent(pc);
00853 }
00854
00855 if (!_IPmatchesCN && cp == KSSLCertificateCache::Accept) {
00856 cp = KSSLCertificateCache::Prompt;
00857
00858 }
00859
00860
00861 switch (cp) {
00862 case KSSLCertificateCache::Accept:
00863 rc = 1;
00864 setMetaData("ssl_action", "accept");
00865 break;
00866 case KSSLCertificateCache::Reject:
00867 rc = -1;
00868 setMetaData("ssl_action", "reject");
00869 break;
00870 case KSSLCertificateCache::Prompt:
00871 {
00872 do {
00873 if (ksv == KSSLCertificate::InvalidHost) {
00874 QString msg = i18n("The IP address of the host %1 "
00875 "does not match the one the "
00876 "certificate was issued to.");
00877 result = messageBox( WarningYesNoCancel,
00878 msg.arg(ourHost),
00879 i18n("Server Authentication"),
00880 i18n("&Details"),
00881 i18n("Co&ntinue") );
00882 } else {
00883 QString msg = i18n("The server certificate failed the "
00884 "authenticity test (%1).");
00885 result = messageBox( WarningYesNoCancel,
00886 msg.arg(ourHost),
00887 i18n("Server Authentication"),
00888 i18n("&Details"),
00889 i18n("Co&ntinue") );
00890 }
00891
00892 if (result == KMessageBox::Yes) {
00893 if (!d->dcc) {
00894 d->dcc = new DCOPClient;
00895 d->dcc->attach();
00896 if (!d->dcc->isApplicationRegistered("kio_uiserver")) {
00897 KApplication::startServiceByDesktopPath("kio_uiserver.desktop",
00898 QStringList() );
00899 }
00900
00901 }
00902 QByteArray data, ignore;
00903 QCString ignoretype;
00904 QDataStream arg(data, IO_WriteOnly);
00905 arg << theurl << mOutgoingMetaData;
00906 arg << metaData("window-id").toInt();
00907 d->dcc->call("kio_uiserver", "UIServer",
00908 "showSSLInfoDialog(QString,KIO::MetaData,int)",
00909 data, ignoretype, ignore);
00910 }
00911 } while (result == KMessageBox::Yes);
00912
00913 if (result == KMessageBox::No) {
00914 setMetaData("ssl_action", "accept");
00915 rc = 1;
00916 cp = KSSLCertificateCache::Accept;
00917 doAddHost = true;
00918 result = messageBox( WarningYesNo,
00919 i18n("Would you like to accept this "
00920 "certificate forever without "
00921 "being prompted?"),
00922 i18n("Server Authentication"),
00923 i18n("&Forever"),
00924 i18n("&Current Sessions Only"));
00925 if (result == KMessageBox::Yes)
00926 permacache = true;
00927 else
00928 permacache = false;
00929 } else {
00930 setMetaData("ssl_action", "reject");
00931 rc = -1;
00932 cp = KSSLCertificateCache::Prompt;
00933 }
00934 break;
00935 }
00936 default:
00937 kdDebug(7029) << "TCPSlaveBase/SSL error in cert code."
00938 << "Please report this to kfm-devel@kde.org."
00939 << endl;
00940 break;
00941 }
00942 }
00943
00944
00945
00946 d->cc->addCertificate(pc, cp, permacache);
00947 if (doAddHost) d->cc->addHost(pc, ourHost);
00948 } else {
00949
00950 KSSLCertificateCache::KSSLCertificatePolicy cp =
00951 d->cc->getPolicyByCertificate(pc);
00952 isChild = true;
00953
00954
00955
00956 bool certAndIPTheSame = (d->ip == metaData("ssl_parent_ip") &&
00957 pc.toString() == metaData("ssl_parent_cert"));
00958
00959 if (ksv == KSSLCertificate::Ok) {
00960 if (certAndIPTheSame) {
00961 rc = 1;
00962 setMetaData("ssl_action", "accept");
00963 } else {
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979 setMetaData("ssl_action", "accept");
00980 rc = 1;
00981
00982
00983 }
00984 } else {
00985 if (d->militantSSL) {
00986 return -1;
00987 }
00988
00989 if (cp == KSSLCertificateCache::Accept) {
00990 if (certAndIPTheSame) {
00991 rc = 1;
00992 setMetaData("ssl_action", "accept");
00993 } else {
00994 result = messageBox(WarningYesNo,
00995 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?"),
00996 i18n("Server Authentication"));
00997 if (result == KMessageBox::Yes) {
00998 rc = 1;
00999 setMetaData("ssl_action", "accept");
01000 d->cc->addHost(pc, ourHost);
01001 } else {
01002 rc = -1;
01003 setMetaData("ssl_action", "reject");
01004 }
01005 }
01006 } else if (cp == KSSLCertificateCache::Reject) {
01007 messageBox(Information, i18n("SSL certificate is being rejected as requested. You can disable this in the KDE Control Center."),
01008 i18n("Server Authentication"));
01009 rc = -1;
01010 setMetaData("ssl_action", "reject");
01011 } else {
01012 do {
01013 QString msg = i18n("The server certificate failed the "
01014 "authenticity test (%1).");
01015 result = messageBox(WarningYesNoCancel,
01016 msg.arg(ourHost),
01017 i18n("Server Authentication"),
01018 i18n("&Details"),
01019 i18n("Co&nnect"));
01020 if (result == KMessageBox::Yes) {
01021 if (!d->dcc) {
01022 d->dcc = new DCOPClient;
01023 d->dcc->attach();
01024 if (!d->dcc->isApplicationRegistered("kio_uiserver")) {
01025 KApplication::startServiceByDesktopPath("kio_uiserver.desktop",
01026 QStringList() );
01027 }
01028 }
01029 QByteArray data, ignore;
01030 QCString ignoretype;
01031 QDataStream arg(data, IO_WriteOnly);
01032 arg << theurl << mOutgoingMetaData;
01033 arg << metaData("window-id").toInt();
01034 d->dcc->call("kio_uiserver", "UIServer",
01035 "showSSLInfoDialog(QString,KIO::MetaData,int)",
01036 data, ignoretype, ignore);
01037 }
01038 } while (result == KMessageBox::Yes);
01039
01040 if (result == KMessageBox::No) {
01041 setMetaData("ssl_action", "accept");
01042 rc = 1;
01043 cp = KSSLCertificateCache::Accept;
01044 result = messageBox(WarningYesNo,
01045 i18n("Would you like to accept this "
01046 "certificate forever without "
01047 "being prompted?"),
01048 i18n("Server Authentication"),
01049 i18n("&Forever"),
01050 i18n("&Current Sessions Only"));
01051 permacache = (result == KMessageBox::Yes);
01052 d->cc->addCertificate(pc, cp, permacache);
01053 d->cc->addHost(pc, ourHost);
01054 } else {
01055 setMetaData("ssl_action", "reject");
01056 rc = -1;
01057 cp = KSSLCertificateCache::Prompt;
01058 d->cc->addCertificate(pc, cp, permacache);
01059 }
01060 }
01061 }
01062 }
01063
01064
01065 if (rc == -1) {
01066 return rc;
01067 }
01068
01069 if (metaData("ssl_activate_warnings") == "TRUE") {
01070
01071 if (!isChild && metaData("ssl_was_in_use") == "FALSE" &&
01072 d->kssl->settings()->warnOnEnter()) {
01073 int result;
01074 do {
01075 result = messageBox( i18n("You are about to "
01076 "enter secure mode. "
01077 "All transmissions "
01078 "will be encrypted "
01079 "unless otherwise "
01080 "noted.\nThis means "
01081 "that no third party "
01082 "will be able to "
01083 "easily observe your "
01084 "data in transit."),
01085 WarningYesNo,
01086 i18n("Security Information"),
01087 i18n("Display SSL "
01088 "&Information"),
01089 i18n("C&onnect"),
01090 "WarnOnEnterSSLMode" );
01091
01092 KConfig *config = new KConfig("kioslaverc");
01093 config->setGroup("Notification Messages");
01094
01095 if (!config->readBoolEntry("WarnOnEnterSSLMode", true)) {
01096 config->deleteEntry("WarnOnEnterSSLMode");
01097 config->sync();
01098 d->kssl->settings()->setWarnOnEnter(false);
01099 d->kssl->settings()->save();
01100 }
01101 delete config;
01102
01103 if ( result == KMessageBox::Yes )
01104 {
01105 if (!d->dcc) {
01106 d->dcc = new DCOPClient;
01107 d->dcc->attach();
01108 if (!d->dcc->isApplicationRegistered("kio_uiserver")) {
01109 KApplication::startServiceByDesktopPath("kio_uiserver.desktop",
01110 QStringList() );
01111 }
01112 }
01113 QByteArray data, ignore;
01114 QCString ignoretype;
01115 QDataStream arg(data, IO_WriteOnly);
01116 arg << theurl << mOutgoingMetaData;
01117 arg << metaData("window-id").toInt();
01118 d->dcc->call("kio_uiserver", "UIServer",
01119 "showSSLInfoDialog(QString,KIO::MetaData,int)",
01120 data, ignoretype, ignore);
01121 }
01122 } while (result != KMessageBox::No);
01123 }
01124
01125 }
01126
01127
01128 kdDebug(7029) << "SSL connection information follows:" << endl
01129 << "+-----------------------------------------------" << endl
01130 << "| Cipher: " << d->kssl->connectionInfo().getCipher() << endl
01131 << "| Description: " << d->kssl->connectionInfo().getCipherDescription() << endl
01132 << "| Version: " << d->kssl->connectionInfo().getCipherVersion() << endl
01133 << "| Strength: " << d->kssl->connectionInfo().getCipherUsedBits()
01134 << " of " << d->kssl->connectionInfo().getCipherBits()
01135 << " bits used." << endl
01136 << "| PEER:" << endl
01137 << "| Subject: " << d->kssl->peerInfo().getPeerCertificate().getSubject() << endl
01138 << "| Issuer: " << d->kssl->peerInfo().getPeerCertificate().getIssuer() << endl
01139 << "| Validation: " << (int)ksv << endl
01140 << "| Certificate matches IP: " << _IPmatchesCN << endl
01141 << "+-----------------------------------------------"
01142 << endl;
01143
01144
01145 return rc;
01146 }
01147
01148
01149 bool TCPSlaveBase::isConnectionValid()
01150 {
01151 if ( m_iSock == -1 )
01152 return false;
01153
01154 fd_set rdfs;
01155 FD_ZERO(&rdfs);
01156 FD_SET(m_iSock , &rdfs);
01157
01158 struct timeval tv;
01159 tv.tv_usec = 0;
01160 tv.tv_sec = 0;
01161 int retval;
01162 #ifdef Q_OS_UNIX
01163 do {
01164 retval = KSocks::self()->select(m_iSock+1, &rdfs, NULL, NULL, &tv);
01165 if (wasKilled())
01166 return false;
01167 } while ((retval == -1) && (errno == EAGAIN));
01168 #else
01169 retval = -1;
01170 #endif
01171
01172
01173
01174
01175
01176
01177 if (retval == -1)
01178 return false;
01179
01180 if (retval == 0)
01181 return true;
01182
01183
01184 char buffer[100];
01185 #ifdef Q_OS_UNIX
01186 do {
01187 retval = KSocks::self()->recv(m_iSock, buffer, 80, MSG_PEEK);
01188
01189 } while ((retval == -1) && (errno == EAGAIN));
01190 #else
01191 retval = -1;
01192 #endif
01193
01194
01195 if (retval <= 0)
01196 return false;
01197
01198 return true;
01199 }
01200
01201
01202 bool TCPSlaveBase::waitForResponse( int t )
01203 {
01204 fd_set rd;
01205 struct timeval timeout;
01206
01207 if ( (m_bIsSSL || d->usingTLS) && !d->useSSLTunneling && d->kssl )
01208 if (d->kssl->pending() > 0)
01209 return true;
01210
01211 FD_ZERO(&rd);
01212 FD_SET(m_iSock, &rd);
01213
01214 timeout.tv_usec = 0;
01215 timeout.tv_sec = t;
01216 time_t startTime;
01217
01218 int rc;
01219 int n = t;
01220
01221 reSelect:
01222 startTime = time(NULL);
01223 #ifdef Q_OS_UNIX
01224 rc = KSocks::self()->select(m_iSock+1, &rd, NULL, NULL, &timeout);
01225 #else
01226 rc = -1;
01227 #endif
01228 if (wasKilled())
01229 return false;
01230
01231 if (rc == -1)
01232 return false;
01233
01234 if (FD_ISSET(m_iSock, &rd))
01235 return true;
01236
01237
01238
01239
01240 int timeDone = time(NULL) - startTime;
01241 if (timeDone < n)
01242 {
01243 n -= timeDone;
01244 timeout.tv_sec = n;
01245 goto reSelect;
01246 }
01247
01248 return false;
01249 }
01250
01251 int TCPSlaveBase::connectResult()
01252 {
01253 return d->status;
01254 }
01255
01256 void TCPSlaveBase::setBlockConnection( bool b )
01257 {
01258 d->block = b;
01259 }
01260
01261 void TCPSlaveBase::setConnectTimeout( int t )
01262 {
01263 d->timeout = t;
01264 }
01265
01266 bool TCPSlaveBase::isSSLTunnelEnabled()
01267 {
01268 return d->useSSLTunneling;
01269 }
01270
01271 void TCPSlaveBase::setEnableSSLTunnel( bool enable )
01272 {
01273 d->useSSLTunneling = enable;
01274 }
01275
01276 void TCPSlaveBase::setRealHost( const QString& realHost )
01277 {
01278 d->realHost = realHost;
01279 }
01280
01281 bool TCPSlaveBase::doSSLHandShake( bool sendError )
01282 {
01283 kdDebug(7029) << "TCPSlaveBase::doSSLHandShake: " << endl;
01284 QString msgHost = d->host;
01285
01286 d->kssl->reInitialize();
01287
01288 if (hasMetaData("ssl_session_id")) {
01289 KSSLSession *s = KSSLSession::fromString(metaData("ssl_session_id"));
01290 if (s) {
01291 d->kssl->setSession(s);
01292 delete s;
01293 }
01294 }
01295 certificatePrompt();
01296
01297 if ( !d->realHost.isEmpty() )
01298 {
01299 msgHost = d->realHost;
01300 }
01301
01302 kdDebug(7029) << "Setting real hostname: " << msgHost << endl;
01303 d->kssl->setPeerHost(msgHost);
01304
01305 d->status = d->kssl->connect(m_iSock);
01306 if (d->status < 0)
01307 {
01308 closeDescriptor();
01309 if ( sendError )
01310 error( ERR_COULD_NOT_CONNECT, msgHost);
01311 return false;
01312 }
01313
01314 setMetaData("ssl_session_id", d->kssl->session()->toString());
01315 setMetaData("ssl_in_use", "TRUE");
01316
01317 if (!d->kssl->reusingSession()) {
01318 int rc = verifyCertificate();
01319 if ( rc != 1 ) {
01320 d->status = -1;
01321 closeDescriptor();
01322 if ( sendError )
01323 error( ERR_COULD_NOT_CONNECT, msgHost);
01324 return false;
01325 }
01326 }
01327
01328 d->needSSLHandShake = false;
01329
01330 d->savedMetaData = mOutgoingMetaData;
01331 return true;
01332 }
01333
01334
01335 bool TCPSlaveBase::userAborted() const
01336 {
01337 return d->userAborted;
01338 }
01339
01340 void TCPSlaveBase::virtual_hook( int id, void* data )
01341 { SlaveBase::virtual_hook( id, data ); }
01342