aboutsummaryrefslogtreecommitdiffstats
path: root/src/security
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/security/defaultAuthenticator.cpp98
-rw-r--r--src/security/sasl/SASLContext.cpp189
-rw-r--r--src/security/sasl/SASLMechanismFactory.cpp131
-rw-r--r--src/security/sasl/SASLSession.cpp179
-rw-r--r--src/security/sasl/SASLSocket.cpp167
-rw-r--r--src/security/sasl/builtinSASLMechanism.cpp182
-rw-r--r--src/security/sasl/defaultSASLAuthenticator.cpp139
7 files changed, 1085 insertions, 0 deletions
diff --git a/src/security/defaultAuthenticator.cpp b/src/security/defaultAuthenticator.cpp
new file mode 100644
index 00000000..913eb07a
--- /dev/null
+++ b/src/security/defaultAuthenticator.cpp
@@ -0,0 +1,98 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002-2005 Vincent Richard <[email protected]>
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "vmime/security/defaultAuthenticator.hpp"
+
+#include "vmime/net/service.hpp"
+
+#include "vmime/platformDependant.hpp"
+
+
+namespace vmime {
+namespace security {
+
+
+defaultAuthenticator::defaultAuthenticator()
+{
+}
+
+
+defaultAuthenticator::~defaultAuthenticator()
+{
+}
+
+
+const string defaultAuthenticator::getUsername() const
+{
+ const string& prefix = m_service->getInfos().getPropertyPrefix();
+ const propertySet& props = m_service->getSession()->getProperties();
+
+ if (props.hasProperty(prefix + net::serviceInfos::property::AUTH_USERNAME.getName()))
+ return props[prefix + net::serviceInfos::property::AUTH_USERNAME.getName()];
+
+ throw exceptions::no_auth_information();
+}
+
+
+const string defaultAuthenticator::getPassword() const
+{
+ const string& prefix = m_service->getInfos().getPropertyPrefix();
+ const propertySet& props = m_service->getSession()->getProperties();
+
+ if (props.hasProperty(prefix + net::serviceInfos::property::AUTH_PASSWORD.getName()))
+ return props[prefix + net::serviceInfos::property::AUTH_PASSWORD.getName()];
+
+ throw exceptions::no_auth_information();
+}
+
+
+const string defaultAuthenticator::getHostname() const
+{
+ return platformDependant::getHandler()->getHostName();
+}
+
+
+const string defaultAuthenticator::getAnonymousToken() const
+{
+ return "anonymous@" + platformDependant::getHandler()->getHostName();
+}
+
+
+const string defaultAuthenticator::getServiceName() const
+{
+ // Information cannot be provided
+ throw exceptions::no_auth_information();
+}
+
+
+void defaultAuthenticator::setService(ref <net::service> serv)
+{
+ m_service = serv;
+}
+
+
+weak_ref <net::service> defaultAuthenticator::getService() const
+{
+ return m_service;
+}
+
+
+} // security
+} // vmime
+
diff --git a/src/security/sasl/SASLContext.cpp b/src/security/sasl/SASLContext.cpp
new file mode 100644
index 00000000..dd8cbd93
--- /dev/null
+++ b/src/security/sasl/SASLContext.cpp
@@ -0,0 +1,189 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002-2005 Vincent Richard <[email protected]>
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include <sstream>
+
+#include <gsasl.h>
+
+#include "vmime/security/sasl/SASLContext.hpp"
+#include "vmime/security/sasl/SASLMechanism.hpp"
+
+#include "vmime/base.hpp"
+#include "vmime/encoderFactory.hpp"
+
+#include "vmime/utility/stream.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace sasl {
+
+
+SASLContext::SASLContext()
+{
+ if (gsasl_init(&m_gsaslContext) != GSASL_OK)
+ throw std::bad_alloc();
+}
+
+
+SASLContext::~SASLContext()
+{
+ gsasl_done(m_gsaslContext);
+}
+
+
+ref <SASLSession> SASLContext::createSession
+ (const string& serviceName,
+ ref <authenticator> auth, ref <SASLMechanism> mech)
+{
+ return vmime::create <SASLSession>
+ (serviceName, thisRef().dynamicCast <SASLContext>(), auth, mech);
+}
+
+
+ref <SASLMechanism> SASLContext::createMechanism(const string& name)
+{
+ return SASLMechanismFactory::getInstance()->create
+ (thisRef().dynamicCast <SASLContext>(), name);
+}
+
+
+ref <SASLMechanism> SASLContext::suggestMechanism
+ (const std::vector <ref <SASLMechanism> >& mechs)
+{
+ if (mechs.empty())
+ return 0;
+
+ std::ostringstream oss;
+
+ for (unsigned int i = 0 ; i < mechs.size() ; ++i)
+ oss << mechs[i]->getName() << " ";
+
+ const string mechList = oss.str();
+ const char* suggested = gsasl_client_suggest_mechanism
+ (m_gsaslContext, mechList.c_str());
+
+ if (suggested)
+ {
+ for (unsigned int i = 0 ; i < mechs.size() ; ++i)
+ {
+ if (mechs[i]->getName() == suggested)
+ return mechs[i];
+ }
+ }
+
+ return 0;
+}
+
+
+void SASLContext::decodeB64(const string& input, byte** output, int* outputLen)
+{
+ string res;
+
+ utility::inputStreamStringAdapter is(input);
+ utility::outputStreamStringAdapter os(res);
+
+ ref <encoder> dec = encoderFactory::getInstance()->create("base64");
+
+ dec->decode(is, os);
+
+ byte* out = new byte[res.length()];
+
+ std::copy(res.begin(), res.end(), out);
+
+ *output = out;
+ *outputLen = res.length();
+}
+
+
+const string SASLContext::encodeB64(const byte* input, const int inputLen)
+{
+ string res;
+
+ utility::inputStreamByteBufferAdapter is(input, inputLen);
+ utility::outputStreamStringAdapter os(res);
+
+ ref <encoder> enc = encoderFactory::getInstance()->create("base64");
+
+ enc->encode(is, os);
+
+ return res;
+}
+
+
+const string SASLContext::getErrorMessage(const string& fname, const int code)
+{
+ string msg = fname + "() returned ";
+
+#define ERROR(x) \
+ case x: msg += #x; break;
+
+ switch (code)
+ {
+ ERROR(GSASL_NEEDS_MORE)
+ ERROR(GSASL_UNKNOWN_MECHANISM)
+ ERROR(GSASL_MECHANISM_CALLED_TOO_MANY_TIMES)
+ ERROR(GSASL_MALLOC_ERROR)
+ ERROR(GSASL_BASE64_ERROR)
+ ERROR(GSASL_CRYPTO_ERROR)
+ ERROR(GSASL_SASLPREP_ERROR)
+ ERROR(GSASL_MECHANISM_PARSE_ERROR)
+ ERROR(GSASL_AUTHENTICATION_ERROR)
+ ERROR(GSASL_INTEGRITY_ERROR)
+ ERROR(GSASL_NO_CLIENT_CODE)
+ ERROR(GSASL_NO_SERVER_CODE)
+ ERROR(GSASL_NO_CALLBACK)
+ ERROR(GSASL_NO_ANONYMOUS_TOKEN)
+ ERROR(GSASL_NO_AUTHID)
+ ERROR(GSASL_NO_AUTHZID)
+ ERROR(GSASL_NO_PASSWORD)
+ ERROR(GSASL_NO_PASSCODE)
+ ERROR(GSASL_NO_PIN)
+ ERROR(GSASL_NO_SERVICE)
+ ERROR(GSASL_NO_HOSTNAME)
+ ERROR(GSASL_GSSAPI_RELEASE_BUFFER_ERROR)
+ ERROR(GSASL_GSSAPI_IMPORT_NAME_ERROR)
+ ERROR(GSASL_GSSAPI_INIT_SEC_CONTEXT_ERROR)
+ ERROR(GSASL_GSSAPI_ACCEPT_SEC_CONTEXT_ERROR)
+ ERROR(GSASL_GSSAPI_UNWRAP_ERROR)
+ ERROR(GSASL_GSSAPI_WRAP_ERROR)
+ ERROR(GSASL_GSSAPI_ACQUIRE_CRED_ERROR)
+ ERROR(GSASL_GSSAPI_DISPLAY_NAME_ERROR)
+ ERROR(GSASL_GSSAPI_UNSUPPORTED_PROTECTION_ERROR)
+ ERROR(GSASL_KERBEROS_V5_INIT_ERROR)
+ ERROR(GSASL_KERBEROS_V5_INTERNAL_ERROR)
+ ERROR(GSASL_SECURID_SERVER_NEED_ADDITIONAL_PASSCODE)
+ ERROR(GSASL_SECURID_SERVER_NEED_NEW_PIN)
+
+ default:
+
+ msg += "unknown error";
+ break;
+ }
+
+#undef ERROR
+
+ return msg;
+}
+
+
+} // sasl
+} // security
+} // vmime
+
diff --git a/src/security/sasl/SASLMechanismFactory.cpp b/src/security/sasl/SASLMechanismFactory.cpp
new file mode 100644
index 00000000..fda4448c
--- /dev/null
+++ b/src/security/sasl/SASLMechanismFactory.cpp
@@ -0,0 +1,131 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002-2005 Vincent Richard <[email protected]>
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include <stdexcept>
+#include <new>
+
+#include <gsasl.h>
+
+#include "vmime/security/sasl/SASLMechanismFactory.hpp"
+#include "vmime/security/sasl/builtinSASLMechanism.hpp"
+#include "vmime/security/sasl/SASLContext.hpp"
+
+#include "vmime/utility/stringUtils.hpp"
+
+#include "vmime/base.hpp"
+#include "vmime/exception.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace sasl {
+
+
+SASLMechanismFactory::SASLMechanismFactory()
+{
+ if (gsasl_init(&m_gsaslContext) != GSASL_OK)
+ throw std::bad_alloc();
+}
+
+
+SASLMechanismFactory::~SASLMechanismFactory()
+{
+ gsasl_done(m_gsaslContext);
+}
+
+
+// static
+SASLMechanismFactory* SASLMechanismFactory::getInstance()
+{
+ static SASLMechanismFactory instance;
+ return &instance;
+}
+
+
+ref <SASLMechanism> SASLMechanismFactory::create
+ (ref <SASLContext> ctx, const string& name_)
+{
+ const string name(utility::stringUtils::toUpper(name_));
+
+ // Check for built-in mechanisms
+ if (isMechanismSupported(name))
+ {
+ return vmime::create <builtinSASLMechanism>(ctx, name);
+ }
+ // Check for registered mechanisms
+ else
+ {
+ MapType::iterator it = m_mechs.find(name);
+
+ if (it != m_mechs.end())
+ return (*it).second->create(ctx, name);
+ }
+
+ throw exceptions::no_such_mechanism(name);
+ return 0;
+}
+
+
+const std::vector <string> SASLMechanismFactory::getSupportedMechanisms() const
+{
+ std::vector <string> list;
+
+ // Registered mechanisms
+ for (MapType::const_iterator it = m_mechs.begin() ;
+ it != m_mechs.end() ; ++it)
+ {
+ list.push_back((*it).first);
+ }
+
+ // Built-in mechanisms
+ char* out = 0;
+
+ if (gsasl_client_mechlist(m_gsaslContext, &out) == GSASL_OK)
+ {
+ // 'out' contains SASL mechanism names, separated by spaces
+ for (char *start = out, *p = out ; ; ++p)
+ {
+ if (*p == ' ' || !*p)
+ {
+ list.push_back(string(start, p));
+ start = p + 1;
+
+ // End of string
+ if (!*p) break;
+ }
+ }
+
+ free(out);
+ }
+
+ return list;
+}
+
+
+const bool SASLMechanismFactory::isMechanismSupported(const string& name) const
+{
+ return (gsasl_client_support_p(m_gsaslContext, name.c_str()) != 0 ||
+ m_mechs.find(name) != m_mechs.end());
+}
+
+
+} // sasl
+} // security
+} // vmime
+
diff --git a/src/security/sasl/SASLSession.cpp b/src/security/sasl/SASLSession.cpp
new file mode 100644
index 00000000..f4d8bf13
--- /dev/null
+++ b/src/security/sasl/SASLSession.cpp
@@ -0,0 +1,179 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002-2005 Vincent Richard <[email protected]>
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include <sstream>
+
+#include <gsasl.h>
+
+#include "vmime/security/sasl/SASLSession.hpp"
+
+#include "vmime/security/sasl/SASLContext.hpp"
+#include "vmime/security/sasl/SASLSocket.hpp"
+#include "vmime/security/sasl/SASLAuthenticator.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace sasl {
+
+
+SASLSession::SASLSession(const string& serviceName, ref <SASLContext> ctx,
+ ref <authenticator> auth, ref <SASLMechanism> mech)
+ : m_serviceName(serviceName), m_context(ctx), m_auth(auth),
+ m_mech(mech), m_gsaslContext(0), m_gsaslSession(0)
+{
+ if (gsasl_init(&m_gsaslContext) != GSASL_OK)
+ throw std::bad_alloc();
+
+ gsasl_client_start(m_gsaslContext, mech->getName().c_str(), &m_gsaslSession);
+
+ gsasl_callback_set(m_gsaslContext, gsaslCallback);
+ gsasl_callback_hook_set(m_gsaslContext, this);
+}
+
+
+SASLSession::~SASLSession()
+{
+ gsasl_finish(m_gsaslSession);
+ m_gsaslSession = 0;
+
+ gsasl_done(m_gsaslContext);
+ m_gsaslContext = 0;
+}
+
+
+void SASLSession::init()
+{
+ ref <SASLAuthenticator> saslAuth = m_auth.dynamicCast <SASLAuthenticator>();
+
+ if (saslAuth)
+ {
+ saslAuth->setSASLMechanism(m_mech);
+ saslAuth->setSASLSession(thisRef().dynamicCast <SASLSession>());
+ }
+}
+
+
+ref <authenticator> SASLSession::getAuthenticator()
+{
+ return m_auth;
+}
+
+
+ref <SASLMechanism> SASLSession::getMechanism()
+{
+ return m_mech;
+}
+
+
+ref <SASLContext> SASLSession::getContext()
+{
+ return m_context;
+}
+
+
+const bool SASLSession::evaluateChallenge
+ (const byte* challenge, const int challengeLen,
+ byte** response, int* responseLen)
+{
+ return m_mech->step(thisRef().dynamicCast <SASLSession>(),
+ challenge, challengeLen, response, responseLen);
+}
+
+
+ref <net::socket> SASLSession::getSecuredSocket(ref <net::socket> sok)
+{
+ return vmime::create <SASLSocket>(thisRef().dynamicCast <SASLSession>(), sok);
+}
+
+
+const string SASLSession::getServiceName() const
+{
+ return m_serviceName;
+}
+
+
+// static
+int SASLSession::gsaslCallback
+ (Gsasl* ctx, Gsasl_session* sctx, Gsasl_property prop)
+{
+ SASLSession* sess = reinterpret_cast <SASLSession*>(gsasl_callback_hook_get(ctx));
+ if (!sess) return GSASL_AUTHENTICATION_ERROR;
+
+ ref <authenticator> auth = sess->getAuthenticator();
+
+ try
+ {
+ string res;
+
+ switch (prop)
+ {
+ case GSASL_AUTHID:
+
+ res = auth->getUsername();
+ break;
+
+ case GSASL_PASSWORD:
+
+ res = auth->getPassword();
+ break;
+
+ case GSASL_ANONYMOUS_TOKEN:
+
+ res = auth->getAnonymousToken();
+ break;
+
+ case GSASL_HOSTNAME:
+
+ res = auth->getHostname();
+ break;
+
+ case GSASL_SERVICE:
+
+ res = auth->getServiceName();
+ break;
+
+ case GSASL_AUTHZID:
+ case GSASL_GSSAPI_DISPLAY_NAME:
+ case GSASL_PASSCODE:
+ case GSASL_SUGGESTED_PIN:
+ case GSASL_PIN:
+ case GSASL_REALM:
+
+ default:
+
+ return GSASL_NO_CALLBACK;
+ }
+
+ gsasl_property_set(sctx, prop, res.c_str());
+
+ return GSASL_OK;
+ }
+ //catch (exceptions::no_auth_information&)
+ catch (...)
+ {
+ return GSASL_NO_CALLBACK;
+ }
+}
+
+
+} // sasl
+} // security
+} // vmime
+
diff --git a/src/security/sasl/SASLSocket.cpp b/src/security/sasl/SASLSocket.cpp
new file mode 100644
index 00000000..321f90f7
--- /dev/null
+++ b/src/security/sasl/SASLSocket.cpp
@@ -0,0 +1,167 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002-2005 Vincent Richard <[email protected]>
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "vmime/security/sasl/SASLSocket.hpp"
+#include "vmime/security/sasl/SASLSession.hpp"
+
+#include "vmime/exception.hpp"
+
+#include <algorithm>
+
+#include <gsasl.h>
+
+
+namespace vmime {
+namespace security {
+namespace sasl {
+
+
+
+SASLSocket::SASLSocket(ref <SASLSession> sess, ref <net::socket> wrapped)
+ : m_session(sess), m_wrapped(wrapped),
+ m_pendingBuffer(0), m_pendingPos(0), m_pendingLen(0)
+{
+}
+
+
+SASLSocket::~SASLSocket()
+{
+ if (m_pendingBuffer)
+ delete [] m_pendingBuffer;
+}
+
+
+void SASLSocket::connect(const string& address, const port_t port)
+{
+ m_wrapped->connect(address, port);
+}
+
+
+void SASLSocket::disconnect()
+{
+ m_wrapped->disconnect();
+}
+
+
+const bool SASLSocket::isConnected() const
+{
+ return m_wrapped->isConnected();
+}
+
+
+void SASLSocket::receive(string& buffer)
+{
+ const int n = receiveRaw(m_recvBuffer, sizeof(m_recvBuffer));
+
+ buffer = string(m_recvBuffer, n);
+}
+
+
+const int SASLSocket::receiveRaw(char* buffer, const int count)
+{
+ if (m_pendingLen != 0)
+ {
+ const int copyLen =
+ (count >= m_pendingLen ? m_pendingLen : count);
+
+ std::copy(m_pendingBuffer + m_pendingPos,
+ m_pendingBuffer + m_pendingPos + copyLen,
+ buffer);
+
+ m_pendingLen -= copyLen;
+ m_pendingPos += copyLen;
+
+ if (m_pendingLen == 0)
+ {
+ delete [] m_pendingBuffer;
+
+ m_pendingBuffer = 0;
+ m_pendingPos = 0;
+ m_pendingLen = 0;
+ }
+
+ return copyLen;
+ }
+
+ const int n = m_wrapped->receiveRaw(buffer, count);
+
+ byte* output = 0;
+ int outputLen = 0;
+
+ m_session->getMechanism()->decode
+ (m_session, reinterpret_cast <const byte*>(buffer), n,
+ &output, &outputLen);
+
+ // If we can not copy all decoded data into the output buffer, put
+ // remaining data into a pending buffer for next calls to receive()
+ if (outputLen > count)
+ {
+ std::copy(output, output + count, buffer);
+
+ m_pendingBuffer = output;
+ m_pendingLen = outputLen;
+ m_pendingPos = count;
+
+ return count;
+ }
+ else
+ {
+ std::copy(output, output + outputLen, buffer);
+
+ delete [] output;
+
+ return outputLen;
+ }
+}
+
+
+void SASLSocket::send(const string& buffer)
+{
+ sendRaw(buffer.data(), buffer.length());
+}
+
+
+void SASLSocket::sendRaw(const char* buffer, const int count)
+{
+ byte* output = 0;
+ int outputLen = 0;
+
+ m_session->getMechanism()->encode
+ (m_session, reinterpret_cast <const byte*>(buffer), count,
+ &output, &outputLen);
+
+ try
+ {
+ m_wrapped->sendRaw
+ (reinterpret_cast <const char*>(output), outputLen);
+ }
+ catch (...)
+ {
+ delete [] output;
+ throw;
+ }
+
+ delete [] output;
+}
+
+
+} // sasl
+} // security
+} // vmime
+
diff --git a/src/security/sasl/builtinSASLMechanism.cpp b/src/security/sasl/builtinSASLMechanism.cpp
new file mode 100644
index 00000000..89704eeb
--- /dev/null
+++ b/src/security/sasl/builtinSASLMechanism.cpp
@@ -0,0 +1,182 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002-2005 Vincent Richard <[email protected]>
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include <gsasl.h>
+
+#include "vmime/security/sasl/builtinSASLMechanism.hpp"
+
+#include "vmime/security/sasl/SASLContext.hpp"
+#include "vmime/security/sasl/SASLSession.hpp"
+
+#include "vmime/exception.hpp"
+
+#include <stdexcept>
+#include <new>
+
+
+namespace vmime {
+namespace security {
+namespace sasl {
+
+
+builtinSASLMechanism::builtinSASLMechanism(ref <SASLContext> ctx, const string& name)
+ : m_context(ctx), m_name(name), m_complete(false)
+{
+}
+
+
+builtinSASLMechanism::~builtinSASLMechanism()
+{
+}
+
+
+const string builtinSASLMechanism::getName() const
+{
+ return m_name;
+}
+
+
+const bool builtinSASLMechanism::step
+ (ref <SASLSession> sess, const byte* challenge, const int challengeLen,
+ byte** response, int* responseLen)
+{
+ char* output = 0;
+ size_t outputLen = 0;
+
+ const int result = gsasl_step(sess->m_gsaslSession,
+ reinterpret_cast <const char*>(challenge), challengeLen,
+ &output, &outputLen);
+
+ if (result == GSASL_OK || result == GSASL_NEEDS_MORE)
+ {
+ byte* res = new byte[outputLen];
+
+ for (size_t i = 0 ; i < outputLen ; ++i)
+ res[i] = output[i];
+
+ *response = res;
+ *responseLen = outputLen;
+
+ free(output);
+ }
+ else
+ {
+ *response = 0;
+ *responseLen = 0;
+ }
+
+ if (result == GSASL_OK)
+ {
+ // Authentication process completed
+ m_complete = true;
+ return true;
+ }
+ else if (result == GSASL_NEEDS_MORE)
+ {
+ // Continue authentication process
+ return false;
+ }
+ else if (result == GSASL_MALLOC_ERROR)
+ {
+ throw std::bad_alloc();
+ }
+ else
+ {
+ throw exceptions::sasl_exception("Error when processing challenge: "
+ + SASLContext::getErrorMessage("gsasl_step", result));
+ }
+}
+
+
+const bool builtinSASLMechanism::isComplete() const
+{
+ return m_complete;
+}
+
+
+void builtinSASLMechanism::encode
+ (ref <SASLSession> sess, const byte* input, const int inputLen,
+ byte** output, int* outputLen)
+{
+ char* coutput = 0;
+ size_t coutputLen = 0;
+
+ if (gsasl_encode(sess->m_gsaslSession,
+ reinterpret_cast <const char*>(input), inputLen,
+ &coutput, &coutputLen) != GSASL_OK)
+ {
+ throw exceptions::sasl_exception("Encoding error.");
+ }
+
+ try
+ {
+ byte* res = new byte[coutputLen];
+
+ std::copy(coutput, coutput + coutputLen, res);
+
+ *output = res;
+ *outputLen = static_cast <int>(coutputLen);
+ }
+ catch (...)
+ {
+ free(coutput);
+ throw;
+ }
+
+ free(coutput);
+}
+
+
+void builtinSASLMechanism::decode
+ (ref <SASLSession> sess, const byte* input, const int inputLen,
+ byte** output, int* outputLen)
+{
+ char* coutput = 0;
+ size_t coutputLen = 0;
+
+ try
+ {
+ if (gsasl_decode(sess->m_gsaslSession,
+ reinterpret_cast <const char*>(input), inputLen,
+ &coutput, &coutputLen) != GSASL_OK)
+ {
+ throw exceptions::sasl_exception("Decoding error.");
+ }
+
+ byte* res = new byte[coutputLen];
+
+ std::copy(coutput, coutput + coutputLen, res);
+
+ *output = res;
+ *outputLen = static_cast <int>(coutputLen);
+ }
+ catch (...)
+ {
+ free(coutput);
+ throw;
+ }
+
+ free(coutput);
+}
+
+
+} // sasl
+} // security
+} // vmime
+
diff --git a/src/security/sasl/defaultSASLAuthenticator.cpp b/src/security/sasl/defaultSASLAuthenticator.cpp
new file mode 100644
index 00000000..d396e069
--- /dev/null
+++ b/src/security/sasl/defaultSASLAuthenticator.cpp
@@ -0,0 +1,139 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002-2005 Vincent Richard <[email protected]>
+//
+// 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.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+
+#include "vmime/security/sasl/defaultSASLAuthenticator.hpp"
+
+#include "vmime/security/sasl/SASLMechanism.hpp"
+#include "vmime/security/sasl/SASLSession.hpp"
+
+#include "vmime/net/service.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace sasl {
+
+
+defaultSASLAuthenticator::defaultSASLAuthenticator()
+{
+}
+
+
+defaultSASLAuthenticator::~defaultSASLAuthenticator()
+{
+}
+
+
+const std::vector <ref <SASLMechanism> >
+ defaultSASLAuthenticator::getAcceptableMechanisms
+ (const std::vector <ref <SASLMechanism> >& available,
+ ref <SASLMechanism> suggested) const
+{
+ if (suggested)
+ {
+ std::vector <ref <SASLMechanism> > res;
+
+ res.push_back(suggested);
+
+ for (unsigned int i = 0 ; i < available.size() ; ++i)
+ {
+ if (available[i]->getName() != suggested->getName())
+ res.push_back(available[i]);
+ }
+
+ return res;
+ }
+ else
+ {
+ return available;
+ }
+}
+
+
+const string defaultSASLAuthenticator::getUsername() const
+{
+ return m_default.getUsername();
+}
+
+
+const string defaultSASLAuthenticator::getPassword() const
+{
+ return m_default.getPassword();
+}
+
+
+const string defaultSASLAuthenticator::getHostname() const
+{
+ return m_default.getHostname();
+}
+
+
+const string defaultSASLAuthenticator::getAnonymousToken() const
+{
+ return m_default.getAnonymousToken();
+}
+
+
+const string defaultSASLAuthenticator::getServiceName() const
+{
+ return m_saslSession->getServiceName();
+}
+
+
+void defaultSASLAuthenticator::setService(ref <net::service> serv)
+{
+ m_service = serv;
+ m_default.setService(serv);
+}
+
+
+weak_ref <net::service> defaultSASLAuthenticator::getService() const
+{
+ return m_service;
+}
+
+
+void defaultSASLAuthenticator::setSASLSession(ref <SASLSession> sess)
+{
+ m_saslSession = sess;
+}
+
+
+ref <SASLSession> defaultSASLAuthenticator::getSASLSession() const
+{
+ return m_saslSession;
+}
+
+
+void defaultSASLAuthenticator::setSASLMechanism(ref <SASLMechanism> mech)
+{
+ m_saslMech = mech;
+}
+
+
+ref <SASLMechanism> defaultSASLAuthenticator::getSASLMechanism() const
+{
+ return m_saslMech;
+}
+
+
+} // sasl
+} // security
+} // vmime
+