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