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 d->cc->addHost(pc, ourHost);
00984 result = messageBox( WarningYesNo,
00985 i18n("Would you like to accept this "
00986 "certificate forever without "
00987 "being prompted?"),
00988 i18n("Server Authentication"),
00989 i18n("&Forever"),
00990 i18n("&Current Sessions Only"));
00991 if (result == KMessageBox::Yes)
00992 permacache = true;
00993 else
00994 permacache = false;
00995 } else {
00996 setMetaData("ssl_action", "reject");
00997 rc = -1;
00998 cp = KSSLCertificateCache::Prompt;
00999 }
01000 d->cc->addCertificate(pc, cp, permacache);
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