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