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