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