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