summaryrefslogtreecommitdiffstats
path: root/kresources/groupwise/soap/ksslsocket.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kresources/groupwise/soap/ksslsocket.cpp')
-rw-r--r--kresources/groupwise/soap/ksslsocket.cpp408
1 files changed, 408 insertions, 0 deletions
diff --git a/kresources/groupwise/soap/ksslsocket.cpp b/kresources/groupwise/soap/ksslsocket.cpp
new file mode 100644
index 000000000..4fdc3f5f6
--- /dev/null
+++ b/kresources/groupwise/soap/ksslsocket.cpp
@@ -0,0 +1,408 @@
+/*
+ ksslsocket.cpp - KDE SSL Socket
+
+ Copyright (c) 2004 by Jason Keirstead <jason@keirstead.org>
+
+ Kopete (c) 2002-2003 by the Kopete developers <kopete-devel@kde.org>
+
+ stolen from kopete, but this is a modified version.
+
+ *************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ *************************************************************************
+*/
+
+#include <qsocketnotifier.h>
+
+#include <dcopclient.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <kssl.h>
+#include <ksslinfodlg.h>
+#include <ksslpeerinfo.h>
+#include <ksslcertchain.h>
+#include <ksslcertificatecache.h>
+#include <kapplication.h>
+#include <kmessagebox.h>
+
+#include "ksslsocket.h"
+
+#include "stdlib.h"
+
+struct KSSLSocketPrivate
+{
+ mutable KSSL *kssl;
+ KSSLCertificateCache *cc;
+ DCOPClient *dcc;
+ QMap<QString,QString> metaData;
+ QSocketNotifier *socketNotifier;
+};
+
+KSSLSocket::KSSLSocket() : KExtendedSocket()
+{
+// kdDebug() << "KSSLSocket() " << (void*)this << endl;
+
+ d = new KSSLSocketPrivate;
+ d->kssl = 0L;
+ d->dcc = 0L;
+ d->cc = new KSSLCertificateCache;
+ d->cc->reload();
+
+ //No blocking
+ setBlockingMode(false);
+
+ //Connect internal slots
+ QObject::connect( this, SIGNAL(connectionSuccess()), this, SLOT(slotConnected()) );
+ QObject::connect( this, SIGNAL(closed(int)), this, SLOT(slotDisconnected()) );
+ QObject::connect( this, SIGNAL(connectionFailed(int)), this, SLOT(slotDisconnected()));
+}
+
+KSSLSocket::~KSSLSocket()
+{
+// kdDebug() << "KSSLSocket()::~KSSLSocket() " << (void*)this << endl;
+
+ //Close connection
+ closeNow();
+
+ if( d->kssl )
+ {
+ d->kssl->close();
+ delete d->kssl;
+ }
+
+ if ( d->dcc )
+ d->dcc->detach();
+ delete d->dcc;
+ delete d->cc;
+ delete d;
+}
+
+Q_LONG KSSLSocket::readBlock( char* data, Q_ULONG maxLen )
+{
+ return d->kssl->read( data, maxLen );
+}
+
+Q_LONG KSSLSocket::writeBlock( const char* data, Q_ULONG len )
+{
+// kdDebug() << "KSSLSocket::writeBlock() " << (void*)this << endl;
+// kdDebug() << " d->kssl: " << (void*)d->kssl << endl;
+ return d->kssl->write( data, len );
+}
+
+void KSSLSocket::slotConnected()
+{
+// kdDebug() << "KSSLSocket::slotConnected() " << (void*)this << endl;
+ if( KSSL::doesSSLWork() )
+ {
+// kdDebug(0) << k_funcinfo << "Trying SSL connection..." << endl;
+ if( !d->kssl )
+ {
+ d->kssl = new KSSL();
+ }
+ else
+ {
+ d->kssl->reInitialize();
+ }
+ d->kssl->setPeerHost(host());
+// kdDebug() << "SOCKET STATUS: " << socketStatus() << endl;
+ int rc = d->kssl->connect( sockfd );
+ if ( rc <= 0 ) {
+ kdError() << "Error connecting KSSL: " << rc << endl;
+ kdDebug() << "SYSTEM ERROR: " << systemError() << endl;
+ emit sslFailure();
+ closeNow();
+ } else {
+ readNotifier()->setEnabled(true);
+
+ if( verifyCertificate() != 1 )
+ {
+ closeNow();
+ }
+ }
+ }
+ else
+ {
+ kdError(0) << k_funcinfo << "SSL not functional!" << endl;
+
+ d->kssl = 0L;
+ emit sslFailure();
+ closeNow();
+ }
+}
+
+void KSSLSocket::slotDisconnected()
+{
+// kdDebug() << "KSSLSocket::slotDisconnected() " << (void*)this << endl;
+ if( readNotifier() )
+ readNotifier()->setEnabled(false);
+}
+
+void KSSLSocket::setMetaData( const QString &key, const QVariant &data )
+{
+ QVariant v = data;
+ d->metaData[key] = v.asString();
+}
+
+bool KSSLSocket::hasMetaData( const QString &key )
+{
+ return d->metaData.contains(key);
+}
+
+QString KSSLSocket::metaData( const QString &key )
+{
+ if( d->metaData.contains(key) )
+ return d->metaData[key];
+ return QString::null;
+}
+
+/*
+I basically copied the below from tcpKIO::SlaveBase.hpp, with some modificaions and formatting.
+
+ * Copyright (C) 2000 Alex Zepeda <zipzippy@sonic.net
+ * Copyright (C) 2001-2003 George Staikos <staikos@kde.org>
+ * Copyright (C) 2001 Dawit Alemayehu <adawit@kde.org>
+*/
+
+int KSSLSocket::messageBox( KIO::SlaveBase::MessageBoxType type, const QString &text, const QString &caption,
+ const QString &buttonYes, const QString &buttonNo )
+{
+ kdDebug(0) << "messageBox " << type << " " << text << " - " << caption << buttonYes << buttonNo << endl;
+ QByteArray data, result;
+ QCString returnType;
+ QDataStream arg(data, IO_WriteOnly);
+ arg << (int)1 << (int)type << text << caption << buttonYes << buttonNo;
+
+ if ( ! d->dcc ){
+ d->dcc = new DCOPClient();
+ d->dcc->attach();
+ }
+ if (!d->dcc->isApplicationRegistered("kio_uiserver"))
+ {
+ KApplication::startServiceByDesktopPath("kio_uiserver.desktop",QStringList());
+ }
+
+ d->dcc->call("kio_uiserver", "UIServer",
+ "messageBox(int,int,QString,QString,QString,QString)", data, returnType, result);
+
+ if( returnType == "int" )
+ {
+ int res;
+ QDataStream r(result, IO_ReadOnly);
+ r >> res;
+ return res;
+ }
+ else
+ return 0; // communication failure
+}
+
+
+// Returns 0 for failed verification, -1 for rejected cert and 1 for ok
+int KSSLSocket::verifyCertificate()
+{
+ int rc = 0;
+ bool permacache = false;
+ bool _IPmatchesCN = false;
+ int result;
+ bool doAddHost = false;
+ QString ourHost = host();
+ QString ourIp = peerAddress()->pretty();
+
+ QString theurl = "https://" + ourHost + ":" + port();
+
+ if (!d->cc)
+ d->cc = new KSSLCertificateCache;
+
+ KSSLCertificate& pc = d->kssl->peerInfo().getPeerCertificate();
+
+ KSSLCertificate::KSSLValidationList ksvl = pc.validateVerbose(KSSLCertificate::SSLServer);
+
+ if ( ksvl.count() == 1 && ksvl.first() == KSSLCertificate::Unknown ) {
+ kdDebug() << "Unknown validation error" << endl;
+ return 0;
+ }
+
+ _IPmatchesCN = d->kssl->peerInfo().certMatchesAddress();
+
+ if (!_IPmatchesCN && (metaData("ssl_militant") == "TRUE") )
+ {
+ ksvl << KSSLCertificate::InvalidHost;
+ }
+
+ KSSLCertificate::KSSLValidation ksv = KSSLCertificate::Ok;
+ if (!ksvl.isEmpty())
+ ksv = ksvl.first();
+
+ /* Setting the various bits of meta-info that will be needed. */
+ setMetaData("ssl_cipher", d->kssl->connectionInfo().getCipher());
+ setMetaData("ssl_cipher_desc", d->kssl->connectionInfo().getCipherDescription());
+ setMetaData("ssl_cipher_version", d->kssl->connectionInfo().getCipherVersion());
+ setMetaData("ssl_cipher_used_bits", QString::number(d->kssl->connectionInfo().getCipherUsedBits()));
+ setMetaData("ssl_cipher_bits", QString::number(d->kssl->connectionInfo().getCipherBits()));
+ setMetaData("ssl_peer_ip", ourIp );
+
+ QString errorStr;
+ for(KSSLCertificate::KSSLValidationList::ConstIterator it = ksvl.begin();
+ it != ksvl.end(); ++it)
+ {
+ errorStr += QString::number(*it)+":";
+ }
+
+ setMetaData("ssl_cert_errors", errorStr);
+ setMetaData("ssl_peer_certificate", pc.toString());
+
+ if (pc.chain().isValid() && pc.chain().depth() > 1)
+ {
+ QString theChain;
+ QPtrList<KSSLCertificate> chain = pc.chain().getChain();
+ for (KSSLCertificate *c = chain.first(); c; c = chain.next())
+ {
+ theChain += c->toString();
+ theChain += "\n";
+ }
+ setMetaData("ssl_peer_chain", theChain);
+ }
+ else
+ {
+ setMetaData("ssl_peer_chain", "");
+ }
+
+ setMetaData("ssl_cert_state", QString::number(ksv));
+
+ if (ksv == KSSLCertificate::Ok)
+ {
+ rc = 1;
+ setMetaData("ssl_action", "accept");
+ }
+
+ // Since we're the parent, we need to teach the child.
+ setMetaData("ssl_parent_ip", ourIp );
+ setMetaData("ssl_parent_cert", pc.toString());
+
+ // - Read from cache and see if there is a policy for this
+ KSSLCertificateCache::KSSLCertificatePolicy cp = d->cc->getPolicyByCertificate(pc);
+ // - validation code
+ if (ksv != KSSLCertificate::Ok)
+ {
+ if( cp == KSSLCertificateCache::Unknown || cp == KSSLCertificateCache::Ambiguous)
+ {
+ cp = KSSLCertificateCache::Prompt;
+ }
+ else
+ {
+ // A policy was already set so let's honor that.
+ permacache = d->cc->isPermanent(pc);
+ }
+
+ if (!_IPmatchesCN && (metaData("ssl_militant") == "TRUE")
+ && cp == KSSLCertificateCache::Accept)
+ {
+ cp = KSSLCertificateCache::Prompt;
+ }
+
+ // Precondition: cp is one of Reject, Accept or Prompt
+ switch (cp)
+ {
+ case KSSLCertificateCache::Accept:
+ rc = 1;
+ break;
+
+ case KSSLCertificateCache::Reject:
+ rc = -1;
+ break;
+
+ case KSSLCertificateCache::Prompt:
+ {
+ do
+ {
+ if (ksv == KSSLCertificate::InvalidHost)
+ {
+ QString msg = i18n("The IP address of the host %1 "
+ "does not match the one the "
+ "certificate was issued to.");
+ result = messageBox( KIO::SlaveBase::WarningYesNoCancel,
+ msg.arg(ourHost),
+ i18n("Server Authentication"),
+ i18n("&Details"),
+ KStdGuiItem::cont().text() );
+ }
+ else
+ {
+ QString msg = i18n("The server certificate failed the "
+ "authenticity test (%1).");
+ result = messageBox( KIO::SlaveBase::WarningYesNoCancel,
+ msg.arg(ourHost),
+ i18n("Server Authentication"),
+ i18n("&Details"),
+ KStdGuiItem::cont().text() );
+ }
+ }
+ while (result == KMessageBox::Yes);
+
+ if (result == KMessageBox::No)
+ {
+ rc = 1;
+ cp = KSSLCertificateCache::Accept;
+ doAddHost = true;
+ result = messageBox( KIO::SlaveBase::WarningYesNo,
+ i18n("Would you like to accept this "
+ "certificate forever without "
+ "being prompted?"),
+ i18n("Server Authentication"),
+ i18n("&Forever"),
+ i18n("&Current Sessions Only"));
+ if (result == KMessageBox::Yes)
+ permacache = true;
+ else
+ permacache = false;
+ }
+ else
+ {
+ rc = -1;
+ cp = KSSLCertificateCache::Prompt;
+ }
+
+ break;
+ }
+ default:
+ kdDebug(0) << "SSL error in cert code."
+ << endl;
+ break;
+ }
+ }
+
+ // - cache the results
+ d->cc->addCertificate(pc, cp, permacache);
+ if (doAddHost)
+ d->cc->addHost(pc, ourHost);
+
+
+ if (rc == -1)
+ return rc;
+
+ if ( getenv("DEBUG_GW_RESOURCE") ) {
+ kdDebug(0) << "SSL connection information follows:" << endl
+ << "+-----------------------------------------------" << endl
+ << "| Cipher: " << d->kssl->connectionInfo().getCipher() << endl
+ << "| Description: " << d->kssl->connectionInfo().getCipherDescription() << endl
+ << "| Version: " << d->kssl->connectionInfo().getCipherVersion() << endl
+ << "| Strength: " << d->kssl->connectionInfo().getCipherUsedBits()
+ << " of " << d->kssl->connectionInfo().getCipherBits()
+ << " bits used." << endl
+ << "| PEER:" << endl
+ << "| Subject: " << d->kssl->peerInfo().getPeerCertificate().getSubject() << endl
+ << "| Issuer: " << d->kssl->peerInfo().getPeerCertificate().getIssuer() << endl
+ << "| Validation: " << (int)ksv << endl
+ << "| Certificate matches IP: " << _IPmatchesCN << endl
+ << "+-----------------------------------------------"
+ << endl;
+ }
+ return rc;
+}
+
+
+#include "ksslsocket.moc"