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 chain.setAutoDelete(true);
00819 for (KSSLCertificate *c = chain.first(); c; c = chain.next()) {
00820 theChain += c->toString();
00821 theChain += "\n";
00822 }
00823 setMetaData("ssl_peer_chain", theChain);
00824 } else setMetaData("ssl_peer_chain", "");
00825
00826 setMetaData("ssl_cert_state", QString::number(ksv));
00827
00828 if (ksv == KSSLCertificate::Ok) {
00829 rc = 1;
00830 setMetaData("ssl_action", "accept");
00831 }
00832
00833 kdDebug(7029) << "SSL HTTP frame the parent? " << metaData("main_frame_request") << endl;
00834 if (!hasMetaData("main_frame_request") || metaData("main_frame_request") == "TRUE") {
00835
00836 setMetaData("ssl_parent_ip", d->ip);
00837 setMetaData("ssl_parent_cert", pc.toString());
00838
00839 KSSLCertificateCache::KSSLCertificatePolicy cp =
00840 d->cc->getPolicyByCertificate(pc);
00841
00842
00843 if (ksv != KSSLCertificate::Ok) {
00844 if (d->militantSSL) {
00845 return -1;
00846 }
00847
00848 if (cp == KSSLCertificateCache::Unknown ||
00849 cp == KSSLCertificateCache::Ambiguous) {
00850 cp = KSSLCertificateCache::Prompt;
00851 } else {
00852
00853 permacache = d->cc->isPermanent(pc);
00854 }
00855
00856 if (!_IPmatchesCN && cp == KSSLCertificateCache::Accept) {
00857 cp = KSSLCertificateCache::Prompt;
00858
00859 }
00860
00861
00862 switch (cp) {
00863 case KSSLCertificateCache::Accept:
00864 rc = 1;
00865 setMetaData("ssl_action", "accept");
00866 break;
00867 case KSSLCertificateCache::Reject:
00868 rc = -1;
00869 setMetaData("ssl_action", "reject");
00870 break;
00871 case KSSLCertificateCache::Prompt:
00872 {
00873 do {
00874 if (ksv == KSSLCertificate::InvalidHost) {
00875 QString msg = i18n("The IP address of the host %1 "
00876 "does not match the one the "
00877 "certificate was issued to.");
00878 result = messageBox( WarningYesNoCancel,
00879 msg.arg(ourHost),
00880 i18n("Server Authentication"),
00881 i18n("&Details"),
00882 i18n("Co&ntinue") );
00883 } else {
00884 QString msg = i18n("The server certificate failed the "
00885 "authenticity test (%1).");
00886 result = messageBox( WarningYesNoCancel,
00887 msg.arg(ourHost),
00888 i18n("Server Authentication"),
00889 i18n("&Details"),
00890 i18n("Co&ntinue") );
00891 }
00892
00893 if (result == KMessageBox::Yes) {
00894 if (!d->dcc) {
00895 d->dcc = new DCOPClient;
00896 d->dcc->attach();
00897 if (!d->dcc->isApplicationRegistered("kio_uiserver")) {
00898 KApplication::startServiceByDesktopPath("kio_uiserver.desktop",
00899 QStringList() );
00900 }
00901
00902 }
00903 QByteArray data, ignore;
00904 QCString ignoretype;
00905 QDataStream arg(data, IO_WriteOnly);
00906 arg << theurl << mOutgoingMetaData;
00907 arg << metaData("window-id").toInt();
00908 d->dcc->call("kio_uiserver", "UIServer",
00909 "showSSLInfoDialog(QString,KIO::MetaData,int)",
00910 data, ignoretype, ignore);
00911 }
00912 } while (result == KMessageBox::Yes);
00913
00914 if (result == KMessageBox::No) {
00915 setMetaData("ssl_action", "accept");
00916 rc = 1;
00917 cp = KSSLCertificateCache::Accept;
00918 doAddHost = true;
00919 result = messageBox( WarningYesNo,
00920 i18n("Would you like to accept this "
00921 "certificate forever without "
00922 "being prompted?"),
00923 i18n("Server Authentication"),
00924 i18n("&Forever"),
00925 i18n("&Current Sessions Only"));
00926 if (result == KMessageBox::Yes)
00927 permacache = true;
00928 else
00929 permacache = false;
00930 } else {
00931 setMetaData("ssl_action", "reject");
00932 rc = -1;
00933 cp = KSSLCertificateCache::Prompt;
00934 }
00935 break;
00936 }
00937 default:
00938 kdDebug(7029) << "TCPSlaveBase/SSL error in cert code."
00939 << "Please report this to kfm-devel@kde.org."
00940 << endl;
00941 break;
00942 }
00943 }
00944
00945
00946
00947 d->cc->addCertificate(pc, cp, permacache);
00948 if (doAddHost) d->cc->addHost(pc, ourHost);
00949 } else {
00950
00951 KSSLCertificateCache::KSSLCertificatePolicy cp =
00952 d->cc->getPolicyByCertificate(pc);
00953 isChild = true;
00954
00955
00956
00957 bool certAndIPTheSame = (d->ip == metaData("ssl_parent_ip") &&
00958 pc.toString() == metaData("ssl_parent_cert"));
00959
00960 if (ksv == KSSLCertificate::Ok) {
00961 if (certAndIPTheSame) {
00962 rc = 1;
00963 setMetaData("ssl_action", "accept");
00964 } else {
00965
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980 setMetaData("ssl_action", "accept");
00981 rc = 1;
00982
00983
00984 }
00985 } else {
00986 if (d->militantSSL) {
00987 return -1;
00988 }
00989
00990 if (cp == KSSLCertificateCache::Accept) {
00991 if (certAndIPTheSame) {
00992 rc = 1;
00993 setMetaData("ssl_action", "accept");
00994 } else {
00995 result = messageBox(WarningYesNo,
00996 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?"),
00997 i18n("Server Authentication"));
00998 if (result == KMessageBox::Yes) {
00999 rc = 1;
01000 setMetaData("ssl_action", "accept");
01001 d->cc->addHost(pc, ourHost);
01002 } else {
01003 rc = -1;
01004 setMetaData("ssl_action", "reject");
01005 }
01006 }
01007 } else if (cp == KSSLCertificateCache::Reject) {
01008 messageBox(Information, i18n("SSL certificate is being rejected as requested. You can disable this in the KDE Control Center."),
01009 i18n("Server Authentication"));
01010 rc = -1;
01011 setMetaData("ssl_action", "reject");
01012 } else {
01013 do {
01014 QString msg = i18n("The server certificate failed the "
01015 "authenticity test (%1).");
01016 result = messageBox(WarningYesNoCancel,
01017 msg.arg(ourHost),
01018 i18n("Server Authentication"),
01019 i18n("&Details"),
01020 i18n("Co&nnect"));
01021 if (result == KMessageBox::Yes) {
01022 if (!d->dcc) {
01023 d->dcc = new DCOPClient;
01024 d->dcc->attach();
01025 if (!d->dcc->isApplicationRegistered("kio_uiserver")) {
01026 KApplication::startServiceByDesktopPath("kio_uiserver.desktop",
01027 QStringList() );
01028 }
01029 }
01030 QByteArray data, ignore;
01031 QCString ignoretype;
01032 QDataStream arg(data, IO_WriteOnly);
01033 arg << theurl << mOutgoingMetaData;
01034 arg << metaData("window-id").toInt();
01035 d->dcc->call("kio_uiserver", "UIServer",
01036 "showSSLInfoDialog(QString,KIO::MetaData,int)",
01037 data, ignoretype, ignore);
01038 }
01039 } while (result == KMessageBox::Yes);
01040
01041 if (result == KMessageBox::No) {
01042 setMetaData("ssl_action", "accept");
01043 rc = 1;
01044 cp = KSSLCertificateCache::Accept;
01045 result = messageBox(WarningYesNo,
01046 i18n("Would you like to accept this "
01047 "certificate forever without "
01048 "being prompted?"),
01049 i18n("Server Authentication"),
01050 i18n("&Forever"),
01051 i18n("&Current Sessions Only"));
01052 permacache = (result == KMessageBox::Yes);
01053 d->cc->addCertificate(pc, cp, permacache);
01054 d->cc->addHost(pc, ourHost);
01055 } else {
01056 setMetaData("ssl_action", "reject");
01057 rc = -1;
01058 cp = KSSLCertificateCache::Prompt;
01059 d->cc->addCertificate(pc, cp, permacache);
01060 }
01061 }
01062 }
01063 }
01064
01065
01066 if (rc == -1) {
01067 return rc;
01068 }
01069
01070 if (metaData("ssl_activate_warnings") == "TRUE") {
01071
01072 if (!isChild && metaData("ssl_was_in_use") == "FALSE" &&
01073 d->kssl->settings()->warnOnEnter()) {
01074 int result;
01075 do {
01076 result = messageBox( i18n("You are about to "
01077 "enter secure mode. "
01078 "All transmissions "
01079 "will be encrypted "
01080 "unless otherwise "
01081 "noted.\nThis means "
01082 "that no third party "
01083 "will be able to "
01084 "easily observe your "
01085 "data in transit."),
01086 WarningYesNo,
01087 i18n("Security Information"),
01088 i18n("Display SSL "
01089 "&Information"),
01090 i18n("C&onnect"),
01091 "WarnOnEnterSSLMode" );
01092
01093 KConfig *config = new KConfig("kioslaverc");
01094 config->setGroup("Notification Messages");
01095
01096 if (!config->readBoolEntry("WarnOnEnterSSLMode", true)) {
01097 config->deleteEntry("WarnOnEnterSSLMode");
01098 config->sync();
01099 d->kssl->settings()->setWarnOnEnter(false);
01100 d->kssl->settings()->save();
01101 }
01102 delete config;
01103
01104 if ( result == KMessageBox::Yes )
01105 {
01106 if (!d->dcc) {
01107 d->dcc = new DCOPClient;
01108 d->dcc->attach();
01109 if (!d->dcc->isApplicationRegistered("kio_uiserver")) {
01110 KApplication::startServiceByDesktopPath("kio_uiserver.desktop",
01111 QStringList() );
01112 }
01113 }
01114 QByteArray data, ignore;
01115 QCString ignoretype;
01116 QDataStream arg(data, IO_WriteOnly);
01117 arg << theurl << mOutgoingMetaData;
01118 arg << metaData("window-id").toInt();
01119 d->dcc->call("kio_uiserver", "UIServer",
01120 "showSSLInfoDialog(QString,KIO::MetaData,int)",
01121 data, ignoretype, ignore);
01122 }
01123 } while (result != KMessageBox::No);
01124 }
01125
01126 }
01127
01128
01129 kdDebug(7029) << "SSL connection information follows:" << endl
01130 << "+-----------------------------------------------" << endl
01131 << "| Cipher: " << d->kssl->connectionInfo().getCipher() << endl
01132 << "| Description: " << d->kssl->connectionInfo().getCipherDescription() << endl
01133 << "| Version: " << d->kssl->connectionInfo().getCipherVersion() << endl
01134 << "| Strength: " << d->kssl->connectionInfo().getCipherUsedBits()
01135 << " of " << d->kssl->connectionInfo().getCipherBits()
01136 << " bits used." << endl
01137 << "| PEER:" << endl
01138 << "| Subject: " << d->kssl->peerInfo().getPeerCertificate().getSubject() << endl
01139 << "| Issuer: " << d->kssl->peerInfo().getPeerCertificate().getIssuer() << endl
01140 << "| Validation: " << (int)ksv << endl
01141 << "| Certificate matches IP: " << _IPmatchesCN << endl
01142 << "+-----------------------------------------------"
01143 << endl;
01144
01145
01146 return rc;
01147 }
01148
01149
01150 bool TCPSlaveBase::isConnectionValid()
01151 {
01152 if ( m_iSock == -1 )
01153 return false;
01154
01155 fd_set rdfs;
01156 FD_ZERO(&rdfs);
01157 FD_SET(m_iSock , &rdfs);
01158
01159 struct timeval tv;
01160 tv.tv_usec = 0;
01161 tv.tv_sec = 0;
01162 int retval;
01163 #ifdef Q_OS_UNIX
01164 do {
01165 retval = KSocks::self()->select(m_iSock+1, &rdfs, NULL, NULL, &tv);
01166 if (wasKilled())
01167 return false;
01168 } while ((retval == -1) && (errno == EAGAIN));
01169 #else
01170 retval = -1;
01171 #endif
01172
01173
01174
01175
01176
01177
01178 if (retval == -1)
01179 return false;
01180
01181 if (retval == 0)
01182 return true;
01183
01184
01185 char buffer[100];
01186 #ifdef Q_OS_UNIX
01187 do {
01188 retval = KSocks::self()->recv(m_iSock, buffer, 80, MSG_PEEK);
01189
01190 } while ((retval == -1) && (errno == EAGAIN));
01191 #else
01192 retval = -1;
01193 #endif
01194
01195
01196 if (retval <= 0)
01197 return false;
01198
01199 return true;
01200 }
01201
01202
01203 bool TCPSlaveBase::waitForResponse( int t )
01204 {
01205 fd_set rd;
01206 struct timeval timeout;
01207
01208 if ( (m_bIsSSL || d->usingTLS) && !d->useSSLTunneling && d->kssl )
01209 if (d->kssl->pending() > 0)
01210 return true;
01211
01212 FD_ZERO(&rd);
01213 FD_SET(m_iSock, &rd);
01214
01215 timeout.tv_usec = 0;
01216 timeout.tv_sec = t;
01217 time_t startTime;
01218
01219 int rc;
01220 int n = t;
01221
01222 reSelect:
01223 startTime = time(NULL);
01224 #ifdef Q_OS_UNIX
01225 rc = KSocks::self()->select(m_iSock+1, &rd, NULL, NULL, &timeout);
01226 #else
01227 rc = -1;
01228 #endif
01229 if (wasKilled())
01230 return false;
01231
01232 if (rc == -1)
01233 return false;
01234
01235 if (FD_ISSET(m_iSock, &rd))
01236 return true;
01237
01238
01239
01240
01241 int timeDone = time(NULL) - startTime;
01242 if (timeDone < n)
01243 {
01244 n -= timeDone;
01245 timeout.tv_sec = n;
01246 goto reSelect;
01247 }
01248
01249 return false;
01250 }
01251
01252 int TCPSlaveBase::connectResult()
01253 {
01254 return d->status;
01255 }
01256
01257 void TCPSlaveBase::setBlockConnection( bool b )
01258 {
01259 d->block = b;
01260 }
01261
01262 void TCPSlaveBase::setConnectTimeout( int t )
01263 {
01264 d->timeout = t;
01265 }
01266
01267 bool TCPSlaveBase::isSSLTunnelEnabled()
01268 {
01269 return d->useSSLTunneling;
01270 }
01271
01272 void TCPSlaveBase::setEnableSSLTunnel( bool enable )
01273 {
01274 d->useSSLTunneling = enable;
01275 }
01276
01277 void TCPSlaveBase::setRealHost( const QString& realHost )
01278 {
01279 d->realHost = realHost;
01280 }
01281
01282 bool TCPSlaveBase::doSSLHandShake( bool sendError )
01283 {
01284 kdDebug(7029) << "TCPSlaveBase::doSSLHandShake: " << endl;
01285 QString msgHost = d->host;
01286
01287 d->kssl->reInitialize();
01288
01289 if (hasMetaData("ssl_session_id")) {
01290 KSSLSession *s = KSSLSession::fromString(metaData("ssl_session_id"));
01291 if (s) {
01292 d->kssl->setSession(s);
01293 delete s;
01294 }
01295 }
01296 certificatePrompt();
01297
01298 if ( !d->realHost.isEmpty() )
01299 {
01300 msgHost = d->realHost;
01301 }
01302
01303 kdDebug(7029) << "Setting real hostname: " << msgHost << endl;
01304 d->kssl->setPeerHost(msgHost);
01305
01306 d->status = d->kssl->connect(m_iSock);
01307 if (d->status < 0)
01308 {
01309 closeDescriptor();
01310 if ( sendError )
01311 error( ERR_COULD_NOT_CONNECT, msgHost);
01312 return false;
01313 }
01314
01315 setMetaData("ssl_session_id", d->kssl->session()->toString());
01316 setMetaData("ssl_in_use", "TRUE");
01317
01318 if (!d->kssl->reusingSession()) {
01319 int rc = verifyCertificate();
01320 if ( rc != 1 ) {
01321 d->status = -1;
01322 closeDescriptor();
01323 if ( sendError )
01324 error( ERR_COULD_NOT_CONNECT, msgHost);
01325 return false;
01326 }
01327 }
01328
01329 d->needSSLHandShake = false;
01330
01331 d->savedMetaData = mOutgoingMetaData;
01332 return true;
01333 }
01334
01335
01336 bool TCPSlaveBase::userAborted() const
01337 {
01338 return d->userAborted;
01339 }
01340
01341 void TCPSlaveBase::virtual_hook( int id, void* data )
01342 { SlaveBase::virtual_hook( id, data ); }
01343