SASL authentication.
This commit is contained in:
parent
e51fb0c931
commit
0edaa87860
@ -2,6 +2,11 @@
|
||||
VERSION 0.7.2cvs
|
||||
================
|
||||
|
||||
2005-09-17 Vincent Richard <vincent@vincent-richard.net>
|
||||
|
||||
* Added SASL support, based on GNU SASL library. Slightly modified
|
||||
auhenticator object; see 'example6' which has been updated.
|
||||
|
||||
2005-09-06 Vincent Richard <vincent@vincent-richard.net>
|
||||
|
||||
* Created 'vmime::security' and 'vmime::security::digest' namespaces.
|
||||
|
136
SConstruct
136
SConstruct
@ -170,12 +170,26 @@ libvmime_sources = [
|
||||
# =============================== Misc ===============================
|
||||
'misc/importanceHelper.cpp', 'misc/importanceHelper.hpp',
|
||||
# ============================= Security =============================
|
||||
'security/authenticator.hpp',
|
||||
'security/defaultAuthenticator.cpp', 'security/defaultAuthenticator.hpp',
|
||||
# -- digest
|
||||
'security/digest/messageDigest.cpp', 'security/digest/messageDigest.hpp',
|
||||
'security/digest/messageDigestFactory.cpp', 'security/digest/messageDigestFactory.hpp',
|
||||
'security/digest/md5/md5MessageDigest.cpp', 'security/digest/md5/md5MessageDigest.hpp',
|
||||
'security/digest/sha1/sha1MessageDigest.cpp', 'security/digest/sha1/sha1MessageDigest.hpp'
|
||||
]
|
||||
|
||||
libvmime_security_sasl_sources = [
|
||||
'security/sasl/SASLContext.cpp', 'security/sasl/SASLContext.hpp',
|
||||
'security/sasl/SASLSession.cpp', 'security/sasl/SASLSession.hpp',
|
||||
'security/sasl/SASLMechanism.hpp',
|
||||
'security/sasl/SASLMechanismFactory.cpp', 'security/sasl/SASLMechanismFactory.hpp',
|
||||
'security/sasl/SASLSocket.cpp', 'security/sasl/SASLSocket.hpp',
|
||||
'security/sasl/SASLAuthenticator.hpp',
|
||||
'security/sasl/defaultSASLAuthenticator.cpp', 'security/sasl/defaultSASLAuthenticator.hpp',
|
||||
'security/sasl/builtinSASLMechanism.cpp', 'security/sasl/builtinSASLMechanism.hpp'
|
||||
]
|
||||
|
||||
libvmime_examples_sources = [
|
||||
'examples/README',
|
||||
# 'examples/Makefile.am', # not generated
|
||||
@ -190,11 +204,8 @@ libvmime_examples_sources = [
|
||||
]
|
||||
|
||||
libvmime_messaging_sources = [
|
||||
'net/authenticator.cpp', 'net/authenticator.hpp',
|
||||
'net/authenticationInfos.cpp', 'net/authenticationInfos.hpp',
|
||||
'net/authHelper.cpp', 'net/authHelper.hpp',
|
||||
'net/builtinServices.inl',
|
||||
'net/defaultAuthenticator.cpp', 'net/defaultAuthenticator.hpp',
|
||||
'net/events.cpp', 'net/events.hpp',
|
||||
'net/folder.cpp', 'net/folder.hpp',
|
||||
'net/message.cpp', 'net/message.hpp',
|
||||
@ -202,7 +213,6 @@ libvmime_messaging_sources = [
|
||||
'net/serviceFactory.cpp', 'net/serviceFactory.hpp',
|
||||
'net/serviceInfos.cpp', 'net/serviceInfos.hpp',
|
||||
'net/session.cpp', 'net/session.hpp',
|
||||
'net/simpleAuthenticator.cpp', 'net/simpleAuthenticator.hpp',
|
||||
'net/socket.hpp',
|
||||
'net/store.hpp',
|
||||
'net/timeoutHandler.hpp',
|
||||
@ -357,7 +367,7 @@ libvmime_autotools = [
|
||||
'vmime/Makefile.in'
|
||||
]
|
||||
|
||||
libvmime_all_sources = [] + libvmime_sources + libvmime_messaging_sources
|
||||
libvmime_all_sources = [] + libvmime_sources + libvmime_messaging_sources + libvmime_security_sasl_sources
|
||||
|
||||
for i in range(len(libvmime_all_sources)):
|
||||
f = libvmime_all_sources[i]
|
||||
@ -463,6 +473,14 @@ opts.AddOptions(
|
||||
+ 'Currently available platform handlers: posix.',
|
||||
'"posix"'
|
||||
),
|
||||
EnumOption(
|
||||
'with_sasl',
|
||||
'Enable SASL support (requires GNU SASL library)',
|
||||
'yes',
|
||||
allowed_values = ('yes', 'no'),
|
||||
map = { },
|
||||
ignorecase = 1
|
||||
),
|
||||
(
|
||||
'sendmail_path',
|
||||
'Specifies the path to sendmail.',
|
||||
@ -554,6 +572,8 @@ else:
|
||||
|
||||
#env.Append(LIBS = ['additional-lib-here'])
|
||||
|
||||
env.ParseConfig('pkg-config --cflags --libs libgsasl')
|
||||
|
||||
# Generate help text for command line options
|
||||
Help(opts.GenerateHelpText(env))
|
||||
|
||||
@ -642,6 +662,7 @@ if env['with_messaging'] == 'yes':
|
||||
print " * protocols : " + env['with_messaging_protocols']
|
||||
print "File-system support : " + env['with_filesystem']
|
||||
print "Platform handlers : " + env['with_platforms']
|
||||
print "SASL support : " + env['with_sasl']
|
||||
|
||||
if IsProtocolSupported(messaging_protocols, 'sendmail'):
|
||||
print "Sendmail path : " + env['sendmail_path']
|
||||
@ -727,6 +748,12 @@ if env['with_filesystem'] == 'yes':
|
||||
else:
|
||||
config_hpp.write('#define VMIME_HAVE_FILESYSTEM_FEATURES 0\n')
|
||||
|
||||
config_hpp.write('// -- SASL support\n')
|
||||
if env['with_sasl'] == 'yes':
|
||||
config_hpp.write('#define VMIME_HAVE_SASL_SUPPORT 1\n')
|
||||
else:
|
||||
config_hpp.write('#define VMIME_HAVE_SASL_SUPPORT 0\n')
|
||||
|
||||
config_hpp.write('// -- Messaging support\n')
|
||||
if env['with_messaging'] == 'yes':
|
||||
config_hpp.write('#define VMIME_HAVE_MESSAGING_FEATURES 1\n')
|
||||
@ -800,6 +827,11 @@ if env['with_messaging'] == 'yes':
|
||||
for file in protosrc[1]:
|
||||
libvmime_sel_sources.append(file)
|
||||
|
||||
# -- SASL support
|
||||
if env['with_sasl'] == 'yes':
|
||||
for file in libvmime_security_sasl_sources:
|
||||
libvmime_sel_sources.append(file)
|
||||
|
||||
# -- platform handlers
|
||||
for platform in platforms:
|
||||
files = libvmime_platforms_sources[platform]
|
||||
@ -852,12 +884,13 @@ Default(libVmime)
|
||||
# Tests
|
||||
if env['build_tests'] == 'yes':
|
||||
if env['debug'] == 'yes':
|
||||
env = env.Copy()
|
||||
env.Append(LIBS = ['cppunit', 'dl', packageVersionedGenericName + '-debug'])
|
||||
env.Append(LIBPATH=['.'])
|
||||
Default(
|
||||
env.Program(
|
||||
target = 'run-tests',
|
||||
source = libvmimetest_sources,
|
||||
LIBS=['cppunit', 'dl', packageVersionedGenericName + '-debug'],
|
||||
LIBPATH=['.']
|
||||
source = libvmimetest_sources
|
||||
)
|
||||
)
|
||||
else:
|
||||
@ -888,6 +921,13 @@ env.Install(includeDir, 'vmime/config.hpp')
|
||||
# Pkg-config support
|
||||
vmime_pc = open(packageVersionedGenericName + ".pc", 'w')
|
||||
|
||||
vmime_pc_requires = ''
|
||||
vmime_pc_libs = ''
|
||||
|
||||
if env['with_sasl'] == 'yes':
|
||||
vmime_pc_requires = vmime_pc_requires + "libgsasl "
|
||||
vmime_pc_libs = vmime_pc_libs + "-lgsasl "
|
||||
|
||||
vmime_pc.write("prefix=" + env['prefix'] + "\n")
|
||||
vmime_pc.write("exec_prefix=" + env['prefix'] + "\n")
|
||||
vmime_pc.write("libdir=" + env['prefix'] + "/lib\n")
|
||||
@ -896,8 +936,8 @@ vmime_pc.write("\n")
|
||||
vmime_pc.write("Name: " + packageRealName + "\n")
|
||||
vmime_pc.write("Description: " + packageDescription + "\n")
|
||||
vmime_pc.write("Version: " + packageVersion + "\n")
|
||||
vmime_pc.write("Requires:\n")
|
||||
vmime_pc.write("Libs: -L${libdir} -l" + packageVersionedGenericName + "\n")
|
||||
vmime_pc.write("Requires: " + vmime_pc_requires + "\n")
|
||||
vmime_pc.write("Libs: -L${libdir} -l" + packageVersionedGenericName + " " + vmime_pc_libs + "\n")
|
||||
#vmime_pc.write("Cflags: -I${includedir}/" + packageVersionedGenericName + "\n")
|
||||
vmime_pc.write("Cflags: -I${includedir}/" + "\n")
|
||||
|
||||
@ -969,8 +1009,8 @@ def generateAutotools(target, source, env):
|
||||
vmime_pc_in.write("Name: @GENERIC_LIBRARY_NAME@\n")
|
||||
vmime_pc_in.write("Description: " + packageDescription + "\n")
|
||||
vmime_pc_in.write("Version: @VERSION@\n")
|
||||
vmime_pc_in.write("Requires:\n")
|
||||
vmime_pc_in.write("Libs: -L${libdir} -l@GENERIC_VERSIONED_LIBRARY_NAME@\n")
|
||||
vmime_pc_in.write("Requires: @GSASL_REQUIRED@\n")
|
||||
vmime_pc_in.write("Libs: -L${libdir} -l@GENERIC_VERSIONED_LIBRARY_NAME@ @GSASL_LIBS@\n")
|
||||
#vmime_pc_in.write("Cflags: -I${includedir}/@GENERIC_VERSIONED_LIBRARY_NAME@\n")
|
||||
vmime_pc_in.write("Cflags: -I${includedir}/\n")
|
||||
vmime_pc_in.close()
|
||||
@ -1074,6 +1114,15 @@ INCLUDES = -I$(top_srcdir) -I$(srcdir) @PKGCONFIG_CFLAGS@ @EXTRA_CFLAGS@
|
||||
Makefile_am.write(packageVersionedName + "_la_SOURCES += " + buildMakefileFileList(x, 1) + "\n")
|
||||
Makefile_am.write("endif\n")
|
||||
|
||||
# -- SASL support
|
||||
x = selectFilesFromSuffixNot(libvmime_security_sasl_sources, '.hpp')
|
||||
sourceFiles += x
|
||||
|
||||
Makefile_am.write("\n")
|
||||
Makefile_am.write("if VMIME_HAVE_SASL_SUPPORT\n")
|
||||
Makefile_am.write(packageVersionedName + "_la_SOURCES += " + buildMakefileFileList(x, 1) + "\n")
|
||||
Makefile_am.write("endif\n")
|
||||
|
||||
# -- platform handlers
|
||||
for platform in libvmime_platforms_sources:
|
||||
Makefile_am.write("\n")
|
||||
@ -1200,6 +1249,13 @@ else
|
||||
AC_ERROR(no usable version of iconv has been found)
|
||||
fi
|
||||
|
||||
# -- GNU SASL Library (http://www.gnu.org/software/gsasl/)
|
||||
AC_CHECK_HEADER(gsasl.h,
|
||||
AC_CHECK_LIB(gsasl, gsasl_check_version,
|
||||
[have_gsasl=yes AC_SUBST(GSASL_AVAIL_LIBS, -lgsasl) AC_SUBST(GSASL_AVAIL_REQUIRED, libgsasl)],
|
||||
have_gsasl=no),
|
||||
have_gsasl=no)
|
||||
|
||||
# -- global constructors (stolen from 'configure.in' in libsigc++)
|
||||
AC_MSG_CHECKING([if linker supports global constructors])
|
||||
cat > mylib.$ac_ext <<EOF
|
||||
@ -1391,7 +1447,7 @@ esac
|
||||
# ** debug
|
||||
|
||||
AC_ARG_ENABLE(debug,
|
||||
[ --enable-debug Turn on debugging (default: disabled)],
|
||||
AC_HELP_STRING([--enable-debug], [Turn on debugging, default: disabled]),
|
||||
[case "${enableval}" in
|
||||
yes) conf_debug=yes ;;
|
||||
no) conf_debug=no ;;
|
||||
@ -1410,8 +1466,7 @@ fi
|
||||
# ** messaging
|
||||
|
||||
AC_ARG_ENABLE(messaging,
|
||||
[ --enable-messaging Enable messaging support\
|
||||
(connection to mail servers, default: enabled)],
|
||||
AC_HELP_STRING([--enable-messaging], [Enable messaging support and connection to mail servers, default: enabled]),
|
||||
[case "${enableval}" in
|
||||
yes) conf_messaging=yes ;;
|
||||
no) conf_messaging=no ;;
|
||||
@ -1427,6 +1482,38 @@ else
|
||||
VMIME_HAVE_MESSAGING_FEATURES=0
|
||||
fi
|
||||
|
||||
# ** SASL
|
||||
|
||||
AC_ARG_ENABLE(sasl,
|
||||
AC_HELP_STRING([--enable-sasl], [Enable SASL support with GNU SASL, default: enabled]),
|
||||
[case "${enableval}" in
|
||||
yes) conf_sasl=yes ;;
|
||||
no) conf_sasl=no ;;
|
||||
*) AC_MSG_ERROR(bad value ${enableval} for --enable-sasl) ;;
|
||||
esac],
|
||||
[conf_sasl=yes])
|
||||
|
||||
if test "x$conf_sasl" = "xyes"; then
|
||||
if test "x$have_gsasl" = "xyes"; then
|
||||
AM_CONDITIONAL(VMIME_HAVE_SASL_SUPPORT, true)
|
||||
VMIME_HAVE_SASL_SUPPORT=1
|
||||
|
||||
GSASL_REQUIRED=${GSASL_AVAIL_REQUIRED}
|
||||
GSASL_LIBS=${GSASL_AVAIL_LIBS}
|
||||
else
|
||||
AC_MSG_ERROR(can't find an usable version of GNU SASL library)
|
||||
fi
|
||||
else
|
||||
AM_CONDITIONAL(VMIME_HAVE_SASL_SUPPORT, false)
|
||||
VMIME_HAVE_SASL_SUPPORT=0
|
||||
|
||||
GSASL_REQUIRED=
|
||||
GSASL_LIBS=
|
||||
fi
|
||||
|
||||
AC_SUBST(GSASL_REQUIRED)
|
||||
AC_SUBST(GSASL_LIBS)
|
||||
|
||||
# ** platform handlers
|
||||
|
||||
VMIME_BUILTIN_PLATFORMS=''
|
||||
@ -1452,9 +1539,9 @@ VMIME_BUILTIN_MESSAGING_PROTOS=''
|
||||
p = proto[0]
|
||||
|
||||
configure_in.write("AC_ARG_ENABLE(messaging-proto-" + p + ",\n")
|
||||
configure_in.write(" [ --enable-messaging-proto-" + p
|
||||
+ " Enable built-in support for protocol '" + p + "' "
|
||||
+ " (default: enabled)],\n")
|
||||
configure_in.write(" AC_HELP_STRING([--enable-messaging-proto-" + p
|
||||
+ "], [Enable built-in support for protocol '" + p + "'"
|
||||
+ ", default: enabled]),\n")
|
||||
configure_in.write(' [case "${enableval}" in\n')
|
||||
configure_in.write(' yes) conf_messaging_proto_' + p + '=yes ;;\n')
|
||||
configure_in.write(' no) conf_messaging_proto_' + p + '=no ;;\n')
|
||||
@ -1514,9 +1601,9 @@ fi
|
||||
configure_in.write('fi\n\n')
|
||||
|
||||
configure_in.write("AC_ARG_ENABLE(platform-" + p + ",\n")
|
||||
configure_in.write(" [ --enable-platform-" + p
|
||||
+ " Compile built-in platform handler for '" + p + "' "
|
||||
+ " (default: disabled, except if default for your platform)],\n")
|
||||
configure_in.write(" AC_HELP_STRING([--enable-platform-" + p
|
||||
+ "], [Compile built-in platform handler for '" + p + "' "
|
||||
+ ", default: disabled, except if default for your platform]),\n")
|
||||
configure_in.write(' [case "${enableval}" in\n')
|
||||
configure_in.write(' yes) conf_platform_' + p + '=yes ;;\n')
|
||||
configure_in.write(' no) conf_platform_' + p + '=no ;;\n')
|
||||
@ -1551,7 +1638,7 @@ AC_SUBST(PKGCONFIG_CFLAGS)
|
||||
AC_SUBST(PKGCONFIG_LIBS)
|
||||
|
||||
EXTRA_CFLAGS="$EXTRA_CFLAGS -D_REENTRANT=1"
|
||||
EXTRA_LIBS=""
|
||||
EXTRA_LIBS="$GSASL_LIBS"
|
||||
|
||||
CFLAGS=""
|
||||
CXXFLAGS=""
|
||||
@ -1666,6 +1753,8 @@ typedef unsigned ${VMIME_TYPE_INT32} vmime_uint32;
|
||||
#define VMIME_WIDE_CHAR_SUPPORT 0
|
||||
// -- File-system support
|
||||
#define VMIME_HAVE_FILESYSTEM_FEATURES 1
|
||||
// -- SASL support
|
||||
#define VMIME_HAVE_SASL_SUPPORT ${VMIME_HAVE_SASL_SUPPORT}
|
||||
// -- Messaging support
|
||||
#define VMIME_HAVE_MESSAGING_FEATURES ${VMIME_HAVE_MESSAGING_FEATURES}
|
||||
""")
|
||||
@ -1719,6 +1808,9 @@ Messaging support : $conf_messaging
|
||||
* protocols :$VMIME_BUILTIN_MESSAGING_PROTOS
|
||||
File-system support : yes
|
||||
Platform handlers :$VMIME_BUILTIN_PLATFORMS
|
||||
SASL support : $conf_sasl
|
||||
|
||||
Please check 'vmime/config.hpp' to ensure the configuration is correct.
|
||||
])
|
||||
""")
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include "vmime/vmime.hpp"
|
||||
#include "vmime/platforms/posix/posixHandler.hpp"
|
||||
@ -31,27 +32,65 @@ static vmime::ref <vmime::net::session> g_session
|
||||
|
||||
|
||||
// Authentification handler
|
||||
class interactiveAuthenticator : public vmime::net::authenticator
|
||||
class interactiveAuthenticator : public vmime::security::sasl::defaultSASLAuthenticator
|
||||
{
|
||||
const vmime::net::authenticationInfos requestAuthInfos() const
|
||||
const std::vector <vmime::ref <vmime::security::sasl::SASLMechanism> > getAcceptableMechanisms
|
||||
(const std::vector <vmime::ref <vmime::security::sasl::SASLMechanism> >& available,
|
||||
vmime::ref <vmime::security::sasl::SASLMechanism> suggested) const
|
||||
{
|
||||
vmime::string username, password;
|
||||
std::cout << std::endl << "Available SASL mechanisms:" << std::endl;
|
||||
|
||||
std::cout << std::endl;
|
||||
std::cout << "Please authenticate yourself:" << std::endl;
|
||||
for (unsigned int i = 0 ; i < available.size() ; ++i)
|
||||
{
|
||||
std::cout << " " << available[i]->getName();
|
||||
|
||||
std::cout << " Username: ";
|
||||
std::cout.flush();
|
||||
if (suggested && available[i]->getName() == suggested->getName())
|
||||
std::cout << "(suggested)";
|
||||
}
|
||||
|
||||
std::getline(std::cin, username);
|
||||
std::cout << std::endl << std::endl;
|
||||
|
||||
std::cout << " Password: ";
|
||||
std::cout.flush();
|
||||
|
||||
std::getline(std::cin, password);
|
||||
|
||||
return (vmime::net::authenticationInfos(username, password));
|
||||
return defaultSASLAuthenticator::getAcceptableMechanisms(available, suggested);
|
||||
}
|
||||
|
||||
void setSASLMechanism(vmime::ref <vmime::security::sasl::SASLMechanism> mech)
|
||||
{
|
||||
std::cout << "Trying " << mech->getName() << std::endl;
|
||||
|
||||
defaultSASLAuthenticator::setSASLMechanism(mech);
|
||||
}
|
||||
|
||||
const vmime::string getUsername() const
|
||||
{
|
||||
if (m_username.empty())
|
||||
m_username = getUserInput("Username");
|
||||
|
||||
return m_username;
|
||||
}
|
||||
|
||||
const vmime::string getPassword() const
|
||||
{
|
||||
if (m_password.empty())
|
||||
m_password = getUserInput("Password");
|
||||
|
||||
return m_password;
|
||||
}
|
||||
|
||||
static const vmime::string getUserInput(const std::string& prompt)
|
||||
{
|
||||
std::cout << prompt << ": ";
|
||||
std::cout.flush();
|
||||
|
||||
vmime::string res;
|
||||
std::getline(std::cin, res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
mutable vmime::string m_username;
|
||||
mutable vmime::string m_password;
|
||||
};
|
||||
|
||||
|
||||
@ -215,7 +254,7 @@ static void sendMessage()
|
||||
|
||||
// You can also set some properties (see example7 to know the properties
|
||||
// available for each service). For example, for SMTP:
|
||||
// tr->setProperty("options.need-authentication", true);
|
||||
tr->setProperty("options.need-authentication", true);
|
||||
|
||||
// Information about the mail
|
||||
std::cout << "Enter email of the expeditor (eg. me@somewhere.com): ";
|
||||
|
@ -347,8 +347,7 @@ const char* net_exception::name() const throw() { return "net_exception"; }
|
||||
socket_exception::~socket_exception() throw() {}
|
||||
socket_exception::socket_exception(const string& what, const exception& other)
|
||||
: net_exception(what.empty()
|
||||
? "Socket error."
|
||||
: "Socket error: '" + what + "'.", other) {}
|
||||
? "Socket error." : what, other) {}
|
||||
|
||||
exception* socket_exception::clone() const { return new socket_exception(*this); }
|
||||
const char* socket_exception::name() const throw() { return "socket_exception"; }
|
||||
@ -361,8 +360,7 @@ const char* socket_exception::name() const throw() { return "socket_exception";
|
||||
connection_error::~connection_error() throw() {}
|
||||
connection_error::connection_error(const string& what, const exception& other)
|
||||
: socket_exception(what.empty()
|
||||
? "Connection error."
|
||||
: "Connection error: '" + what + "'.", other) {}
|
||||
? "Connection error." : what, other) {}
|
||||
|
||||
exception* connection_error::clone() const { return new connection_error(*this); }
|
||||
const char* connection_error::name() const throw() { return "connection_error"; }
|
||||
@ -675,6 +673,48 @@ const char* file_not_found::name() const throw() { return "file_not_found"; }
|
||||
#endif // VMIME_HAVE_FILESYSTEM_FEATURES
|
||||
|
||||
|
||||
#if VMIME_HAVE_SASL_SUPPORT
|
||||
|
||||
|
||||
//
|
||||
// sasl_exception
|
||||
//
|
||||
|
||||
sasl_exception::~sasl_exception() throw() {}
|
||||
sasl_exception::sasl_exception(const string& what, const exception& other)
|
||||
: exception(what, other) {}
|
||||
|
||||
exception* sasl_exception::clone() const { return new sasl_exception(*this); }
|
||||
const char* sasl_exception::name() const throw() { return "sasl_exception"; }
|
||||
|
||||
|
||||
//
|
||||
// no_such_mechanism
|
||||
//
|
||||
|
||||
no_such_mechanism::~no_such_mechanism() throw() {}
|
||||
no_such_mechanism::no_such_mechanism(const string& name, const exception& other)
|
||||
: sasl_exception("No such SASL mechanism: '" + name + "'.", other) {}
|
||||
|
||||
exception* no_such_mechanism::clone() const { return new no_such_mechanism(*this); }
|
||||
const char* no_such_mechanism::name() const throw() { return "no_such_mechanism"; }
|
||||
|
||||
|
||||
//
|
||||
// no_auth_information
|
||||
//
|
||||
|
||||
no_auth_information::~no_auth_information() throw() {}
|
||||
no_auth_information::no_auth_information(const exception& other)
|
||||
: sasl_exception("Information cannot be provided.", other) {}
|
||||
|
||||
exception* no_auth_information::clone() const { return new no_auth_information(*this); }
|
||||
const char* no_auth_information::name() const throw() { return "no_auth_information"; }
|
||||
|
||||
|
||||
#endif // VMIME_HAVE_SASL_SUPPORT
|
||||
|
||||
|
||||
} // exceptions
|
||||
|
||||
|
||||
|
@ -1,52 +0,0 @@
|
||||
//
|
||||
// VMime library (http://www.vmime.org)
|
||||
// Copyright (C) 2002-2005 Vincent Richard <vincent@vincent-richard.net>
|
||||
//
|
||||
// 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/net/authenticationInfos.hpp"
|
||||
|
||||
|
||||
namespace vmime {
|
||||
namespace net {
|
||||
|
||||
|
||||
authenticationInfos::authenticationInfos(const string& username, const string& password)
|
||||
: m_username(username), m_password(password)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
authenticationInfos::authenticationInfos(const authenticationInfos& infos)
|
||||
: object(), m_username(infos.m_username), m_password(infos.m_password)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
const string& authenticationInfos::getUsername() const
|
||||
{
|
||||
return (m_username);
|
||||
}
|
||||
|
||||
|
||||
const string& authenticationInfos::getPassword() const
|
||||
{
|
||||
return (m_password);
|
||||
}
|
||||
|
||||
|
||||
} // net
|
||||
} // vmime
|
@ -1,33 +0,0 @@
|
||||
//
|
||||
// VMime library (http://www.vmime.org)
|
||||
// Copyright (C) 2002-2005 Vincent Richard <vincent@vincent-richard.net>
|
||||
//
|
||||
// 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/net/authenticator.hpp"
|
||||
|
||||
|
||||
namespace vmime {
|
||||
namespace net {
|
||||
|
||||
|
||||
authenticator::~authenticator()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
} // net
|
||||
} // vmime
|
@ -1,43 +0,0 @@
|
||||
//
|
||||
// VMime library (http://www.vmime.org)
|
||||
// Copyright (C) 2002-2005 Vincent Richard <vincent@vincent-richard.net>
|
||||
//
|
||||
// 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/net/defaultAuthenticator.hpp"
|
||||
#include "vmime/net/session.hpp"
|
||||
|
||||
|
||||
namespace vmime {
|
||||
namespace net {
|
||||
|
||||
|
||||
defaultAuthenticator::defaultAuthenticator(weak_ref <session> sess, const string& prefix)
|
||||
: m_session(sess), m_prefix(prefix)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
const authenticationInfos defaultAuthenticator::requestAuthInfos() const
|
||||
{
|
||||
return (authenticationInfos
|
||||
(m_session->getProperties()[m_prefix + "auth.username"],
|
||||
m_session->getProperties()[m_prefix + "auth.password"]));
|
||||
}
|
||||
|
||||
|
||||
} // net
|
||||
} // vmime
|
@ -25,6 +25,10 @@
|
||||
#include "vmime/exception.hpp"
|
||||
#include "vmime/platformDependant.hpp"
|
||||
|
||||
#if VMIME_HAVE_SASL_SUPPORT
|
||||
#include "vmime/security/sasl/SASLContext.hpp"
|
||||
#endif // VMIME_HAVE_SASL_SUPPORT
|
||||
|
||||
#include <sstream>
|
||||
|
||||
|
||||
@ -42,7 +46,7 @@ namespace net {
|
||||
namespace imap {
|
||||
|
||||
|
||||
IMAPConnection::IMAPConnection(weak_ref <IMAPStore> store, ref <authenticator> auth)
|
||||
IMAPConnection::IMAPConnection(weak_ref <IMAPStore> store, ref <security::authenticator> auth)
|
||||
: m_store(store), m_auth(auth), m_socket(NULL), m_parser(NULL), m_tag(NULL),
|
||||
m_hierarchySeparator('\0'), m_state(STATE_NONE), m_timeoutHandler(NULL)
|
||||
{
|
||||
@ -51,10 +55,17 @@ IMAPConnection::IMAPConnection(weak_ref <IMAPStore> store, ref <authenticator> a
|
||||
|
||||
IMAPConnection::~IMAPConnection()
|
||||
{
|
||||
if (isConnected())
|
||||
disconnect();
|
||||
else if (m_socket)
|
||||
internalDisconnect();
|
||||
try
|
||||
{
|
||||
if (isConnected())
|
||||
disconnect();
|
||||
else if (m_socket)
|
||||
internalDisconnect();
|
||||
}
|
||||
catch (vmime::exception&)
|
||||
{
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -107,25 +118,14 @@ void IMAPConnection::connect()
|
||||
}
|
||||
else if (greet->resp_cond_auth()->condition() != IMAPParser::resp_cond_auth::PREAUTH)
|
||||
{
|
||||
const authenticationInfos auth = m_auth->requestAuthInfos();
|
||||
|
||||
// TODO: other authentication methods
|
||||
|
||||
send(true, "LOGIN " + IMAPUtils::quoteString(auth.getUsername())
|
||||
+ " " + IMAPUtils::quoteString(auth.getPassword()), true);
|
||||
|
||||
utility::auto_ptr <IMAPParser::response> resp(m_parser->readResponse());
|
||||
|
||||
if (resp->isBad())
|
||||
try
|
||||
{
|
||||
internalDisconnect();
|
||||
throw exceptions::command_error("LOGIN", m_parser->lastLine());
|
||||
authenticate();
|
||||
}
|
||||
else if (resp->response_done()->response_tagged()->
|
||||
resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
|
||||
catch (...)
|
||||
{
|
||||
internalDisconnect();
|
||||
throw exceptions::authentication_error(m_parser->lastLine());
|
||||
m_state = STATE_NONE;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
@ -137,6 +137,278 @@ void IMAPConnection::connect()
|
||||
}
|
||||
|
||||
|
||||
void IMAPConnection::authenticate()
|
||||
{
|
||||
getAuthenticator()->setService(thisRef().dynamicCast <service>());
|
||||
|
||||
#if VMIME_HAVE_SASL_SUPPORT
|
||||
// First, try SASL authentication
|
||||
if (GET_PROPERTY(bool, PROPERTY_OPTIONS_SASL))
|
||||
{
|
||||
try
|
||||
{
|
||||
authenticateSASL();
|
||||
return;
|
||||
}
|
||||
catch (exceptions::authentication_error& e)
|
||||
{
|
||||
if (!GET_PROPERTY(bool, PROPERTY_OPTIONS_SASL_FALLBACK))
|
||||
{
|
||||
// Can't fallback on normal authentication
|
||||
internalDisconnect();
|
||||
throw e;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ignore, will try normal authentication
|
||||
}
|
||||
}
|
||||
catch (exception& e)
|
||||
{
|
||||
internalDisconnect();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
#endif // VMIME_HAVE_SASL_SUPPORT
|
||||
|
||||
// Normal authentication
|
||||
const string username = getAuthenticator()->getUsername();
|
||||
const string password = getAuthenticator()->getPassword();
|
||||
|
||||
send(true, "LOGIN " + IMAPUtils::quoteString(username)
|
||||
+ " " + IMAPUtils::quoteString(password), true);
|
||||
|
||||
utility::auto_ptr <IMAPParser::response> resp(m_parser->readResponse());
|
||||
|
||||
if (resp->isBad())
|
||||
{
|
||||
internalDisconnect();
|
||||
throw exceptions::command_error("LOGIN", m_parser->lastLine());
|
||||
}
|
||||
else if (resp->response_done()->response_tagged()->
|
||||
resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
|
||||
{
|
||||
internalDisconnect();
|
||||
throw exceptions::authentication_error(m_parser->lastLine());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if VMIME_HAVE_SASL_SUPPORT
|
||||
|
||||
void IMAPConnection::authenticateSASL()
|
||||
{
|
||||
if (!getAuthenticator().dynamicCast <security::sasl::SASLAuthenticator>())
|
||||
throw exceptions::authentication_error("No SASL authenticator available.");
|
||||
|
||||
const std::vector <string> capa = getCapabilities();
|
||||
std::vector <string> saslMechs;
|
||||
|
||||
for (unsigned int i = 0 ; i < capa.size() ; ++i)
|
||||
{
|
||||
const string& x = capa[i];
|
||||
|
||||
if (x.length() > 5 &&
|
||||
(x[0] == 'A' || x[0] == 'a') &&
|
||||
(x[1] == 'U' || x[1] == 'u') &&
|
||||
(x[2] == 'T' || x[2] == 't') &&
|
||||
(x[3] == 'H' || x[3] == 'h') &&
|
||||
x[4] == '=')
|
||||
{
|
||||
saslMechs.push_back(string(x.begin() + 5, x.end()));
|
||||
}
|
||||
}
|
||||
|
||||
if (saslMechs.empty())
|
||||
throw exceptions::authentication_error("No SASL mechanism available.");
|
||||
|
||||
std::vector <ref <security::sasl::SASLMechanism> > mechList;
|
||||
|
||||
ref <security::sasl::SASLContext> saslContext =
|
||||
vmime::create <security::sasl::SASLContext>();
|
||||
|
||||
for (unsigned int i = 0 ; i < saslMechs.size() ; ++i)
|
||||
{
|
||||
try
|
||||
{
|
||||
mechList.push_back
|
||||
(saslContext->createMechanism(saslMechs[i]));
|
||||
}
|
||||
catch (exceptions::no_such_mechanism&)
|
||||
{
|
||||
// Ignore mechanism
|
||||
}
|
||||
}
|
||||
|
||||
if (mechList.empty())
|
||||
throw exceptions::authentication_error("No SASL mechanism available.");
|
||||
|
||||
// Try to suggest a mechanism among all those supported
|
||||
ref <security::sasl::SASLMechanism> suggestedMech =
|
||||
saslContext->suggestMechanism(mechList);
|
||||
|
||||
if (!suggestedMech)
|
||||
throw exceptions::authentication_error("Unable to suggest SASL mechanism.");
|
||||
|
||||
// Allow application to choose which mechanisms to use
|
||||
mechList = getAuthenticator().dynamicCast <security::sasl::SASLAuthenticator>()->
|
||||
getAcceptableMechanisms(mechList, suggestedMech);
|
||||
|
||||
if (mechList.empty())
|
||||
throw exceptions::authentication_error("No SASL mechanism available.");
|
||||
|
||||
// Try each mechanism in the list in turn
|
||||
for (unsigned int i = 0 ; i < mechList.size() ; ++i)
|
||||
{
|
||||
ref <security::sasl::SASLMechanism> mech = mechList[i];
|
||||
|
||||
ref <security::sasl::SASLSession> saslSession =
|
||||
saslContext->createSession("imap", getAuthenticator(), mech);
|
||||
|
||||
saslSession->init();
|
||||
|
||||
send(true, "AUTHENTICATE " + mech->getName(), true);
|
||||
|
||||
for (bool cont = true ; cont ; )
|
||||
{
|
||||
utility::auto_ptr <IMAPParser::response> resp(m_parser->readResponse());
|
||||
|
||||
if (resp->response_done() &&
|
||||
resp->response_done()->response_tagged() &&
|
||||
resp->response_done()->response_tagged()->resp_cond_state()->
|
||||
status() == IMAPParser::resp_cond_state::OK)
|
||||
{
|
||||
m_socket = saslSession->getSecuredSocket(m_socket);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector <IMAPParser::continue_req_or_response_data*>
|
||||
respDataList = resp->continue_req_or_response_data();
|
||||
|
||||
string response;
|
||||
|
||||
for (unsigned int i = 0 ; i < respDataList.size() ; ++i)
|
||||
{
|
||||
if (respDataList[i]->continue_req())
|
||||
{
|
||||
response = respDataList[i]->continue_req()->resp_text()->text();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (response.empty())
|
||||
{
|
||||
cont = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
byte* challenge = 0;
|
||||
int challengeLen = 0;
|
||||
|
||||
byte* resp = 0;
|
||||
int respLen = 0;
|
||||
|
||||
try
|
||||
{
|
||||
// Extract challenge
|
||||
saslContext->decodeB64(response, &challenge, &challengeLen);
|
||||
|
||||
// Prepare response
|
||||
saslSession->evaluateChallenge
|
||||
(challenge, challengeLen, &resp, &respLen);
|
||||
|
||||
// Send response
|
||||
send(false, saslContext->encodeB64(resp, respLen), true);
|
||||
}
|
||||
catch (exceptions::sasl_exception& e)
|
||||
{
|
||||
if (challenge)
|
||||
{
|
||||
delete [] challenge;
|
||||
challenge = NULL;
|
||||
}
|
||||
|
||||
if (resp)
|
||||
{
|
||||
delete [] resp;
|
||||
resp = NULL;
|
||||
}
|
||||
|
||||
// Cancel SASL exchange
|
||||
send(false, "*", true);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
if (challenge)
|
||||
delete [] challenge;
|
||||
|
||||
if (resp)
|
||||
delete [] resp;
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
if (challenge)
|
||||
delete [] challenge;
|
||||
|
||||
if (resp)
|
||||
delete [] resp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw exceptions::authentication_error
|
||||
("Could not authenticate using SASL: all mechanisms failed.");
|
||||
}
|
||||
|
||||
#endif // VMIME_HAVE_SASL_SUPPORT
|
||||
|
||||
|
||||
const std::vector <string> IMAPConnection::getCapabilities()
|
||||
{
|
||||
send(true, "CAPABILITY", true);
|
||||
|
||||
utility::auto_ptr <IMAPParser::response> resp(m_parser->readResponse());
|
||||
|
||||
std::vector <string> res;
|
||||
|
||||
if (resp->response_done()->response_tagged()->
|
||||
resp_cond_state()->status() == IMAPParser::resp_cond_state::OK)
|
||||
{
|
||||
const std::vector <IMAPParser::continue_req_or_response_data*>& respDataList =
|
||||
resp->continue_req_or_response_data();
|
||||
|
||||
for (unsigned int i = 0 ; i < respDataList.size() ; ++i)
|
||||
{
|
||||
if (respDataList[i]->response_data() == NULL)
|
||||
continue;
|
||||
|
||||
const IMAPParser::capability_data* capaData =
|
||||
respDataList[i]->response_data()->capability_data();
|
||||
|
||||
std::vector <IMAPParser::capability*> caps = capaData->capabilities();
|
||||
|
||||
for (unsigned int j = 0 ; j < caps.size() ; ++j)
|
||||
{
|
||||
if (caps[j]->auth_type())
|
||||
res.push_back("AUTH=" + caps[j]->auth_type()->name());
|
||||
else
|
||||
res.push_back(caps[j]->atom()->value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
ref <security::authenticator> IMAPConnection::getAuthenticator()
|
||||
{
|
||||
return m_auth;
|
||||
}
|
||||
|
||||
|
||||
const bool IMAPConnection::isConnected() const
|
||||
{
|
||||
return (m_socket && m_socket->isConnected() &&
|
||||
|
@ -133,7 +133,7 @@ void IMAPFolder::open(const int mode, bool failIfModeIsNotAvailable)
|
||||
|
||||
// Open a connection for this folder
|
||||
ref <IMAPConnection> connection =
|
||||
vmime::create <IMAPConnection>(m_store, m_store->oneTimeAuthenticator());
|
||||
vmime::create <IMAPConnection>(m_store, m_store->getAuthenticator());
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -32,67 +32,23 @@ namespace net {
|
||||
namespace imap {
|
||||
|
||||
|
||||
#ifndef VMIME_BUILDING_DOC
|
||||
|
||||
//
|
||||
// IMAPauthenticator: private class used internally
|
||||
//
|
||||
// Used to request user credentials only in the first authentication
|
||||
// and reuse this information the next times
|
||||
//
|
||||
|
||||
class IMAPauthenticator : public authenticator
|
||||
{
|
||||
public:
|
||||
|
||||
IMAPauthenticator(ref <authenticator> auth)
|
||||
: m_auth(auth), m_infos(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
~IMAPauthenticator()
|
||||
{
|
||||
}
|
||||
|
||||
const authenticationInfos requestAuthInfos() const
|
||||
{
|
||||
if (m_infos == NULL)
|
||||
m_infos = vmime::create <authenticationInfos>(m_auth->requestAuthInfos());
|
||||
|
||||
return (*m_infos);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
ref <authenticator> m_auth;
|
||||
mutable ref <authenticationInfos> m_infos;
|
||||
};
|
||||
|
||||
#endif // VMIME_BUILDING_DOC
|
||||
|
||||
|
||||
|
||||
//
|
||||
// IMAPStore
|
||||
//
|
||||
|
||||
IMAPStore::IMAPStore(ref <session> sess, ref <authenticator> auth)
|
||||
: store(sess, getInfosInstance(), auth),
|
||||
m_connection(NULL), m_oneTimeAuth(NULL)
|
||||
IMAPStore::IMAPStore(ref <session> sess, ref <security::authenticator> auth)
|
||||
: store(sess, getInfosInstance(), auth), m_connection(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
IMAPStore::~IMAPStore()
|
||||
{
|
||||
if (isConnected())
|
||||
disconnect();
|
||||
}
|
||||
|
||||
|
||||
ref <authenticator> IMAPStore::oneTimeAuthenticator()
|
||||
{
|
||||
return (m_oneTimeAuth);
|
||||
try
|
||||
{
|
||||
if (isConnected())
|
||||
disconnect();
|
||||
}
|
||||
catch (vmime::exception&)
|
||||
{
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -140,10 +96,8 @@ void IMAPStore::connect()
|
||||
if (isConnected())
|
||||
throw exceptions::already_connected();
|
||||
|
||||
m_oneTimeAuth = vmime::create <IMAPauthenticator>(getAuthenticator());
|
||||
|
||||
m_connection = vmime::create <IMAPConnection>
|
||||
(thisWeakRef().dynamicCast <IMAPStore>(), m_oneTimeAuth);
|
||||
(thisWeakRef().dynamicCast <IMAPStore>(), getAuthenticator());
|
||||
|
||||
try
|
||||
{
|
||||
@ -179,8 +133,6 @@ void IMAPStore::disconnect()
|
||||
|
||||
m_connection->disconnect();
|
||||
|
||||
m_oneTimeAuth = NULL;
|
||||
|
||||
m_connection = NULL;
|
||||
}
|
||||
|
||||
@ -263,7 +215,10 @@ const IMAPStore::_infos::props& IMAPStore::_infos::getProperties() const
|
||||
static props p =
|
||||
{
|
||||
// IMAP-specific options
|
||||
// (none)
|
||||
#if VMIME_HAVE_SASL_SUPPORT
|
||||
property("options.sasl", serviceInfos::property::TYPE_BOOL, "true"),
|
||||
property("options.sasl.fallback", serviceInfos::property::TYPE_BOOL, "true"),
|
||||
#endif // VMIME_HAVE_SASL_SUPPORT
|
||||
|
||||
// Common properties
|
||||
property(serviceInfos::property::AUTH_USERNAME, serviceInfos::property::FLAG_REQUIRED),
|
||||
@ -286,7 +241,10 @@ const std::vector <serviceInfos::property> IMAPStore::_infos::getAvailableProper
|
||||
const props& p = getProperties();
|
||||
|
||||
// IMAP-specific options
|
||||
// (none)
|
||||
#if VMIME_HAVE_SASL_SUPPORT
|
||||
list.push_back(p.PROPERTY_OPTIONS_SASL);
|
||||
list.push_back(p.PROPERTY_OPTIONS_SASL_FALLBACK);
|
||||
#endif // VMIME_HAVE_SASL_SUPPORT
|
||||
|
||||
// Common properties
|
||||
list.push_back(p.PROPERTY_AUTH_USERNAME);
|
||||
|
@ -39,7 +39,7 @@ namespace net {
|
||||
namespace maildir {
|
||||
|
||||
|
||||
maildirStore::maildirStore(ref <session> sess, ref <authenticator> auth)
|
||||
maildirStore::maildirStore(ref <session> sess, ref <security::authenticator> auth)
|
||||
: store(sess, getInfosInstance(), auth), m_connected(false)
|
||||
{
|
||||
}
|
||||
@ -47,8 +47,15 @@ maildirStore::maildirStore(ref <session> sess, ref <authenticator> auth)
|
||||
|
||||
maildirStore::~maildirStore()
|
||||
{
|
||||
if (isConnected())
|
||||
disconnect();
|
||||
try
|
||||
{
|
||||
if (isConnected())
|
||||
disconnect();
|
||||
}
|
||||
catch (vmime::exception&)
|
||||
{
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -96,7 +103,7 @@ const bool maildirStore::isValidFolderName(const folder::path::component& name)
|
||||
const string& buf = name.getBuffer();
|
||||
|
||||
// Name cannot start/end with spaces
|
||||
if (utility::stringUtils::trim(buf) != name.getBuffer())
|
||||
if (utility::stringUtils::trim(buf) != buf)
|
||||
return false;
|
||||
|
||||
// Name cannot start with '.'
|
||||
|
@ -25,6 +25,11 @@
|
||||
#include "vmime/messageId.hpp"
|
||||
#include "vmime/security/digest/messageDigestFactory.hpp"
|
||||
#include "vmime/utility/filteredStream.hpp"
|
||||
#include "vmime/utility/stringUtils.hpp"
|
||||
|
||||
#if VMIME_HAVE_SASL_SUPPORT
|
||||
#include "vmime/security/sasl/SASLContext.hpp"
|
||||
#endif // VMIME_HAVE_SASL_SUPPORT
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@ -41,7 +46,7 @@ namespace net {
|
||||
namespace pop3 {
|
||||
|
||||
|
||||
POP3Store::POP3Store(ref <session> sess, ref <authenticator> auth)
|
||||
POP3Store::POP3Store(ref <session> sess, ref <security::authenticator> auth)
|
||||
: store(sess, getInfosInstance(), auth), m_socket(NULL),
|
||||
m_authentified(false), m_timeoutHandler(NULL)
|
||||
{
|
||||
@ -50,10 +55,17 @@ POP3Store::POP3Store(ref <session> sess, ref <authenticator> auth)
|
||||
|
||||
POP3Store::~POP3Store()
|
||||
{
|
||||
if (isConnected())
|
||||
disconnect();
|
||||
else if (m_socket)
|
||||
internalDisconnect();
|
||||
try
|
||||
{
|
||||
if (isConnected())
|
||||
disconnect();
|
||||
else if (m_socket)
|
||||
internalDisconnect();
|
||||
}
|
||||
catch (vmime::exception&)
|
||||
{
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -128,98 +140,319 @@ void POP3Store::connect()
|
||||
string response;
|
||||
readResponse(response, false);
|
||||
|
||||
if (isSuccessResponse(response))
|
||||
{
|
||||
bool authentified = false;
|
||||
|
||||
const authenticationInfos auth = getAuthenticator()->requestAuthInfos();
|
||||
|
||||
// Secured authentication with APOP (if requested and if available)
|
||||
//
|
||||
// eg: C: APOP vincent <digest>
|
||||
// --- S: +OK vincent is a valid mailbox
|
||||
messageId mid(response);
|
||||
|
||||
if (GET_PROPERTY(bool, PROPERTY_OPTIONS_APOP))
|
||||
{
|
||||
if (mid.getLeft().length() && mid.getRight().length())
|
||||
{
|
||||
// <digest> is the result of MD5 applied to "<message-id>password"
|
||||
ref <security::digest::messageDigest> md5 =
|
||||
security::digest::messageDigestFactory::getInstance()->create("md5");
|
||||
|
||||
md5->update(mid.generate() + auth.getPassword());
|
||||
md5->finalize();
|
||||
|
||||
sendRequest("APOP " + auth.getUsername() + " " + md5->getHexDigest());
|
||||
readResponse(response, false);
|
||||
|
||||
if (isSuccessResponse(response))
|
||||
{
|
||||
authentified = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!GET_PROPERTY(bool, PROPERTY_OPTIONS_APOP_FALLBACK))
|
||||
{
|
||||
internalDisconnect();
|
||||
throw exceptions::authentication_error(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// APOP not supported
|
||||
if (!GET_PROPERTY(bool, PROPERTY_OPTIONS_APOP_FALLBACK))
|
||||
{
|
||||
// Can't fallback on basic authentification
|
||||
internalDisconnect();
|
||||
throw exceptions::unsupported_option();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!authentified)
|
||||
{
|
||||
// Basic authentication
|
||||
//
|
||||
// eg: C: USER vincent
|
||||
// --- S: +OK vincent is a valid mailbox
|
||||
//
|
||||
// C: PASS couic
|
||||
// S: +OK vincent's maildrop has 2 messages (320 octets)
|
||||
|
||||
sendRequest("USER " + auth.getUsername());
|
||||
readResponse(response, false);
|
||||
|
||||
if (isSuccessResponse(response))
|
||||
{
|
||||
sendRequest("PASS " + auth.getPassword());
|
||||
readResponse(response, false);
|
||||
|
||||
if (!isSuccessResponse(response))
|
||||
{
|
||||
internalDisconnect();
|
||||
throw exceptions::authentication_error(response);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
internalDisconnect();
|
||||
throw exceptions::authentication_error(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
if (!isSuccessResponse(response))
|
||||
{
|
||||
internalDisconnect();
|
||||
throw exceptions::connection_greeting_error(response);
|
||||
}
|
||||
|
||||
// Start authentication process
|
||||
authenticate(messageId(response));
|
||||
}
|
||||
|
||||
|
||||
void POP3Store::authenticate(const messageId& randomMID)
|
||||
{
|
||||
getAuthenticator()->setService(thisRef().dynamicCast <service>());
|
||||
|
||||
#if VMIME_HAVE_SASL_SUPPORT
|
||||
// First, try SASL authentication
|
||||
if (GET_PROPERTY(bool, PROPERTY_OPTIONS_SASL))
|
||||
{
|
||||
try
|
||||
{
|
||||
authenticateSASL();
|
||||
|
||||
m_authentified = true;
|
||||
return;
|
||||
}
|
||||
catch (exceptions::authentication_error& e)
|
||||
{
|
||||
if (!GET_PROPERTY(bool, PROPERTY_OPTIONS_SASL_FALLBACK))
|
||||
{
|
||||
// Can't fallback on APOP/normal authentication
|
||||
internalDisconnect();
|
||||
throw e;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ignore, will try APOP/normal authentication
|
||||
}
|
||||
}
|
||||
catch (exception& e)
|
||||
{
|
||||
internalDisconnect();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
#endif // VMIME_HAVE_SASL_SUPPORT
|
||||
|
||||
// Secured authentication with APOP (if requested and if available)
|
||||
//
|
||||
// eg: C: APOP vincent <digest>
|
||||
// --- S: +OK vincent is a valid mailbox
|
||||
|
||||
const string username = getAuthenticator()->getUsername();
|
||||
const string password = getAuthenticator()->getPassword();
|
||||
|
||||
string response;
|
||||
|
||||
if (GET_PROPERTY(bool, PROPERTY_OPTIONS_APOP))
|
||||
{
|
||||
if (randomMID.getLeft().length() != 0 &&
|
||||
randomMID.getRight().length() != 0)
|
||||
{
|
||||
// <digest> is the result of MD5 applied to "<message-id>password"
|
||||
ref <security::digest::messageDigest> md5 =
|
||||
security::digest::messageDigestFactory::getInstance()->create("md5");
|
||||
|
||||
md5->update(randomMID.generate() + password);
|
||||
md5->finalize();
|
||||
|
||||
sendRequest("APOP " + username + " " + md5->getHexDigest());
|
||||
readResponse(response, false);
|
||||
|
||||
if (isSuccessResponse(response))
|
||||
{
|
||||
m_authentified = true;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Some servers close the connection after an
|
||||
// unsuccessful APOP command, so the fallback
|
||||
// may not always work...
|
||||
//
|
||||
// S: +OK Qpopper (version 4.0.5) at xxx starting. <30396.1126730747@xxx>
|
||||
// C: APOP plop c5e0a87d088ec71d60e32692d4c5bdf4
|
||||
// S: -ERR [AUTH] Password supplied for "o" is incorrect.
|
||||
// S: +OK Pop server at xxx signing off.
|
||||
// [Connection closed by foreign host.]
|
||||
|
||||
if (!GET_PROPERTY(bool, PROPERTY_OPTIONS_APOP_FALLBACK))
|
||||
{
|
||||
// Can't fallback on basic authentication
|
||||
internalDisconnect();
|
||||
throw exceptions::authentication_error(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// APOP not supported
|
||||
if (!GET_PROPERTY(bool, PROPERTY_OPTIONS_APOP_FALLBACK))
|
||||
{
|
||||
// Can't fallback on basic authentication
|
||||
internalDisconnect();
|
||||
throw exceptions::authentication_error("APOP not supported");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Basic authentication
|
||||
//
|
||||
// eg: C: USER vincent
|
||||
// --- S: +OK vincent is a valid mailbox
|
||||
//
|
||||
// C: PASS couic
|
||||
// S: +OK vincent's maildrop has 2 messages (320 octets)
|
||||
sendRequest("USER " + username);
|
||||
readResponse(response, false);
|
||||
|
||||
if (!isSuccessResponse(response))
|
||||
{
|
||||
internalDisconnect();
|
||||
throw exceptions::authentication_error(response);
|
||||
}
|
||||
|
||||
sendRequest("PASS " + password);
|
||||
readResponse(response, false);
|
||||
|
||||
if (!isSuccessResponse(response))
|
||||
{
|
||||
internalDisconnect();
|
||||
throw exceptions::authentication_error(response);
|
||||
}
|
||||
|
||||
m_authentified = true;
|
||||
}
|
||||
|
||||
|
||||
#if VMIME_HAVE_SASL_SUPPORT
|
||||
|
||||
void POP3Store::authenticateSASL()
|
||||
{
|
||||
if (!getAuthenticator().dynamicCast <security::sasl::SASLAuthenticator>())
|
||||
throw exceptions::authentication_error("No SASL authenticator available.");
|
||||
|
||||
std::vector <string> capa = getCapabilities();
|
||||
std::vector <string> saslMechs;
|
||||
|
||||
for (unsigned int i = 0 ; i < capa.size() ; ++i)
|
||||
{
|
||||
const string& x = capa[i];
|
||||
|
||||
// C: CAPA
|
||||
// S: +OK List of capabilities follows
|
||||
// S: LOGIN-DELAY 0
|
||||
// S: PIPELINING
|
||||
// S: UIDL
|
||||
// S: ...
|
||||
// S: SASL DIGEST-MD5 CRAM-MD5 <-----
|
||||
// S: EXPIRE NEVER
|
||||
// S: ...
|
||||
|
||||
if (x.length() > 5 &&
|
||||
(x[0] == 'S' || x[0] == 's') &&
|
||||
(x[1] == 'A' || x[1] == 'a') &&
|
||||
(x[2] == 'S' || x[2] == 's') &&
|
||||
(x[3] == 'L' || x[3] == 'l') &&
|
||||
std::isspace(x[4]))
|
||||
{
|
||||
const string list(x.begin() + 5, x.end());
|
||||
|
||||
std::istringstream iss(list);
|
||||
string mech;
|
||||
|
||||
while (iss >> mech)
|
||||
saslMechs.push_back(mech);
|
||||
}
|
||||
}
|
||||
|
||||
if (saslMechs.empty())
|
||||
throw exceptions::authentication_error("No SASL mechanism available.");
|
||||
|
||||
std::vector <ref <security::sasl::SASLMechanism> > mechList;
|
||||
|
||||
ref <security::sasl::SASLContext> saslContext =
|
||||
vmime::create <security::sasl::SASLContext>();
|
||||
|
||||
for (unsigned int i = 0 ; i < saslMechs.size() ; ++i)
|
||||
{
|
||||
try
|
||||
{
|
||||
mechList.push_back
|
||||
(saslContext->createMechanism(saslMechs[i]));
|
||||
}
|
||||
catch (exceptions::no_such_mechanism&)
|
||||
{
|
||||
// Ignore mechanism
|
||||
}
|
||||
}
|
||||
|
||||
if (mechList.empty())
|
||||
throw exceptions::authentication_error("No SASL mechanism available.");
|
||||
|
||||
// Try to suggest a mechanism among all those supported
|
||||
ref <security::sasl::SASLMechanism> suggestedMech =
|
||||
saslContext->suggestMechanism(mechList);
|
||||
|
||||
if (!suggestedMech)
|
||||
throw exceptions::authentication_error("Unable to suggest SASL mechanism.");
|
||||
|
||||
// Allow application to choose which mechanisms to use
|
||||
mechList = getAuthenticator().dynamicCast <security::sasl::SASLAuthenticator>()->
|
||||
getAcceptableMechanisms(mechList, suggestedMech);
|
||||
|
||||
if (mechList.empty())
|
||||
throw exceptions::authentication_error("No SASL mechanism available.");
|
||||
|
||||
// Try each mechanism in the list in turn
|
||||
for (unsigned int i = 0 ; i < mechList.size() ; ++i)
|
||||
{
|
||||
ref <security::sasl::SASLMechanism> mech = mechList[i];
|
||||
|
||||
ref <security::sasl::SASLSession> saslSession =
|
||||
saslContext->createSession("pop3", getAuthenticator(), mech);
|
||||
|
||||
saslSession->init();
|
||||
|
||||
sendRequest("AUTH " + mech->getName());
|
||||
|
||||
for (bool cont = true ; cont ; )
|
||||
{
|
||||
string response;
|
||||
readResponse(response, false);
|
||||
|
||||
switch (getResponseCode(response))
|
||||
{
|
||||
case RESPONSE_OK:
|
||||
{
|
||||
m_socket = saslSession->getSecuredSocket(m_socket);
|
||||
return;
|
||||
}
|
||||
case RESPONSE_READY:
|
||||
{
|
||||
byte* challenge = 0;
|
||||
int challengeLen = 0;
|
||||
|
||||
byte* resp = 0;
|
||||
int respLen = 0;
|
||||
|
||||
try
|
||||
{
|
||||
// Extract challenge
|
||||
stripResponseCode(response, response);
|
||||
saslContext->decodeB64(response, &challenge, &challengeLen);
|
||||
|
||||
// Prepare response
|
||||
saslSession->evaluateChallenge
|
||||
(challenge, challengeLen, &resp, &respLen);
|
||||
|
||||
// Send response
|
||||
sendRequest(saslContext->encodeB64(resp, respLen));
|
||||
}
|
||||
catch (exceptions::sasl_exception& e)
|
||||
{
|
||||
if (challenge)
|
||||
{
|
||||
delete [] challenge;
|
||||
challenge = NULL;
|
||||
}
|
||||
|
||||
if (resp)
|
||||
{
|
||||
delete [] resp;
|
||||
resp = NULL;
|
||||
}
|
||||
|
||||
// Cancel SASL exchange
|
||||
sendRequest("*");
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
if (challenge)
|
||||
delete [] challenge;
|
||||
|
||||
if (resp)
|
||||
delete [] resp;
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
if (challenge)
|
||||
delete [] challenge;
|
||||
|
||||
if (resp)
|
||||
delete [] resp;
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
||||
cont = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw exceptions::authentication_error
|
||||
("Could not authenticate using SASL: all mechanisms failed.");
|
||||
}
|
||||
|
||||
#endif // VMIME_HAVE_SASL_SUPPORT
|
||||
|
||||
|
||||
const bool POP3Store::isConnected() const
|
||||
{
|
||||
return (m_socket && m_socket->isConnected() && m_authentified);
|
||||
@ -259,7 +492,7 @@ void POP3Store::internalDisconnect()
|
||||
|
||||
void POP3Store::noop()
|
||||
{
|
||||
m_socket->send("NOOP");
|
||||
sendRequest("NOOP");
|
||||
|
||||
string response;
|
||||
readResponse(response, false);
|
||||
@ -269,12 +502,33 @@ void POP3Store::noop()
|
||||
}
|
||||
|
||||
|
||||
const std::vector <string> POP3Store::getCapabilities()
|
||||
{
|
||||
sendRequest("CAPA");
|
||||
|
||||
string response;
|
||||
readResponse(response, true);
|
||||
|
||||
std::vector <string> res;
|
||||
|
||||
if (isSuccessResponse(response))
|
||||
{
|
||||
stripFirstLine(response, response);
|
||||
|
||||
std::istringstream iss(response);
|
||||
string line;
|
||||
|
||||
while (std::getline(iss, line, '\n'))
|
||||
res.push_back(utility::stringUtils::trim(line));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
const bool POP3Store::isSuccessResponse(const string& buffer)
|
||||
{
|
||||
static const string OK("+OK");
|
||||
|
||||
return (buffer.length() >= 3 &&
|
||||
std::equal(buffer.begin(), buffer.begin() + 3, OK.begin()));
|
||||
return getResponseCode(buffer) == RESPONSE_OK;
|
||||
}
|
||||
|
||||
|
||||
@ -296,6 +550,34 @@ const bool POP3Store::stripFirstLine(const string& buffer, string& result, strin
|
||||
}
|
||||
|
||||
|
||||
const int POP3Store::getResponseCode(const string& buffer)
|
||||
{
|
||||
if (buffer.length() >= 2)
|
||||
{
|
||||
// +[space]
|
||||
if (buffer[0] == '+' &&
|
||||
(buffer[1] == ' ' || buffer[1] == '\t'))
|
||||
{
|
||||
return RESPONSE_READY;
|
||||
}
|
||||
|
||||
// +OK
|
||||
if (buffer.length() >= 3)
|
||||
{
|
||||
if (buffer[0] == '+' &&
|
||||
(buffer[1] == 'O' || buffer[1] == 'o') &&
|
||||
(buffer[2] == 'K' || buffer[1] == 'k'))
|
||||
{
|
||||
return RESPONSE_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -ERR or whatever
|
||||
return RESPONSE_ERR;
|
||||
}
|
||||
|
||||
|
||||
void POP3Store::stripResponseCode(const string& buffer, string& result)
|
||||
{
|
||||
const string::size_type pos = buffer.find_first_of(" \t");
|
||||
@ -588,8 +870,12 @@ const POP3Store::_infos::props& POP3Store::_infos::getProperties() const
|
||||
static props p =
|
||||
{
|
||||
// POP3-specific options
|
||||
property("options.apop", serviceInfos::property::TYPE_BOOL, "false"),
|
||||
property("options.apop.fallback", serviceInfos::property::TYPE_BOOL, "false"),
|
||||
property("options.apop", serviceInfos::property::TYPE_BOOL, "true"),
|
||||
property("options.apop.fallback", serviceInfos::property::TYPE_BOOL, "true"),
|
||||
#if VMIME_HAVE_SASL_SUPPORT
|
||||
property("options.sasl", serviceInfos::property::TYPE_BOOL, "true"),
|
||||
property("options.sasl.fallback", serviceInfos::property::TYPE_BOOL, "true"),
|
||||
#endif // VMIME_HAVE_SASL_SUPPORT
|
||||
|
||||
// Common properties
|
||||
property(serviceInfos::property::AUTH_USERNAME, serviceInfos::property::FLAG_REQUIRED),
|
||||
@ -614,6 +900,10 @@ const std::vector <serviceInfos::property> POP3Store::_infos::getAvailableProper
|
||||
// POP3-specific options
|
||||
list.push_back(p.PROPERTY_OPTIONS_APOP);
|
||||
list.push_back(p.PROPERTY_OPTIONS_APOP_FALLBACK);
|
||||
#if VMIME_HAVE_SASL_SUPPORT
|
||||
list.push_back(p.PROPERTY_OPTIONS_SASL);
|
||||
list.push_back(p.PROPERTY_OPTIONS_SASL_FALLBACK);
|
||||
#endif // VMIME_HAVE_SASL_SUPPORT
|
||||
|
||||
// Common properties
|
||||
list.push_back(p.PROPERTY_AUTH_USERNAME);
|
||||
|
@ -46,7 +46,7 @@ namespace net {
|
||||
namespace sendmail {
|
||||
|
||||
|
||||
sendmailTransport::sendmailTransport(ref <session> sess, ref <authenticator> auth)
|
||||
sendmailTransport::sendmailTransport(ref <session> sess, ref <security::authenticator> auth)
|
||||
: transport(sess, getInfosInstance(), auth), m_connected(false)
|
||||
{
|
||||
}
|
||||
@ -54,8 +54,15 @@ sendmailTransport::sendmailTransport(ref <session> sess, ref <authenticator> aut
|
||||
|
||||
sendmailTransport::~sendmailTransport()
|
||||
{
|
||||
if (isConnected())
|
||||
disconnect();
|
||||
try
|
||||
{
|
||||
if (isConnected())
|
||||
disconnect();
|
||||
}
|
||||
catch (vmime::exception&)
|
||||
{
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -17,22 +17,33 @@
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//
|
||||
|
||||
#include "vmime/config.hpp"
|
||||
#include "vmime/net/service.hpp"
|
||||
|
||||
#include "vmime/net/defaultAuthenticator.hpp"
|
||||
#if VMIME_HAVE_SASL_SUPPORT
|
||||
#include "vmime/security/sasl/defaultSASLAuthenticator.hpp"
|
||||
#else
|
||||
#include "vmime/security/defaultAuthenticator.hpp"
|
||||
#endif // VMIME_HAVE_SASL_SUPPORT
|
||||
|
||||
|
||||
namespace vmime {
|
||||
namespace net {
|
||||
|
||||
|
||||
service::service(ref <session> sess, const serviceInfos& infos, ref <authenticator> auth)
|
||||
service::service(ref <session> sess, const serviceInfos& /* infos */,
|
||||
ref <security::authenticator> auth)
|
||||
: m_session(sess), m_auth(auth)
|
||||
{
|
||||
if (!auth)
|
||||
{
|
||||
m_auth = vmime::create <defaultAuthenticator>
|
||||
(sess, infos.getPropertyPrefix());
|
||||
#if VMIME_HAVE_SASL_SUPPORT
|
||||
m_auth = vmime::create
|
||||
<security::sasl::defaultSASLAuthenticator>();
|
||||
#else
|
||||
m_auth = vmime::create
|
||||
<security::defaultAuthenticator>();
|
||||
#endif // VMIME_HAVE_SASL_SUPPORT
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,17 +65,23 @@ ref <session> service::getSession()
|
||||
}
|
||||
|
||||
|
||||
ref <const authenticator> service::getAuthenticator() const
|
||||
ref <const security::authenticator> service::getAuthenticator() const
|
||||
{
|
||||
return (m_auth);
|
||||
}
|
||||
|
||||
|
||||
ref <authenticator> service::getAuthenticator()
|
||||
ref <security::authenticator> service::getAuthenticator()
|
||||
{
|
||||
return (m_auth);
|
||||
}
|
||||
|
||||
|
||||
void service::setAuthenticator(ref <security::authenticator> auth)
|
||||
{
|
||||
m_auth = auth;
|
||||
}
|
||||
|
||||
|
||||
} // net
|
||||
} // vmime
|
||||
|
@ -48,14 +48,16 @@ serviceFactory* serviceFactory::getInstance()
|
||||
|
||||
|
||||
ref <service> serviceFactory::create
|
||||
(ref <session> sess, const string& protocol, ref <authenticator> auth)
|
||||
(ref <session> sess, const string& protocol,
|
||||
ref <security::authenticator> auth)
|
||||
{
|
||||
return (getServiceByProtocol(protocol)->create(sess, auth));
|
||||
}
|
||||
|
||||
|
||||
ref <service> serviceFactory::create
|
||||
(ref <session> sess, const utility::url& u, ref <authenticator> auth)
|
||||
(ref <session> sess, const utility::url& u,
|
||||
ref <security::authenticator> auth)
|
||||
{
|
||||
ref <service> serv = create(sess, u.getProtocol(), auth);
|
||||
|
||||
|
@ -50,13 +50,14 @@ session::~session()
|
||||
}
|
||||
|
||||
|
||||
ref <transport> session::getTransport(ref <authenticator> auth)
|
||||
ref <transport> session::getTransport(ref <security::authenticator> auth)
|
||||
{
|
||||
return (getTransport(m_props["transport.protocol"], auth));
|
||||
}
|
||||
|
||||
|
||||
ref <transport> session::getTransport(const string& protocol, ref <authenticator> auth)
|
||||
ref <transport> session::getTransport
|
||||
(const string& protocol, ref <security::authenticator> auth)
|
||||
{
|
||||
ref <session> sess = thisRef().dynamicCast <session>();
|
||||
ref <service> sv = serviceFactory::getInstance()->create(sess, protocol, auth);
|
||||
@ -68,7 +69,8 @@ ref <transport> session::getTransport(const string& protocol, ref <authenticator
|
||||
}
|
||||
|
||||
|
||||
ref <transport> session::getTransport(const utility::url& url, ref <authenticator> auth)
|
||||
ref <transport> session::getTransport
|
||||
(const utility::url& url, ref <security::authenticator> auth)
|
||||
{
|
||||
ref <session> sess = thisRef().dynamicCast <session>();
|
||||
ref <service> sv = serviceFactory::getInstance()->create(sess, url, auth);
|
||||
@ -80,13 +82,14 @@ ref <transport> session::getTransport(const utility::url& url, ref <authenticato
|
||||
}
|
||||
|
||||
|
||||
ref <store> session::getStore(ref <authenticator> auth)
|
||||
ref <store> session::getStore(ref <security::authenticator> auth)
|
||||
{
|
||||
return (getStore(m_props["store.protocol"], auth));
|
||||
}
|
||||
|
||||
|
||||
ref <store> session::getStore(const string& protocol, ref <authenticator> auth)
|
||||
ref <store> session::getStore
|
||||
(const string& protocol, ref <security::authenticator> auth)
|
||||
{
|
||||
ref <session> sess = thisRef().dynamicCast <session>();
|
||||
ref <service> sv = serviceFactory::getInstance()->create(sess, protocol, auth);
|
||||
@ -98,7 +101,8 @@ ref <store> session::getStore(const string& protocol, ref <authenticator> auth)
|
||||
}
|
||||
|
||||
|
||||
ref <store> session::getStore(const utility::url& url, ref <authenticator> auth)
|
||||
ref <store> session::getStore
|
||||
(const utility::url& url, ref <security::authenticator> auth)
|
||||
{
|
||||
ref <session> sess = thisRef().dynamicCast <session>();
|
||||
ref <service> sv = serviceFactory::getInstance()->create(sess, url, auth);
|
||||
|
@ -1,69 +0,0 @@
|
||||
//
|
||||
// VMime library (http://www.vmime.org)
|
||||
// Copyright (C) 2002-2005 Vincent Richard <vincent@vincent-richard.net>
|
||||
//
|
||||
// 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/net/simpleAuthenticator.hpp"
|
||||
|
||||
|
||||
namespace vmime {
|
||||
namespace net {
|
||||
|
||||
|
||||
simpleAuthenticator::simpleAuthenticator()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
simpleAuthenticator::simpleAuthenticator(const string& username, const string& password)
|
||||
: m_username(username), m_password(password)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
const authenticationInfos simpleAuthenticator::requestAuthInfos() const
|
||||
{
|
||||
return (authenticationInfos(m_username, m_password));
|
||||
}
|
||||
|
||||
|
||||
const string& simpleAuthenticator::getUsername() const
|
||||
{
|
||||
return (m_username);
|
||||
}
|
||||
|
||||
|
||||
void simpleAuthenticator::setUsername(const string& username)
|
||||
{
|
||||
m_username = username;
|
||||
}
|
||||
|
||||
|
||||
const string& simpleAuthenticator::getPassword() const
|
||||
{
|
||||
return (m_password);
|
||||
}
|
||||
|
||||
|
||||
void simpleAuthenticator::setPassword(const string& password)
|
||||
{
|
||||
m_password = password;
|
||||
}
|
||||
|
||||
|
||||
} // net
|
||||
} // vmime
|
@ -27,6 +27,11 @@
|
||||
#include "vmime/net/authHelper.hpp"
|
||||
|
||||
#include "vmime/utility/filteredStream.hpp"
|
||||
#include "vmime/utility/stringUtils.hpp"
|
||||
|
||||
#if VMIME_HAVE_SASL_SUPPORT
|
||||
#include "vmime/security/sasl/SASLContext.hpp"
|
||||
#endif // VMIME_HAVE_SASL_SUPPORT
|
||||
|
||||
|
||||
// Helpers for service properties
|
||||
@ -41,7 +46,7 @@ namespace net {
|
||||
namespace smtp {
|
||||
|
||||
|
||||
SMTPTransport::SMTPTransport(ref <session> sess, ref <authenticator> auth)
|
||||
SMTPTransport::SMTPTransport(ref <session> sess, ref <security::authenticator> auth)
|
||||
: transport(sess, getInfosInstance(), auth), m_socket(NULL),
|
||||
m_authentified(false), m_extendedSMTP(false), m_timeoutHandler(NULL)
|
||||
{
|
||||
@ -50,10 +55,17 @@ SMTPTransport::SMTPTransport(ref <session> sess, ref <authenticator> auth)
|
||||
|
||||
SMTPTransport::~SMTPTransport()
|
||||
{
|
||||
if (isConnected())
|
||||
disconnect();
|
||||
else if (m_socket)
|
||||
internalDisconnect();
|
||||
try
|
||||
{
|
||||
if (isConnected())
|
||||
disconnect();
|
||||
else if (m_socket)
|
||||
internalDisconnect();
|
||||
}
|
||||
catch (vmime::exception&)
|
||||
{
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -87,15 +99,16 @@ void SMTPTransport::connect()
|
||||
m_socket = sf->create();
|
||||
m_socket->connect(address, port);
|
||||
|
||||
m_responseBuffer.clear();
|
||||
|
||||
// Connection
|
||||
//
|
||||
// eg: C: <connection to server>
|
||||
// --- S: 220 smtp.domain.com Service ready
|
||||
|
||||
string response;
|
||||
readResponse(response);
|
||||
|
||||
if (responseCode(response) != 220)
|
||||
if (readAllResponses(response) != 220)
|
||||
{
|
||||
internalDisconnect();
|
||||
throw exceptions::connection_greeting_error(response);
|
||||
@ -105,12 +118,12 @@ void SMTPTransport::connect()
|
||||
// First, try Extended SMTP (ESMTP)
|
||||
//
|
||||
// eg: C: EHLO thismachine.ourdomain.com
|
||||
// S: 250 OK
|
||||
// S: 250-smtp.theserver.com
|
||||
// S: 250 AUTH CRAM-MD5 DIGEST-MD5
|
||||
|
||||
sendRequest("EHLO " + platformDependant::getHandler()->getHostName());
|
||||
readResponse(response);
|
||||
|
||||
if (responseCode(response) != 250)
|
||||
if (readAllResponses(response, true) != 250)
|
||||
{
|
||||
// Next, try "Basic" SMTP
|
||||
//
|
||||
@ -118,9 +131,8 @@ void SMTPTransport::connect()
|
||||
// S: 250 OK
|
||||
|
||||
sendRequest("HELO " + platformDependant::getHandler()->getHostName());
|
||||
readResponse(response);
|
||||
|
||||
if (responseCode(response) != 250)
|
||||
if (readAllResponses(response) != 250)
|
||||
{
|
||||
internalDisconnect();
|
||||
throw exceptions::connection_greeting_error(response);
|
||||
@ -131,93 +143,231 @@ void SMTPTransport::connect()
|
||||
else
|
||||
{
|
||||
m_extendedSMTP = true;
|
||||
m_extendedSMTPResponse = response;
|
||||
}
|
||||
|
||||
// Authentication
|
||||
if (GET_PROPERTY(bool, PROPERTY_OPTIONS_NEEDAUTH))
|
||||
authenticate();
|
||||
}
|
||||
|
||||
|
||||
void SMTPTransport::authenticate()
|
||||
{
|
||||
if (!m_extendedSMTP)
|
||||
{
|
||||
if (!m_extendedSMTP)
|
||||
internalDisconnect();
|
||||
throw exceptions::command_error("AUTH", "ESMTP not supported.");
|
||||
}
|
||||
|
||||
getAuthenticator()->setService(thisRef().dynamicCast <service>());
|
||||
|
||||
#if VMIME_HAVE_SASL_SUPPORT
|
||||
// First, try SASL authentication
|
||||
if (GET_PROPERTY(bool, PROPERTY_OPTIONS_SASL))
|
||||
{
|
||||
try
|
||||
{
|
||||
authenticateSASL();
|
||||
|
||||
m_authentified = true;
|
||||
return;
|
||||
}
|
||||
catch (exceptions::authentication_error& e)
|
||||
{
|
||||
if (!GET_PROPERTY(bool, PROPERTY_OPTIONS_SASL_FALLBACK))
|
||||
{
|
||||
// Can't fallback on normal authentication
|
||||
internalDisconnect();
|
||||
throw e;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ignore, will try normal authentication
|
||||
}
|
||||
}
|
||||
catch (exception& e)
|
||||
{
|
||||
internalDisconnect();
|
||||
throw exceptions::command_error("AUTH", "ESMTP not supported.");
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
#endif // VMIME_HAVE_SASL_SUPPORT
|
||||
|
||||
const authenticationInfos auth = getAuthenticator()->requestAuthInfos();
|
||||
bool authentified = false;
|
||||
// No other authentication method is possible
|
||||
throw exceptions::authentication_error("All authentication methods failed");
|
||||
}
|
||||
|
||||
enum AuthMethods
|
||||
|
||||
#if VMIME_HAVE_SASL_SUPPORT
|
||||
|
||||
void SMTPTransport::authenticateSASL()
|
||||
{
|
||||
if (!getAuthenticator().dynamicCast <security::sasl::SASLAuthenticator>())
|
||||
throw exceptions::authentication_error("No SASL authenticator available.");
|
||||
|
||||
// Obtain SASL mechanisms supported by server from EHLO response
|
||||
std::vector <string> saslMechs;
|
||||
std::istringstream iss(m_extendedSMTPResponse);
|
||||
|
||||
while (!iss.eof())
|
||||
{
|
||||
string line;
|
||||
std::getline(iss, line);
|
||||
|
||||
std::istringstream liss(line);
|
||||
string word;
|
||||
|
||||
bool inAuth = false;
|
||||
|
||||
while (liss >> word)
|
||||
{
|
||||
First = 0,
|
||||
CRAM_MD5 = First,
|
||||
// TODO: more authentication methods...
|
||||
End
|
||||
};
|
||||
|
||||
for (int currentMethod = First ; !authentified ; ++currentMethod)
|
||||
{
|
||||
switch (currentMethod)
|
||||
if (word.length() == 4 &&
|
||||
(word[0] == 'A' || word[0] == 'a') ||
|
||||
(word[0] == 'U' || word[0] == 'u') ||
|
||||
(word[0] == 'T' || word[0] == 't') ||
|
||||
(word[0] == 'H' || word[0] == 'h'))
|
||||
{
|
||||
case CRAM_MD5:
|
||||
{
|
||||
sendRequest("AUTH CRAM-MD5");
|
||||
readResponse(response);
|
||||
|
||||
if (responseCode(response) == 334)
|
||||
{
|
||||
encoderB64 base64;
|
||||
|
||||
string challengeB64 = responseText(response);
|
||||
string challenge, challengeHex;
|
||||
|
||||
{
|
||||
utility::inputStreamStringAdapter in(challengeB64);
|
||||
utility::outputStreamStringAdapter out(challenge);
|
||||
|
||||
base64.decode(in, out);
|
||||
}
|
||||
|
||||
hmac_md5(challenge, auth.getPassword(), challengeHex);
|
||||
|
||||
string decoded = auth.getUsername() + " " + challengeHex;
|
||||
string encoded;
|
||||
|
||||
{
|
||||
utility::inputStreamStringAdapter in(decoded);
|
||||
utility::outputStreamStringAdapter out(encoded);
|
||||
|
||||
base64.encode(in, out);
|
||||
}
|
||||
|
||||
sendRequest(encoded);
|
||||
readResponse(response);
|
||||
|
||||
if (responseCode(response) == 235)
|
||||
{
|
||||
authentified = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
internalDisconnect();
|
||||
throw exceptions::authentication_error(response);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
inAuth = true;
|
||||
}
|
||||
case End:
|
||||
else if (inAuth)
|
||||
{
|
||||
// All authentication methods have been tried and
|
||||
// the server does not understand any.
|
||||
throw exceptions::authentication_error(response);
|
||||
}
|
||||
|
||||
saslMechs.push_back(word);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_authentified = true;
|
||||
if (saslMechs.empty())
|
||||
throw exceptions::authentication_error("No SASL mechanism available.");
|
||||
|
||||
std::vector <ref <security::sasl::SASLMechanism> > mechList;
|
||||
|
||||
ref <security::sasl::SASLContext> saslContext =
|
||||
vmime::create <security::sasl::SASLContext>();
|
||||
|
||||
for (unsigned int i = 0 ; i < saslMechs.size() ; ++i)
|
||||
{
|
||||
try
|
||||
{
|
||||
mechList.push_back
|
||||
(saslContext->createMechanism(saslMechs[i]));
|
||||
}
|
||||
catch (exceptions::no_such_mechanism&)
|
||||
{
|
||||
// Ignore mechanism
|
||||
}
|
||||
}
|
||||
|
||||
if (mechList.empty())
|
||||
throw exceptions::authentication_error("No SASL mechanism available.");
|
||||
|
||||
// Try to suggest a mechanism among all those supported
|
||||
ref <security::sasl::SASLMechanism> suggestedMech =
|
||||
saslContext->suggestMechanism(mechList);
|
||||
|
||||
if (!suggestedMech)
|
||||
throw exceptions::authentication_error("Unable to suggest SASL mechanism.");
|
||||
|
||||
// Allow application to choose which mechanisms to use
|
||||
mechList = getAuthenticator().dynamicCast <security::sasl::SASLAuthenticator>()->
|
||||
getAcceptableMechanisms(mechList, suggestedMech);
|
||||
|
||||
if (mechList.empty())
|
||||
throw exceptions::authentication_error("No SASL mechanism available.");
|
||||
|
||||
// Try each mechanism in the list in turn
|
||||
for (unsigned int i = 0 ; i < mechList.size() ; ++i)
|
||||
{
|
||||
ref <security::sasl::SASLMechanism> mech = mechList[i];
|
||||
|
||||
ref <security::sasl::SASLSession> saslSession =
|
||||
saslContext->createSession("smtp", getAuthenticator(), mech);
|
||||
|
||||
saslSession->init();
|
||||
|
||||
sendRequest("AUTH " + mech->getName());
|
||||
|
||||
for (bool cont = true ; cont ; )
|
||||
{
|
||||
string response;
|
||||
|
||||
switch (readAllResponses(response))
|
||||
{
|
||||
case 235:
|
||||
{
|
||||
m_socket = saslSession->getSecuredSocket(m_socket);
|
||||
return;
|
||||
}
|
||||
case 334:
|
||||
{
|
||||
byte* challenge = 0;
|
||||
int challengeLen = 0;
|
||||
|
||||
byte* resp = 0;
|
||||
int respLen = 0;
|
||||
|
||||
try
|
||||
{
|
||||
// Extract challenge
|
||||
saslContext->decodeB64(response, &challenge, &challengeLen);
|
||||
|
||||
// Prepare response
|
||||
saslSession->evaluateChallenge
|
||||
(challenge, challengeLen, &resp, &respLen);
|
||||
|
||||
// Send response
|
||||
sendRequest(saslContext->encodeB64(resp, respLen));
|
||||
}
|
||||
catch (exceptions::sasl_exception& e)
|
||||
{
|
||||
if (challenge)
|
||||
{
|
||||
delete [] challenge;
|
||||
challenge = NULL;
|
||||
}
|
||||
|
||||
if (resp)
|
||||
{
|
||||
delete [] resp;
|
||||
resp = NULL;
|
||||
}
|
||||
|
||||
// Cancel SASL exchange
|
||||
sendRequest("*");
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
if (challenge)
|
||||
delete [] challenge;
|
||||
|
||||
if (resp)
|
||||
delete [] resp;
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
if (challenge)
|
||||
delete [] challenge;
|
||||
|
||||
if (resp)
|
||||
delete [] resp;
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
||||
cont = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw exceptions::authentication_error
|
||||
("Could not authenticate using SASL: all mechanisms failed.");
|
||||
}
|
||||
|
||||
#endif // VMIME_HAVE_SASL_SUPPORT
|
||||
|
||||
|
||||
const bool SMTPTransport::isConnected() const
|
||||
{
|
||||
@ -250,12 +400,11 @@ void SMTPTransport::internalDisconnect()
|
||||
|
||||
void SMTPTransport::noop()
|
||||
{
|
||||
m_socket->send("NOOP");
|
||||
sendRequest("NOOP");
|
||||
|
||||
string response;
|
||||
readResponse(response);
|
||||
|
||||
if (responseCode(response) != 250)
|
||||
if (readAllResponses(response) != 250)
|
||||
throw exceptions::command_error("NOOP", response);
|
||||
}
|
||||
|
||||
@ -274,9 +423,8 @@ void SMTPTransport::send(const mailbox& expeditor, const mailboxList& recipients
|
||||
string response;
|
||||
|
||||
sendRequest("MAIL FROM: <" + expeditor.getEmail() + ">");
|
||||
readResponse(response);
|
||||
|
||||
if (responseCode(response) != 250)
|
||||
if (readAllResponses(response) != 250)
|
||||
{
|
||||
internalDisconnect();
|
||||
throw exceptions::command_error("MAIL", response);
|
||||
@ -288,9 +436,8 @@ void SMTPTransport::send(const mailbox& expeditor, const mailboxList& recipients
|
||||
const mailbox& mbox = *recipients.getMailboxAt(i);
|
||||
|
||||
sendRequest("RCPT TO: <" + mbox.getEmail() + ">");
|
||||
readResponse(response);
|
||||
|
||||
if (responseCode(response) != 250)
|
||||
if (readAllResponses(response) != 250)
|
||||
{
|
||||
internalDisconnect();
|
||||
throw exceptions::command_error("RCPT TO", response);
|
||||
@ -299,9 +446,8 @@ void SMTPTransport::send(const mailbox& expeditor, const mailboxList& recipients
|
||||
|
||||
// Send the message data
|
||||
sendRequest("DATA");
|
||||
readResponse(response);
|
||||
|
||||
if (responseCode(response) != 354)
|
||||
if (readAllResponses(response) != 354)
|
||||
{
|
||||
internalDisconnect();
|
||||
throw exceptions::command_error("DATA", response);
|
||||
@ -315,9 +461,8 @@ void SMTPTransport::send(const mailbox& expeditor, const mailboxList& recipients
|
||||
|
||||
// Send end-of-data delimiter
|
||||
m_socket->sendRaw("\r\n.\r\n", 5);
|
||||
readResponse(response);
|
||||
|
||||
if (responseCode(response) != 250)
|
||||
if (readAllResponses(response) != 250)
|
||||
{
|
||||
internalDisconnect();
|
||||
throw exceptions::command_error("DATA", response);
|
||||
@ -332,7 +477,7 @@ void SMTPTransport::sendRequest(const string& buffer, const bool end)
|
||||
}
|
||||
|
||||
|
||||
const int SMTPTransport::responseCode(const string& response)
|
||||
const int SMTPTransport::getResponseCode(const string& response)
|
||||
{
|
||||
int code = 0;
|
||||
|
||||
@ -347,35 +492,25 @@ const int SMTPTransport::responseCode(const string& response)
|
||||
}
|
||||
|
||||
|
||||
const string SMTPTransport::responseText(const string& response)
|
||||
const string SMTPTransport::readResponseLine()
|
||||
{
|
||||
string text;
|
||||
string currentBuffer = m_responseBuffer;
|
||||
|
||||
std::istringstream iss(response);
|
||||
std::string line;
|
||||
|
||||
while (std::getline(iss, line))
|
||||
while (true)
|
||||
{
|
||||
if (line.length() >= 4)
|
||||
text += line.substr(4);
|
||||
else
|
||||
text += line;
|
||||
// Get a line from the response buffer
|
||||
string::size_type lineEnd = currentBuffer.find_first_of('\n');
|
||||
|
||||
text += "\n";
|
||||
}
|
||||
if (lineEnd != string::npos)
|
||||
{
|
||||
const string line(currentBuffer.begin(), currentBuffer.begin() + lineEnd);
|
||||
|
||||
return (text);
|
||||
}
|
||||
currentBuffer.erase(currentBuffer.begin(), currentBuffer.begin() + lineEnd + 1);
|
||||
m_responseBuffer = currentBuffer;
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
void SMTPTransport::readResponse(string& buffer)
|
||||
{
|
||||
bool foundTerminator = false;
|
||||
|
||||
buffer.clear();
|
||||
|
||||
for ( ; !foundTerminator ; )
|
||||
{
|
||||
// Check whether the time-out delay is elapsed
|
||||
if (m_timeoutHandler && m_timeoutHandler->isTimeOut())
|
||||
{
|
||||
@ -393,40 +528,61 @@ void SMTPTransport::readResponse(string& buffer)
|
||||
continue;
|
||||
}
|
||||
|
||||
// We have received data: reset the time-out counter
|
||||
if (m_timeoutHandler)
|
||||
m_timeoutHandler->resetTimeOut();
|
||||
currentBuffer += receiveBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
// Append the data to the response buffer
|
||||
buffer += receiveBuffer;
|
||||
|
||||
// Check for terminator string (and strip it if present)
|
||||
if (buffer.length() >= 2 && buffer[buffer.length() - 1] == '\n')
|
||||
const int SMTPTransport::readResponse(string& text)
|
||||
{
|
||||
string line = readResponseLine();
|
||||
|
||||
// Special case where CRLF occurs after response code
|
||||
if (line.length() < 4)
|
||||
line = line + '\n' + readResponseLine();
|
||||
|
||||
const int code = getResponseCode(line);
|
||||
|
||||
m_responseContinues = (line.length() >= 4 && line[3] == '-');
|
||||
|
||||
if (line.length() > 4)
|
||||
text = utility::stringUtils::trim(line.substr(4));
|
||||
else
|
||||
text = utility::stringUtils::trim(line);
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
|
||||
const int SMTPTransport::readAllResponses(string& outText, const bool allText)
|
||||
{
|
||||
string text;
|
||||
|
||||
const int firstCode = readResponse(outText);
|
||||
|
||||
if (allText)
|
||||
text = outText;
|
||||
|
||||
while (m_responseContinues)
|
||||
{
|
||||
const int code = readResponse(outText);
|
||||
|
||||
if (allText)
|
||||
text += '\n' + outText;
|
||||
|
||||
if (code != firstCode)
|
||||
{
|
||||
string::size_type p = buffer.length() - 2;
|
||||
bool end = false;
|
||||
if (allText)
|
||||
outText = text;
|
||||
|
||||
for ( ; !end ; --p)
|
||||
{
|
||||
if (p == 0 || buffer[p] == '\n')
|
||||
{
|
||||
end = true;
|
||||
|
||||
if (p + 4 < buffer.length())
|
||||
foundTerminator = true;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove [CR]LF at the end of the response
|
||||
if (buffer.length() >= 2 && buffer[buffer.length() - 1] == '\n')
|
||||
{
|
||||
if (buffer[buffer.length() - 2] == '\r')
|
||||
buffer.resize(buffer.length() - 2);
|
||||
else
|
||||
buffer.resize(buffer.length() - 1);
|
||||
}
|
||||
if (allText)
|
||||
outText = text;
|
||||
|
||||
return firstCode;
|
||||
}
|
||||
|
||||
|
||||
@ -460,6 +616,10 @@ const SMTPTransport::_infos::props& SMTPTransport::_infos::getProperties() const
|
||||
{
|
||||
// SMTP-specific options
|
||||
property("options.need-authentication", serviceInfos::property::TYPE_BOOL, "false"),
|
||||
#if VMIME_HAVE_SASL_SUPPORT
|
||||
property("options.sasl", serviceInfos::property::TYPE_BOOL, "true"),
|
||||
property("options.sasl.fallback", serviceInfos::property::TYPE_BOOL, "false"),
|
||||
#endif // VMIME_HAVE_SASL_SUPPORT
|
||||
|
||||
// Common properties
|
||||
property(serviceInfos::property::AUTH_USERNAME),
|
||||
@ -483,6 +643,10 @@ const std::vector <serviceInfos::property> SMTPTransport::_infos::getAvailablePr
|
||||
|
||||
// SMTP-specific options
|
||||
list.push_back(p.PROPERTY_OPTIONS_NEEDAUTH);
|
||||
#if VMIME_HAVE_SASL_SUPPORT
|
||||
list.push_back(p.PROPERTY_OPTIONS_SASL);
|
||||
list.push_back(p.PROPERTY_OPTIONS_SASL_FALLBACK);
|
||||
#endif // VMIME_HAVE_SASL_SUPPORT
|
||||
|
||||
// Common properties
|
||||
list.push_back(p.PROPERTY_AUTH_USERNAME);
|
||||
|
@ -28,7 +28,7 @@ namespace vmime {
|
||||
namespace net {
|
||||
|
||||
|
||||
transport::transport(ref <session> sess, const serviceInfos& infos, ref <authenticator> auth)
|
||||
transport::transport(ref <session> sess, const serviceInfos& infos, ref <security::authenticator> auth)
|
||||
: service(sess, infos, auth)
|
||||
{
|
||||
}
|
||||
|
98
src/security/defaultAuthenticator.cpp
Normal file
98
src/security/defaultAuthenticator.cpp
Normal file
@ -0,0 +1,98 @@
|
||||
//
|
||||
// VMime library (http://www.vmime.org)
|
||||
// Copyright (C) 2002-2005 Vincent Richard <vincent@vincent-richard.net>
|
||||
//
|
||||
// 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
|
||||
|
189
src/security/sasl/SASLContext.cpp
Normal file
189
src/security/sasl/SASLContext.cpp
Normal file
@ -0,0 +1,189 @@
|
||||
//
|
||||
// VMime library (http://www.vmime.org)
|
||||
// Copyright (C) 2002-2005 Vincent Richard <vincent@vincent-richard.net>
|
||||
//
|
||||
// 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
|
||||
|
131
src/security/sasl/SASLMechanismFactory.cpp
Normal file
131
src/security/sasl/SASLMechanismFactory.cpp
Normal file
@ -0,0 +1,131 @@
|
||||
//
|
||||
// VMime library (http://www.vmime.org)
|
||||
// Copyright (C) 2002-2005 Vincent Richard <vincent@vincent-richard.net>
|
||||
//
|
||||
// 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
|
||||
|
179
src/security/sasl/SASLSession.cpp
Normal file
179
src/security/sasl/SASLSession.cpp
Normal file
@ -0,0 +1,179 @@
|
||||
//
|
||||
// VMime library (http://www.vmime.org)
|
||||
// Copyright (C) 2002-2005 Vincent Richard <vincent@vincent-richard.net>
|
||||
//
|
||||
// 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
|
||||
|
167
src/security/sasl/SASLSocket.cpp
Normal file
167
src/security/sasl/SASLSocket.cpp
Normal file
@ -0,0 +1,167 @@
|
||||
//
|
||||
// VMime library (http://www.vmime.org)
|
||||
// Copyright (C) 2002-2005 Vincent Richard <vincent@vincent-richard.net>
|
||||
//
|
||||
// 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
|
||||
|
182
src/security/sasl/builtinSASLMechanism.cpp
Normal file
182
src/security/sasl/builtinSASLMechanism.cpp
Normal file
@ -0,0 +1,182 @@
|
||||
//
|
||||
// VMime library (http://www.vmime.org)
|
||||
// Copyright (C) 2002-2005 Vincent Richard <vincent@vincent-richard.net>
|
||||
//
|
||||
// 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
|
||||
|
139
src/security/sasl/defaultSASLAuthenticator.cpp
Normal file
139
src/security/sasl/defaultSASLAuthenticator.cpp
Normal file
@ -0,0 +1,139 @@
|
||||
//
|
||||
// VMime library (http://www.vmime.org)
|
||||
// Copyright (C) 2002-2005 Vincent Richard <vincent@vincent-richard.net>
|
||||
//
|
||||
// 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
|
||||
|
@ -326,6 +326,67 @@ const stream::size_type inputStreamPointerAdapter::skip(const size_type count)
|
||||
}
|
||||
|
||||
|
||||
|
||||
// inputStreamByteBufferAdapter
|
||||
|
||||
inputStreamByteBufferAdapter::inputStreamByteBufferAdapter(const byte* buffer, const size_type length)
|
||||
: m_buffer(buffer), m_length(length), m_pos(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
const bool inputStreamByteBufferAdapter::eof() const
|
||||
{
|
||||
return m_pos >= m_length;
|
||||
}
|
||||
|
||||
|
||||
void inputStreamByteBufferAdapter::reset()
|
||||
{
|
||||
m_pos = 0;
|
||||
}
|
||||
|
||||
|
||||
const stream::size_type inputStreamByteBufferAdapter::read
|
||||
(value_type* const data, const size_type count)
|
||||
{
|
||||
const size_type remaining = m_length - m_pos;
|
||||
|
||||
if (remaining < count)
|
||||
{
|
||||
std::copy(m_buffer + m_pos, m_buffer + m_pos + remaining, data);
|
||||
m_pos += remaining;
|
||||
|
||||
return remaining;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::copy(m_buffer + m_pos, m_buffer + m_pos + count, data);
|
||||
m_pos += count;
|
||||
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const stream::size_type inputStreamByteBufferAdapter::skip(const size_type count)
|
||||
{
|
||||
const size_type remaining = m_length - m_pos;
|
||||
|
||||
if (remaining < count)
|
||||
{
|
||||
m_pos += remaining;
|
||||
return remaining;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pos += count;
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef VMIME_HAVE_MESSAGING_FEATURES
|
||||
|
||||
|
||||
|
@ -811,6 +811,58 @@ public:
|
||||
#endif // VMIME_HAVE_FILESYSTEM_FEATURES
|
||||
|
||||
|
||||
#if VMIME_HAVE_SASL_SUPPORT
|
||||
|
||||
|
||||
/** Base class for exceptions throw by SASL module.
|
||||
*/
|
||||
|
||||
class sasl_exception : public vmime::exception
|
||||
{
|
||||
public:
|
||||
|
||||
sasl_exception(const string& what, const exception& other = NO_EXCEPTION);
|
||||
~sasl_exception() throw();
|
||||
|
||||
exception* clone() const;
|
||||
const char* name() const throw();
|
||||
};
|
||||
|
||||
|
||||
/** No mechanism is registered with the specified name.
|
||||
*/
|
||||
|
||||
class no_such_mechanism : public sasl_exception
|
||||
{
|
||||
public:
|
||||
|
||||
no_such_mechanism(const string& name, const exception& other = NO_EXCEPTION);
|
||||
~no_such_mechanism() throw();
|
||||
|
||||
exception* clone() const;
|
||||
const char* name() const throw();
|
||||
};
|
||||
|
||||
|
||||
/** The requested information cannot be provided.
|
||||
*/
|
||||
|
||||
class no_auth_information : public sasl_exception
|
||||
{
|
||||
public:
|
||||
|
||||
no_auth_information(const exception& other = NO_EXCEPTION);
|
||||
~no_auth_information() throw();
|
||||
|
||||
exception* clone() const;
|
||||
const char* name() const throw();
|
||||
};
|
||||
|
||||
|
||||
#endif // VMIME_HAVE_SASL_SUPPORT
|
||||
|
||||
|
||||
|
||||
} // exceptions
|
||||
|
||||
|
||||
|
@ -1,54 +0,0 @@
|
||||
//
|
||||
// VMime library (http://www.vmime.org)
|
||||
// Copyright (C) 2002-2005 Vincent Richard <vincent@vincent-richard.net>
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#ifndef VMIME_NET_AUTHENTICATOR_HPP_INCLUDED
|
||||
#define VMIME_NET_AUTHENTICATOR_HPP_INCLUDED
|
||||
|
||||
|
||||
#include "vmime/types.hpp"
|
||||
#include "vmime/net/authenticationInfos.hpp"
|
||||
|
||||
|
||||
namespace vmime {
|
||||
namespace net {
|
||||
|
||||
|
||||
/** This class is used to obtain user credentials.
|
||||
*/
|
||||
|
||||
class authenticator : public object
|
||||
{
|
||||
public:
|
||||
|
||||
virtual ~authenticator();
|
||||
|
||||
/** Called when the service needs to retrieve user credentials.
|
||||
* It should return the user account name and password.
|
||||
*
|
||||
* @return user credentials (user name and password)
|
||||
*/
|
||||
virtual const authenticationInfos requestAuthInfos() const = 0;
|
||||
};
|
||||
|
||||
|
||||
} // net
|
||||
} // vmime
|
||||
|
||||
|
||||
#endif // VMIME_NET_AUTHENTICATOR_HPP_INCLUDED
|
@ -23,13 +23,14 @@
|
||||
|
||||
#include "vmime/config.hpp"
|
||||
|
||||
#include "vmime/net/authenticator.hpp"
|
||||
#include "vmime/net/socket.hpp"
|
||||
#include "vmime/net/timeoutHandler.hpp"
|
||||
#include "vmime/net/session.hpp"
|
||||
|
||||
#include "vmime/net/imap/IMAPParser.hpp"
|
||||
|
||||
#include "vmime/security/authenticator.hpp"
|
||||
|
||||
|
||||
namespace vmime {
|
||||
namespace net {
|
||||
@ -44,7 +45,7 @@ class IMAPConnection : public object
|
||||
{
|
||||
public:
|
||||
|
||||
IMAPConnection(weak_ref <IMAPStore> store, ref <authenticator> auth);
|
||||
IMAPConnection(weak_ref <IMAPStore> store, ref <security::authenticator> auth);
|
||||
~IMAPConnection();
|
||||
|
||||
|
||||
@ -83,11 +84,21 @@ public:
|
||||
|
||||
ref <session> getSession();
|
||||
|
||||
const std::vector <string> getCapabilities();
|
||||
|
||||
ref <security::authenticator> getAuthenticator();
|
||||
|
||||
private:
|
||||
|
||||
void authenticate();
|
||||
#if VMIME_HAVE_SASL_SUPPORT
|
||||
void authenticateSASL();
|
||||
#endif // VMIME_HAVE_SASL_SUPPORT
|
||||
|
||||
|
||||
weak_ref <IMAPStore> m_store;
|
||||
|
||||
ref <authenticator> m_auth;
|
||||
ref <security::authenticator> m_auth;
|
||||
|
||||
ref <socket> m_socket;
|
||||
|
||||
|
@ -1401,22 +1401,32 @@ public:
|
||||
|
||||
string::size_type pos = *currentPos;
|
||||
|
||||
parser.check <one_char <'\\'> >(line, &pos);
|
||||
if (parser.check <one_char <'\\'> >(line, &pos, true))
|
||||
{
|
||||
atom* at = parser.get <atom>(line, &pos);
|
||||
const string name = utility::stringUtils::toLower(at->value());
|
||||
delete (at);
|
||||
|
||||
atom* at = parser.get <atom>(line, &pos);
|
||||
const string name = utility::stringUtils::toLower(at->value());
|
||||
delete (at);
|
||||
|
||||
if (name == "marked")
|
||||
m_type = MARKED;
|
||||
else if (name == "noinferiors")
|
||||
m_type = NOINFERIORS;
|
||||
else if (name == "noselect")
|
||||
m_type = NOSELECT;
|
||||
else if (name == "unmarked")
|
||||
m_type = UNMARKED;
|
||||
if (name == "marked")
|
||||
m_type = MARKED;
|
||||
else if (name == "noinferiors")
|
||||
m_type = NOINFERIORS;
|
||||
else if (name == "noselect")
|
||||
m_type = NOSELECT;
|
||||
else if (name == "unmarked")
|
||||
m_type = UNMARKED;
|
||||
else
|
||||
{
|
||||
m_type = UNKNOWN;
|
||||
m_name = "\\" + name;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
atom* at = parser.get <atom>(line, &pos);
|
||||
const string name = utility::stringUtils::toLower(at->value());
|
||||
delete (at);
|
||||
|
||||
m_type = UNKNOWN;
|
||||
m_name = name;
|
||||
}
|
||||
@ -1989,40 +1999,13 @@ public:
|
||||
string::size_type pos = *currentPos;
|
||||
|
||||
parser.checkWithArg <special_atom>(line, &pos, "capability");
|
||||
parser.check <SPACE>(line, &pos);
|
||||
|
||||
bool IMAP4rev1 = false;
|
||||
|
||||
for (bool end = false ; !end && !IMAP4rev1 ; )
|
||||
while (parser.check <SPACE>(line, &pos, true))
|
||||
{
|
||||
if (parser.checkWithArg <special_atom>(line, &pos, "imap4rev1", true))
|
||||
{
|
||||
IMAP4rev1 = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
capability* cap = parser.get <capability>(line, &pos);
|
||||
end = (cap == NULL);
|
||||
capability* cap = parser.get <capability>(line, &pos);
|
||||
if (cap == NULL) break;
|
||||
|
||||
if (cap)
|
||||
{
|
||||
m_capabilities.push_back(cap);
|
||||
}
|
||||
}
|
||||
|
||||
parser.check <SPACE>(line, &pos);
|
||||
}
|
||||
|
||||
|
||||
if (parser.check <SPACE>(line, &pos, true))
|
||||
{
|
||||
for (capability* cap = NULL ;
|
||||
(cap = parser.get <capability>(line, &pos)) != NULL ; )
|
||||
{
|
||||
m_capabilities.push_back(cap);
|
||||
|
||||
parser.check <SPACE>(line, &pos);
|
||||
}
|
||||
m_capabilities.push_back(cap);
|
||||
}
|
||||
|
||||
*currentPos = pos;
|
||||
|
@ -52,7 +52,7 @@ class IMAPStore : public store
|
||||
|
||||
public:
|
||||
|
||||
IMAPStore(ref <session> sess, ref <authenticator> auth);
|
||||
IMAPStore(ref <session> sess, ref <security::authenticator> auth);
|
||||
~IMAPStore();
|
||||
|
||||
const string getProtocolName() const;
|
||||
@ -79,13 +79,6 @@ private:
|
||||
// Connection
|
||||
ref <IMAPConnection> m_connection;
|
||||
|
||||
// Used to request the authentication informations only the
|
||||
// first time, and reuse these informations the next time.
|
||||
ref <class authenticator> m_oneTimeAuth;
|
||||
|
||||
|
||||
|
||||
ref <class authenticator> oneTimeAuthenticator();
|
||||
|
||||
|
||||
ref <IMAPConnection> connection();
|
||||
@ -106,7 +99,10 @@ private:
|
||||
struct props
|
||||
{
|
||||
// IMAP-specific options
|
||||
// (none)
|
||||
#if VMIME_HAVE_SASL_SUPPORT
|
||||
serviceInfos::property PROPERTY_OPTIONS_SASL;
|
||||
serviceInfos::property PROPERTY_OPTIONS_SASL_FALLBACK;
|
||||
#endif // VMIME_HAVE_SASL_SUPPORT
|
||||
|
||||
// Common properties
|
||||
serviceInfos::property PROPERTY_AUTH_USERNAME;
|
||||
|
@ -49,7 +49,7 @@ class maildirStore : public store
|
||||
|
||||
public:
|
||||
|
||||
maildirStore(ref <session> sess, ref <authenticator> auth);
|
||||
maildirStore(ref <session> sess, ref <security::authenticator> auth);
|
||||
~maildirStore();
|
||||
|
||||
const string getProtocolName() const;
|
||||
|
@ -48,7 +48,7 @@ class POP3Store : public store
|
||||
|
||||
public:
|
||||
|
||||
POP3Store(ref <session> sess, ref <authenticator> auth);
|
||||
POP3Store(ref <session> sess, ref <security::authenticator> auth);
|
||||
~POP3Store();
|
||||
|
||||
const string getProtocolName() const;
|
||||
@ -72,9 +72,24 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
enum ResponseCode
|
||||
{
|
||||
RESPONSE_OK = 0,
|
||||
RESPONSE_READY,
|
||||
RESPONSE_ERR
|
||||
};
|
||||
|
||||
void authenticate(const messageId& randomMID);
|
||||
#if VMIME_HAVE_SASL_SUPPORT
|
||||
void authenticateSASL();
|
||||
#endif // VMIME_HAVE_SASL_SUPPORT
|
||||
|
||||
const std::vector <string> getCapabilities();
|
||||
|
||||
static const bool isSuccessResponse(const string& buffer);
|
||||
static const bool stripFirstLine(const string& buffer, string& result, string* firstLine = NULL);
|
||||
static void stripResponseCode(const string& buffer, string& result);
|
||||
static const int getResponseCode(const string& buffer);
|
||||
|
||||
void sendRequest(const string& buffer, const bool end = true);
|
||||
void readResponse(string& buffer, const bool multiLine, utility::progressionListener* progress = NULL);
|
||||
@ -108,6 +123,10 @@ private:
|
||||
// POP3-specific options
|
||||
serviceInfos::property PROPERTY_OPTIONS_APOP;
|
||||
serviceInfos::property PROPERTY_OPTIONS_APOP_FALLBACK;
|
||||
#if VMIME_HAVE_SASL_SUPPORT
|
||||
serviceInfos::property PROPERTY_OPTIONS_SASL;
|
||||
serviceInfos::property PROPERTY_OPTIONS_SASL_FALLBACK;
|
||||
#endif // VMIME_HAVE_SASL_SUPPORT
|
||||
|
||||
// Common properties
|
||||
serviceInfos::property PROPERTY_AUTH_USERNAME;
|
||||
|
@ -43,7 +43,7 @@ class sendmailTransport : public transport
|
||||
{
|
||||
public:
|
||||
|
||||
sendmailTransport(ref <session> sess, ref <authenticator> auth);
|
||||
sendmailTransport(ref <session> sess, ref <security::authenticator> auth);
|
||||
~sendmailTransport();
|
||||
|
||||
const string getProtocolName() const;
|
||||
|
@ -24,7 +24,6 @@
|
||||
#include "vmime/types.hpp"
|
||||
|
||||
#include "vmime/net/session.hpp"
|
||||
#include "vmime/net/authenticator.hpp"
|
||||
|
||||
#include "vmime/net/serviceFactory.hpp"
|
||||
#include "vmime/net/serviceInfos.hpp"
|
||||
@ -43,7 +42,7 @@ class service : public object
|
||||
{
|
||||
protected:
|
||||
|
||||
service(ref <session> sess, const serviceInfos& infos, ref <authenticator> auth);
|
||||
service(ref <session> sess, const serviceInfos& infos, ref <security::authenticator> auth);
|
||||
|
||||
public:
|
||||
|
||||
@ -110,13 +109,19 @@ public:
|
||||
*
|
||||
* @return authenticator object
|
||||
*/
|
||||
ref <const authenticator> getAuthenticator() const;
|
||||
ref <const security::authenticator> getAuthenticator() const;
|
||||
|
||||
/** Return the authenticator object used with this service instance.
|
||||
*
|
||||
* @return authenticator object
|
||||
*/
|
||||
ref <authenticator> getAuthenticator();
|
||||
ref <security::authenticator> getAuthenticator();
|
||||
|
||||
/** Set the authenticator object used with this service instance.
|
||||
*
|
||||
* @param auth authenticator object
|
||||
*/
|
||||
void setAuthenticator(ref <security::authenticator> auth);
|
||||
|
||||
/** Set a property for this service (service prefix is added automatically).
|
||||
*
|
||||
@ -150,7 +155,7 @@ public:
|
||||
private:
|
||||
|
||||
ref <session> m_session;
|
||||
ref <authenticator> m_auth;
|
||||
ref <security::authenticator> m_auth;
|
||||
};
|
||||
|
||||
|
||||
|
@ -30,9 +30,10 @@
|
||||
#include "vmime/utility/url.hpp"
|
||||
|
||||
#include "vmime/net/serviceInfos.hpp"
|
||||
#include "vmime/net/authenticator.hpp"
|
||||
#include "vmime/net/timeoutHandler.hpp"
|
||||
|
||||
#include "vmime/security/authenticator.hpp"
|
||||
|
||||
#include "vmime/utility/progressionListener.hpp"
|
||||
|
||||
|
||||
@ -69,7 +70,9 @@ public:
|
||||
|
||||
public:
|
||||
|
||||
virtual ref <service> create(ref <session> sess, ref <authenticator> auth) const = 0;
|
||||
virtual ref <service> create
|
||||
(ref <session> sess,
|
||||
ref <security::authenticator> auth) const = 0;
|
||||
|
||||
virtual const string& getName() const = 0;
|
||||
virtual const serviceInfos& getInfos() const = 0;
|
||||
@ -92,7 +95,9 @@ private:
|
||||
|
||||
public:
|
||||
|
||||
ref <service> create(ref <session> sess, ref <authenticator> auth) const
|
||||
ref <service> create
|
||||
(ref <session> sess,
|
||||
ref <security::authenticator> auth) const
|
||||
{
|
||||
return vmime::create <S>(sess, auth);
|
||||
}
|
||||
@ -137,7 +142,10 @@ public:
|
||||
* @throw exceptions::no_service_available if no service is registered
|
||||
* for this protocol
|
||||
*/
|
||||
ref <service> create(ref <session> sess, const string& protocol, ref <authenticator> auth = NULL);
|
||||
ref <service> create
|
||||
(ref <session> sess,
|
||||
const string& protocol,
|
||||
ref <security::authenticator> auth = NULL);
|
||||
|
||||
/** Create a new service instance from a URL.
|
||||
*
|
||||
@ -149,7 +157,10 @@ public:
|
||||
* @throw exceptions::no_service_available if no service is registered
|
||||
* for this protocol
|
||||
*/
|
||||
ref <service> create(ref <session> sess, const utility::url& u, ref <authenticator> auth = NULL);
|
||||
ref <service> create
|
||||
(ref <session> sess,
|
||||
const utility::url& u,
|
||||
ref <security::authenticator> auth = NULL);
|
||||
|
||||
/** Return information about a registered protocol.
|
||||
*
|
||||
|
@ -21,7 +21,7 @@
|
||||
#define VMIME_NET_SESSION_HPP_INCLUDED
|
||||
|
||||
|
||||
#include "vmime/net/authenticator.hpp"
|
||||
#include "vmime/security/authenticator.hpp"
|
||||
|
||||
#include "vmime/utility/url.hpp"
|
||||
|
||||
@ -60,7 +60,8 @@ public:
|
||||
* credentials by reading the session properties "auth.username" and "auth.password".
|
||||
* @return a new transport service
|
||||
*/
|
||||
ref <transport> getTransport(ref <authenticator> auth = NULL);
|
||||
ref <transport> getTransport
|
||||
(ref <security::authenticator> auth = NULL);
|
||||
|
||||
/** Return a transport service instance for the specified protocol.
|
||||
*
|
||||
@ -70,7 +71,9 @@ public:
|
||||
* credentials by reading the session properties "auth.username" and "auth.password".
|
||||
* @return a new transport service
|
||||
*/
|
||||
ref <transport> getTransport(const string& protocol, ref <authenticator> auth = NULL);
|
||||
ref <transport> getTransport
|
||||
(const string& protocol,
|
||||
ref <security::authenticator> auth = NULL);
|
||||
|
||||
/** Return a transport service instance for the specified URL.
|
||||
*
|
||||
@ -80,7 +83,9 @@ public:
|
||||
* credentials by reading the session properties "auth.username" and "auth.password".
|
||||
* @return a new transport service
|
||||
*/
|
||||
ref <transport> getTransport(const utility::url& url, ref <authenticator> auth = NULL);
|
||||
ref <transport> getTransport
|
||||
(const utility::url& url,
|
||||
ref <security::authenticator> auth = NULL);
|
||||
|
||||
/** Return a transport service instance for the protocol specified
|
||||
* in the session properties.
|
||||
@ -92,7 +97,7 @@ public:
|
||||
* credentials by reading the session properties "auth.username" and "auth.password".
|
||||
* @return a new store service
|
||||
*/
|
||||
ref <store> getStore(ref <authenticator> auth = NULL);
|
||||
ref <store> getStore(ref <security::authenticator> auth = NULL);
|
||||
|
||||
/** Return a store service instance for the specified protocol.
|
||||
*
|
||||
@ -102,7 +107,9 @@ public:
|
||||
* credentials by reading the session properties "auth.username" and "auth.password".
|
||||
* @return a new store service
|
||||
*/
|
||||
ref <store> getStore(const string& protocol, ref <authenticator> auth = NULL);
|
||||
ref <store> getStore
|
||||
(const string& protocol,
|
||||
ref <security::authenticator> auth = NULL);
|
||||
|
||||
/** Return a store service instance for the specified URL.
|
||||
*
|
||||
@ -112,7 +119,9 @@ public:
|
||||
* credentials by reading the session properties "auth.username" and "auth.password".
|
||||
* @return a new store service
|
||||
*/
|
||||
ref <store> getStore(const utility::url& url, ref <authenticator> auth = NULL);
|
||||
ref <store> getStore
|
||||
(const utility::url& url,
|
||||
ref <security::authenticator> auth = NULL);
|
||||
|
||||
/** Properties for the session and for the services.
|
||||
*/
|
||||
|
@ -1,62 +0,0 @@
|
||||
//
|
||||
// VMime library (http://www.vmime.org)
|
||||
// Copyright (C) 2002-2005 Vincent Richard <vincent@vincent-richard.net>
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#ifndef VMIME_NET_SIMPLEAUTHENTICATOR_HPP_INCLUDED
|
||||
#define VMIME_NET_SIMPLEAUTHENTICATOR_HPP_INCLUDED
|
||||
|
||||
|
||||
#include "vmime/net/authenticator.hpp"
|
||||
|
||||
|
||||
namespace vmime {
|
||||
namespace net {
|
||||
|
||||
|
||||
/** Basic implementation for an authenticator.
|
||||
*/
|
||||
|
||||
class simpleAuthenticator : public authenticator
|
||||
{
|
||||
public:
|
||||
|
||||
simpleAuthenticator();
|
||||
simpleAuthenticator(const string& username, const string& password);
|
||||
|
||||
public:
|
||||
|
||||
const string& getUsername() const;
|
||||
void setUsername(const string& username);
|
||||
|
||||
const string& getPassword() const;
|
||||
void setPassword(const string& password);
|
||||
|
||||
const authenticationInfos requestAuthInfos() const;
|
||||
|
||||
private:
|
||||
|
||||
string m_username;
|
||||
string m_password;
|
||||
};
|
||||
|
||||
|
||||
} // net
|
||||
} // vmime
|
||||
|
||||
|
||||
#endif // VMIME_NET_SIMPLEAUTHENTICATOR_HPP_INCLUDED
|
@ -40,7 +40,7 @@ class SMTPTransport : public transport
|
||||
{
|
||||
public:
|
||||
|
||||
SMTPTransport(ref <session> sess, ref <authenticator> auth);
|
||||
SMTPTransport(ref <session> sess, ref <security::authenticator> auth);
|
||||
~SMTPTransport();
|
||||
|
||||
const string getProtocolName() const;
|
||||
@ -58,18 +58,30 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
static const int responseCode(const string& response);
|
||||
static const string responseText(const string& response);
|
||||
static const int getResponseCode(const string& response);
|
||||
|
||||
void sendRequest(const string& buffer, const bool end = true);
|
||||
|
||||
void readResponse(string& buffer);
|
||||
const string readResponseLine();
|
||||
const int readResponse(string& text);
|
||||
const int readAllResponses(string& text, const bool allText = false);
|
||||
|
||||
void internalDisconnect();
|
||||
|
||||
void authenticate();
|
||||
#if VMIME_HAVE_SASL_SUPPORT
|
||||
void authenticateSASL();
|
||||
#endif // VMIME_HAVE_SASL_SUPPORT
|
||||
|
||||
|
||||
ref <socket> m_socket;
|
||||
bool m_authentified;
|
||||
|
||||
bool m_extendedSMTP;
|
||||
string m_extendedSMTPResponse;
|
||||
|
||||
string m_responseBuffer;
|
||||
bool m_responseContinues;
|
||||
|
||||
ref <timeoutHandler> m_timeoutHandler;
|
||||
|
||||
@ -83,6 +95,10 @@ private:
|
||||
{
|
||||
// SMTP-specific options
|
||||
serviceInfos::property PROPERTY_OPTIONS_NEEDAUTH;
|
||||
#if VMIME_HAVE_SASL_SUPPORT
|
||||
serviceInfos::property PROPERTY_OPTIONS_SASL;
|
||||
serviceInfos::property PROPERTY_OPTIONS_SASL_FALLBACK;
|
||||
#endif // VMIME_HAVE_SASL_SUPPORT
|
||||
|
||||
// Common properties
|
||||
serviceInfos::property PROPERTY_AUTH_USERNAME;
|
||||
|
@ -37,7 +37,7 @@ class store : public service
|
||||
{
|
||||
protected:
|
||||
|
||||
store(ref <session> sess, const serviceInfos& infos, ref <authenticator> auth)
|
||||
store(ref <session> sess, const serviceInfos& infos, ref <security::authenticator> auth)
|
||||
: service(sess, infos, auth) { }
|
||||
|
||||
public:
|
||||
|
@ -42,7 +42,7 @@ class transport : public service
|
||||
{
|
||||
protected:
|
||||
|
||||
transport(ref <session> sess, const serviceInfos& infos, ref <authenticator> auth);
|
||||
transport(ref <session> sess, const serviceInfos& infos, ref <security::authenticator> auth);
|
||||
|
||||
public:
|
||||
|
||||
|
116
vmime/security/authenticator.hpp
Normal file
116
vmime/security/authenticator.hpp
Normal file
@ -0,0 +1,116 @@
|
||||
//
|
||||
// VMime library (http://www.vmime.org)
|
||||
// Copyright (C) 2002-2005 Vincent Richard <vincent@vincent-richard.net>
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#ifndef VMIME_SECURITY_AUTHENTICATOR_HPP_INCLUDED
|
||||
#define VMIME_SECURITY_AUTHENTICATOR_HPP_INCLUDED
|
||||
|
||||
|
||||
#include "vmime/types.hpp"
|
||||
|
||||
|
||||
// Forward declarations
|
||||
namespace vmime {
|
||||
namespace net {
|
||||
|
||||
class service;
|
||||
|
||||
} // net
|
||||
} // vmime
|
||||
|
||||
|
||||
namespace vmime {
|
||||
namespace security {
|
||||
|
||||
|
||||
/** Provides required information for user authentication. The same
|
||||
* information can be requested multiple time (eg. in IMAP, there is a
|
||||
* new connection started each time a folder is open), so the object is
|
||||
* responsible for caching the information to avoid useless interactions
|
||||
* with the user.
|
||||
*
|
||||
* Usually, you should not inherit from this class, but instead from the
|
||||
* more convenient defaultAuthenticator class.
|
||||
*
|
||||
* WARNING: an authenticator should be used with one and ONLY ONE messaging
|
||||
* service at a time.
|
||||
*/
|
||||
class authenticator : public object
|
||||
{
|
||||
public:
|
||||
|
||||
/** Return the authentication identity (usually, this
|
||||
* is the username).
|
||||
*
|
||||
* @return username
|
||||
* @throw exceptions::no_auth_information if the information
|
||||
* could not be provided
|
||||
*/
|
||||
virtual const string getUsername() const = 0;
|
||||
|
||||
/** Return the password of the authentication identity.
|
||||
*
|
||||
* @return password
|
||||
* @throw exceptions::no_auth_information if the information
|
||||
* could not be provided
|
||||
*/
|
||||
virtual const string getPassword() const = 0;
|
||||
|
||||
/** Return the local host name of the machine.
|
||||
*
|
||||
* @return hostname
|
||||
* @throw exceptions::no_auth_information if the information
|
||||
* could not be provided
|
||||
*/
|
||||
virtual const string getHostname() const = 0;
|
||||
|
||||
/** Return the anonymous token (usually, this is the user's
|
||||
* email address).
|
||||
*
|
||||
* @return anonymous token
|
||||
* @throw exceptions::no_auth_information if the information
|
||||
* could not be provided
|
||||
*/
|
||||
virtual const string getAnonymousToken() const = 0;
|
||||
|
||||
/** Return the registered service name of the application
|
||||
* service (eg: "imap"). This can be used by GSSAPI or DIGEST-MD5
|
||||
* mechanisms with SASL.
|
||||
*
|
||||
* @return service name
|
||||
* @throw exceptions::no_auth_information if the information
|
||||
* could not be provided
|
||||
*/
|
||||
virtual const string getServiceName() const = 0;
|
||||
|
||||
/** Called by the messaging service to allow this authenticator to
|
||||
* know which service is currently using it. This is called just
|
||||
* before the service starts the authentication process.
|
||||
*
|
||||
* @param serv messaging service instance
|
||||
*/
|
||||
virtual void setService(ref <net::service> serv) = 0;
|
||||
};
|
||||
|
||||
|
||||
} // security
|
||||
} // vmime
|
||||
|
||||
|
||||
#endif // VMIME_SECURITY_AUTHENTICATOR_HPP_INCLUDED
|
||||
|
@ -17,44 +17,45 @@
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//
|
||||
|
||||
#ifndef VMIME_NET_DEFAULTAUTHENTICATOR_HPP_INCLUDED
|
||||
#define VMIME_NET_DEFAULTAUTHENTICATOR_HPP_INCLUDED
|
||||
#ifndef VMIME_SECURITY_DEFAULTAUTHENTICATOR_HPP_INCLUDED
|
||||
#define VMIME_SECURITY_DEFAULTAUTHENTICATOR_HPP_INCLUDED
|
||||
|
||||
|
||||
#include "vmime/net/authenticator.hpp"
|
||||
#include "vmime/propertySet.hpp"
|
||||
#include "vmime/security/authenticator.hpp"
|
||||
|
||||
|
||||
namespace vmime {
|
||||
namespace net {
|
||||
namespace security {
|
||||
|
||||
|
||||
class session;
|
||||
|
||||
|
||||
/** Default implementation for authenticator. It simply returns
|
||||
* the credentials set in the session properties (named 'username'
|
||||
* and 'password'). This is the default implementation used if
|
||||
* you do not write your own authenticator object.
|
||||
/** An authenticator that can provide some basic information by
|
||||
* reading in the messaging session properties.
|
||||
*/
|
||||
|
||||
class defaultAuthenticator : public authenticator
|
||||
{
|
||||
public:
|
||||
|
||||
defaultAuthenticator(weak_ref <session> session, const string& prefix);
|
||||
defaultAuthenticator();
|
||||
~defaultAuthenticator();
|
||||
|
||||
const authenticationInfos requestAuthInfos() const;
|
||||
const string getUsername() const;
|
||||
const string getPassword() const;
|
||||
const string getHostname() const;
|
||||
const string getAnonymousToken() const;
|
||||
const string getServiceName() const;
|
||||
|
||||
void setService(ref <net::service> serv);
|
||||
weak_ref <net::service> getService() const;
|
||||
|
||||
private:
|
||||
|
||||
weak_ref <session> m_session;
|
||||
const string m_prefix;
|
||||
weak_ref <net::service> m_service;
|
||||
};
|
||||
|
||||
|
||||
} // net
|
||||
} // security
|
||||
} // vmime
|
||||
|
||||
|
||||
#endif // VMIME_NET_DEFAULTAUTHENTICATOR_HPP_INCLUDED
|
||||
#endif // VMIME_SECURITY_DEFAULTAUTHENTICATOR_HPP_INCLUDED
|
||||
|
84
vmime/security/sasl/SASLAuthenticator.hpp
Normal file
84
vmime/security/sasl/SASLAuthenticator.hpp
Normal file
@ -0,0 +1,84 @@
|
||||
//
|
||||
// VMime library (http://www.vmime.org)
|
||||
// Copyright (C) 2002-2005 Vincent Richard <vincent@vincent-richard.net>
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#ifndef VMIME_SECURITY_SASL_SASLAUTHENTICATOR_HPP_INCLUDED
|
||||
#define VMIME_SECURITY_SASL_SASLAUTHENTICATOR_HPP_INCLUDED
|
||||
|
||||
|
||||
#include "vmime/types.hpp"
|
||||
|
||||
#include "vmime/security/authenticator.hpp"
|
||||
|
||||
|
||||
namespace vmime {
|
||||
namespace security {
|
||||
namespace sasl {
|
||||
|
||||
|
||||
class SASLMechanism;
|
||||
class SASLSession;
|
||||
|
||||
|
||||
/** SASL-aware authenticator.
|
||||
*
|
||||
* Usually, you should not inherit from this class, but instead from the
|
||||
* more convenient defaultSASLAuthenticator class.
|
||||
*/
|
||||
class SASLAuthenticator : public authenticator
|
||||
{
|
||||
public:
|
||||
|
||||
/** This method is called to allow the client to choose the
|
||||
* authentication mechanisms that will be used. By default,
|
||||
* the more secure mechanisms are chosen.
|
||||
*
|
||||
* @param available available mechanisms
|
||||
* @param suggested suggested mechanism (or NULL if the system
|
||||
* could not suggest a mechanism)
|
||||
* @return ordered list of mechanism to use among the available
|
||||
* mechanisms (from the first to try to the last)
|
||||
*/
|
||||
virtual const std::vector <ref <SASLMechanism> > getAcceptableMechanisms
|
||||
(const std::vector <ref <SASLMechanism> >& available,
|
||||
ref <SASLMechanism> suggested) const = 0;
|
||||
|
||||
/** Set the SASL session which is using this authenticator.
|
||||
*
|
||||
* @param sess SASL session
|
||||
*/
|
||||
virtual void setSASLSession(ref <SASLSession> sess) = 0;
|
||||
|
||||
/** Set the SASL mechanism which has been selected for the
|
||||
* SASL authentication process. This may be called several times
|
||||
* if the multiple mechanisms are tried by the service which
|
||||
* use this authentication.
|
||||
*
|
||||
* @param mech SASL mechanism
|
||||
*/
|
||||
virtual void setSASLMechanism(ref <SASLMechanism> mech) = 0;
|
||||
};
|
||||
|
||||
|
||||
} // sasl
|
||||
} // security
|
||||
} // vmime
|
||||
|
||||
|
||||
#endif // VMIME_SECURITY_SASL_SASLAUTHENTICATOR_HPP_INCLUDED
|
||||
|
116
vmime/security/sasl/SASLContext.hpp
Normal file
116
vmime/security/sasl/SASLContext.hpp
Normal file
@ -0,0 +1,116 @@
|
||||
//
|
||||
// VMime library (http://www.vmime.org)
|
||||
// Copyright (C) 2002-2005 Vincent Richard <vincent@vincent-richard.net>
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#ifndef VMIME_SECURITY_SASL_SASLCONTEXT_HPP_INCLUDED
|
||||
#define VMIME_SECURITY_SASL_SASLCONTEXT_HPP_INCLUDED
|
||||
|
||||
|
||||
#include "vmime/types.hpp"
|
||||
|
||||
#include "vmime/security/sasl/SASLSession.hpp"
|
||||
#include "vmime/security/sasl/SASLMechanismFactory.hpp"
|
||||
|
||||
|
||||
namespace vmime {
|
||||
namespace security {
|
||||
namespace sasl {
|
||||
|
||||
|
||||
/** An SASL client context.
|
||||
*/
|
||||
class SASLContext : public object
|
||||
{
|
||||
friend class SASLSession;
|
||||
friend class builtinSASLMechanism;
|
||||
|
||||
public:
|
||||
|
||||
~SASLContext();
|
||||
|
||||
/** Construct and initialize a new SASL context.
|
||||
*/
|
||||
SASLContext();
|
||||
|
||||
/** Create and initialize a new SASL session.
|
||||
*
|
||||
* @param serviceName name of the service which will use the session
|
||||
* @param auth authenticator object to use during the session
|
||||
* @param mech SASL mechanism
|
||||
* @return a new SASL session
|
||||
*/
|
||||
ref <SASLSession> createSession
|
||||
(const string& serviceName,
|
||||
ref <authenticator> auth, ref <SASLMechanism> mech);
|
||||
|
||||
/** Create an instance of an SASL mechanism.
|
||||
*
|
||||
* @param name mechanism name
|
||||
* @return a new instance of the specified SASL mechanism
|
||||
* @throw exceptions::no_such_mechanism if no mechanism is
|
||||
* registered for the specified name
|
||||
*/
|
||||
ref <SASLMechanism> createMechanism(const string& name);
|
||||
|
||||
/** Suggests an SASL mechanism among a set of mechanisms
|
||||
* supported by the server.
|
||||
*
|
||||
* @param mechs list of mechanisms
|
||||
* @return suggested mechanism (usually the safest mechanism
|
||||
* supported by both the client and the server)
|
||||
*/
|
||||
ref <SASLMechanism> suggestMechanism
|
||||
(const std::vector <ref <SASLMechanism> >& mechs);
|
||||
|
||||
/** Helper function for decoding Base64-encoded challenge.
|
||||
*
|
||||
* @param input input buffer
|
||||
* @param output output buffer
|
||||
* @param outputLen length of output buffer
|
||||
*/
|
||||
void decodeB64(const string& input, byte** output, int* outputLen);
|
||||
|
||||
/** Helper function for encoding challenge in Base64.
|
||||
*
|
||||
* @param input input buffer
|
||||
* @param inputLen length of input buffer
|
||||
* @return Base64-encoded challenge
|
||||
*/
|
||||
const string encodeB64(const byte* input, const int inputLen);
|
||||
|
||||
private:
|
||||
|
||||
static const string getErrorMessage(const string& fname, const int code);
|
||||
|
||||
|
||||
#ifdef GSASL_VERSION
|
||||
Gsasl* m_gsaslContext;
|
||||
#else
|
||||
void* m_gsaslContext;
|
||||
#endif // GSASL_VERSION
|
||||
|
||||
};
|
||||
|
||||
|
||||
} // sasl
|
||||
} // security
|
||||
} // vmime
|
||||
|
||||
|
||||
#endif // VMIME_SECURITY_SASL_SASLCONTEXT_HPP_INCLUDED
|
||||
|
119
vmime/security/sasl/SASLMechanism.hpp
Normal file
119
vmime/security/sasl/SASLMechanism.hpp
Normal file
@ -0,0 +1,119 @@
|
||||
//
|
||||
// VMime library (http://www.vmime.org)
|
||||
// Copyright (C) 2002-2005 Vincent Richard <vincent@vincent-richard.net>
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#ifndef VMIME_SECURITY_SASL_SASLMECHANISM_HPP_INCLUDED
|
||||
#define VMIME_SECURITY_SASL_SASLMECHANISM_HPP_INCLUDED
|
||||
|
||||
|
||||
#include "vmime/types.hpp"
|
||||
|
||||
|
||||
namespace vmime {
|
||||
namespace security {
|
||||
namespace sasl {
|
||||
|
||||
|
||||
class SASLSession;
|
||||
|
||||
|
||||
/** An SASL mechanism.
|
||||
*/
|
||||
class SASLMechanism : public object
|
||||
{
|
||||
public:
|
||||
|
||||
/** Return the name of this mechanism.
|
||||
*
|
||||
* @return mechanism name
|
||||
*/
|
||||
virtual const string getName() const = 0;
|
||||
|
||||
/** Perform one step of SASL authentication. Accept data from the
|
||||
* server (challenge), process it and return data to be returned
|
||||
* in response to the server.
|
||||
*
|
||||
* @param sess SASL session
|
||||
* @param challenge challenge sent from the server
|
||||
* @param challengeLen length of challenge
|
||||
* @param response response to send to the server (allocated by
|
||||
* this function, free with delete[])
|
||||
* @param responseLen length of response buffer
|
||||
* @return true if authentication terminated successfully, or
|
||||
* false if the authentication process should continue
|
||||
* @throw exceptions::sasl_exception if an error occured during
|
||||
* authentication (in this case, the values in 'response' and
|
||||
* 'responseLen' are undetermined)
|
||||
*/
|
||||
virtual const bool step
|
||||
(ref <SASLSession> sess,
|
||||
const byte* challenge, const int challengeLen,
|
||||
byte** response, int* responseLen) = 0;
|
||||
|
||||
/** Check whether authentication has completed. If false, more
|
||||
* calls to evaluateChallenge() are needed to complete the
|
||||
* authentication process).
|
||||
*
|
||||
* @return true if the authentication has finished, or false
|
||||
* otherwise
|
||||
*/
|
||||
virtual const bool isComplete() const = 0;
|
||||
|
||||
/** Encode data according to negotiated SASL mechanism. This
|
||||
* might mean that data is integrity or privacy protected.
|
||||
*
|
||||
* @param sess SASL session
|
||||
* @param input input buffer
|
||||
* @param inputLen length of input buffer
|
||||
* @param output output buffer (allocated bu the function,
|
||||
* free with delete[])
|
||||
* @param outputLen length of output buffer
|
||||
* @throw exceptions::sasl_exception if an error occured during
|
||||
* the encoding of data (in this case, the values in 'output' and
|
||||
* 'outputLen' are undetermined)
|
||||
*/
|
||||
virtual void encode(ref <SASLSession> sess,
|
||||
const byte* input, const int inputLen,
|
||||
byte** output, int* outputLen) = 0;
|
||||
|
||||
/** Decode data according to negotiated SASL mechanism. This
|
||||
* might mean that data is integrity or privacy protected.
|
||||
*
|
||||
* @param sess SASL session
|
||||
* @param input input buffer
|
||||
* @param inputLen length of input buffer
|
||||
* @param output output buffer (allocated bu the function,
|
||||
* free with delete[])
|
||||
* @param outputLen length of output buffer
|
||||
* @throw exceptions::sasl_exception if an error occured during
|
||||
* the encoding of data (in this case, the values in 'output' and
|
||||
* 'outputLen' are undetermined)
|
||||
*/
|
||||
virtual void decode(ref <SASLSession> sess,
|
||||
const byte* input, const int inputLen,
|
||||
byte** output, int* outputLen) = 0;
|
||||
};
|
||||
|
||||
|
||||
} // sasl
|
||||
} // security
|
||||
} // vmime
|
||||
|
||||
|
||||
#endif // VMIME_SECURITY_SASL_SASLMECHANISM_HPP_INCLUDED
|
||||
|
131
vmime/security/sasl/SASLMechanismFactory.hpp
Normal file
131
vmime/security/sasl/SASLMechanismFactory.hpp
Normal file
@ -0,0 +1,131 @@
|
||||
//
|
||||
// VMime library (http://www.vmime.org)
|
||||
// Copyright (C) 2002-2005 Vincent Richard <vincent@vincent-richard.net>
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#ifndef VMIME_SECURITY_SASL_SASLMECHANISMFACTORY_HPP_INCLUDED
|
||||
#define VMIME_SECURITY_SASL_SASLMECHANISMFACTORY_HPP_INCLUDED
|
||||
|
||||
|
||||
#include "vmime/types.hpp"
|
||||
#include "vmime/base.hpp"
|
||||
|
||||
#include "vmime/security/sasl/SASLMechanism.hpp"
|
||||
|
||||
#include <map>
|
||||
|
||||
|
||||
namespace vmime {
|
||||
namespace security {
|
||||
namespace sasl {
|
||||
|
||||
|
||||
class SASLContext;
|
||||
|
||||
|
||||
/** Constructs SASL mechanism objects.
|
||||
*/
|
||||
class SASLMechanismFactory : public object
|
||||
{
|
||||
private:
|
||||
|
||||
SASLMechanismFactory();
|
||||
~SASLMechanismFactory();
|
||||
|
||||
|
||||
class registeredMechanism : public object
|
||||
{
|
||||
public:
|
||||
|
||||
virtual ref <SASLMechanism> create
|
||||
(ref <SASLContext> ctx, const string& name) = 0;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class registeredMechanismImpl : public registeredMechanism
|
||||
{
|
||||
public:
|
||||
|
||||
ref <SASLMechanism> create(ref <SASLContext> ctx, const string& name)
|
||||
{
|
||||
return vmime::create <T>(ctx, name);
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::map <string, ref <registeredMechanism> > MapType;
|
||||
MapType m_mechs;
|
||||
|
||||
public:
|
||||
|
||||
static SASLMechanismFactory* getInstance();
|
||||
|
||||
/** Register a mechanism into this factory, so that subsequent
|
||||
* calls to create return a valid object for this mechanism.
|
||||
*
|
||||
* @param name mechanism name
|
||||
*/
|
||||
template <typename MECH_CLASS>
|
||||
void registerMechanism(const string& name)
|
||||
{
|
||||
m_mechs.insert(MapType::value_type(name,
|
||||
vmime::create <registeredMechanismImpl <MECH_CLASS> >()));
|
||||
}
|
||||
|
||||
/** Create a mechanism object given its name.
|
||||
*
|
||||
* @param ctx SASL context
|
||||
* @param name mechanism name
|
||||
* @return a new mechanism object
|
||||
* @throw exceptions::no_such_mechanism if no mechanism is
|
||||
* registered for the specified name
|
||||
*/
|
||||
ref <SASLMechanism> create(ref <SASLContext> ctx, const string& name);
|
||||
|
||||
/** Return a list of supported mechanisms. This includes mechanisms
|
||||
* registered using registerMechanism() as well as the ones that
|
||||
* are built-in.
|
||||
*
|
||||
* @return list of supported mechanisms
|
||||
*/
|
||||
const std::vector <string> getSupportedMechanisms() const;
|
||||
|
||||
/** Test whether an authentication mechanism is supported.
|
||||
*
|
||||
* @param name mechanism name
|
||||
* @return true if the specified mechanism is supported,
|
||||
* false otherwise
|
||||
*/
|
||||
const bool isMechanismSupported(const string& name) const;
|
||||
|
||||
private:
|
||||
|
||||
#ifdef GSASL_VERSION
|
||||
Gsasl* m_gsaslContext;
|
||||
#else
|
||||
void* m_gsaslContext;
|
||||
#endif // GSASL_VERSION
|
||||
|
||||
};
|
||||
|
||||
|
||||
} // sasl
|
||||
} // security
|
||||
} // vmime
|
||||
|
||||
|
||||
#endif // VMIME_SECURITY_SASL_SASLMECHANISMFACTORY_HPP_INCLUDED
|
||||
|
150
vmime/security/sasl/SASLSession.hpp
Normal file
150
vmime/security/sasl/SASLSession.hpp
Normal file
@ -0,0 +1,150 @@
|
||||
//
|
||||
// VMime library (http://www.vmime.org)
|
||||
// Copyright (C) 2002-2005 Vincent Richard <vincent@vincent-richard.net>
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#ifndef VMIME_SECURITY_SASL_SASLSESSION_HPP_INCLUDED
|
||||
#define VMIME_SECURITY_SASL_SASLSESSION_HPP_INCLUDED
|
||||
|
||||
|
||||
#include "vmime/types.hpp"
|
||||
|
||||
#include "vmime/security/sasl/SASLAuthenticator.hpp"
|
||||
#include "vmime/security/sasl/SASLMechanism.hpp"
|
||||
#include "vmime/security/sasl/SASLSocket.hpp"
|
||||
|
||||
|
||||
namespace vmime {
|
||||
namespace security {
|
||||
namespace sasl {
|
||||
|
||||
|
||||
class SASLContext;
|
||||
|
||||
|
||||
/** An SASL client session.
|
||||
*/
|
||||
class SASLSession : public object
|
||||
{
|
||||
friend class builtinSASLMechanism;
|
||||
friend class SASLSocket;
|
||||
|
||||
public:
|
||||
|
||||
~SASLSession();
|
||||
|
||||
/** Construct a new SASL session.
|
||||
*
|
||||
* @param serviceName name of the service using this session
|
||||
* @param ctx SASL context
|
||||
* @param auth authenticator to use for this session
|
||||
* @param mech SASL mechanism
|
||||
*/
|
||||
SASLSession(const string& serviceName, ref <SASLContext> ctx,
|
||||
ref <authenticator> auth, ref <SASLMechanism> mech);
|
||||
|
||||
/** Initialize this SASL session. This must be called before
|
||||
* calling any other method on this object (except accessors).
|
||||
*/
|
||||
void init();
|
||||
|
||||
/** Return the authenticator used for this session. This is the
|
||||
* authenticator which has been previously set with a call to
|
||||
* setAuthenticator().
|
||||
*
|
||||
* @return authenticator object
|
||||
*/
|
||||
ref <authenticator> getAuthenticator();
|
||||
|
||||
/** Return the mechanism used for this session.
|
||||
*
|
||||
* @return SASL mechanism
|
||||
*/
|
||||
ref <SASLMechanism> getMechanism();
|
||||
|
||||
/** Return the SASL context.
|
||||
*
|
||||
* @return SASL context
|
||||
*/
|
||||
ref <SASLContext> getContext();
|
||||
|
||||
/** Perform one step of SASL authentication. Accept data from the
|
||||
* server (challenge), process it and return data to be returned
|
||||
* in response to the server.
|
||||
*
|
||||
* @param challenge challenge sent from the server
|
||||
* @param challengeLen length of challenge
|
||||
* @param response response to send to the server (allocated by
|
||||
* this function, free with delete[])
|
||||
* @param responseLen length of response buffer
|
||||
* @return true if authentication terminated successfully, or
|
||||
* false if the authentication process should continue
|
||||
* @throw exceptions::sasl_exception if an error occured during
|
||||
* authentication (in this case, the values in 'response' and
|
||||
* 'responseLen' are undetermined)
|
||||
*/
|
||||
const bool evaluateChallenge
|
||||
(const byte* challenge, const int challengeLen,
|
||||
byte** response, int* responseLen);
|
||||
|
||||
/** Return a socket in which transmitted data is integrity
|
||||
* and/or privacy protected, depending on the QOP (Quality of
|
||||
* Protection) negotiated during the SASL authentication.
|
||||
*
|
||||
* @param sok socket to wrap
|
||||
* @return secured socket
|
||||
*/
|
||||
ref <net::socket> getSecuredSocket(ref <net::socket> sok);
|
||||
|
||||
/** Return the name of the service which is using this
|
||||
* SASL session (eg. "imap"). This value should be returned
|
||||
* by the authenticator when INFO_SERVICE is requested.
|
||||
*
|
||||
* @return service name
|
||||
*/
|
||||
const string getServiceName() const;
|
||||
|
||||
private:
|
||||
|
||||
const string m_serviceName;
|
||||
|
||||
ref <SASLContext> m_context;
|
||||
ref <authenticator> m_auth;
|
||||
ref <SASLMechanism> m_mech;
|
||||
|
||||
#ifdef GSASL_VERSION
|
||||
Gsasl* m_gsaslContext;
|
||||
Gsasl_session* m_gsaslSession;
|
||||
|
||||
static int gsaslCallback(Gsasl* ctx, Gsasl_session* sctx, Gsasl_property prop);
|
||||
#else
|
||||
void* m_gsaslContext;
|
||||
void* m_gsaslSession;
|
||||
|
||||
static int gsaslCallback(void* ctx, void* sctx, int prop);
|
||||
#endif // GSASL_VERSION
|
||||
|
||||
};
|
||||
|
||||
|
||||
} // sasl
|
||||
} // security
|
||||
} // vmime
|
||||
|
||||
|
||||
#endif // VMIME_SECURITY_SASL_SASLSESSION_HPP_INCLUDED
|
||||
|
@ -17,48 +17,60 @@
|
||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
//
|
||||
|
||||
#ifndef VMIME_NET_AUTHENTICATIONINFOS_HPP_INCLUDED
|
||||
#define VMIME_NET_AUTHENTICATIONINFOS_HPP_INCLUDED
|
||||
#ifndef VMIME_SECURITY_SASL_SASLSOCKET_HPP_INCLUDED
|
||||
#define VMIME_SECURITY_SASL_SASLSOCKET_HPP_INCLUDED
|
||||
|
||||
|
||||
#include "vmime/types.hpp"
|
||||
|
||||
#include "vmime/net/socket.hpp"
|
||||
|
||||
|
||||
namespace vmime {
|
||||
namespace net {
|
||||
namespace security {
|
||||
namespace sasl {
|
||||
|
||||
|
||||
/** This class encapsulates user credentials.
|
||||
class SASLSession;
|
||||
|
||||
|
||||
/** A socket which provides data integrity and/or privacy protection.
|
||||
*/
|
||||
|
||||
class authenticationInfos : public object
|
||||
class SASLSocket : public net::socket
|
||||
{
|
||||
public:
|
||||
|
||||
authenticationInfos(const string& username, const string& password);
|
||||
authenticationInfos(const authenticationInfos& infos);
|
||||
SASLSocket(ref <SASLSession> sess, ref <net::socket> wrapped);
|
||||
~SASLSocket();
|
||||
|
||||
/** Return the user account name.
|
||||
*
|
||||
* @return account name
|
||||
*/
|
||||
const string& getUsername() const;
|
||||
void connect(const string& address, const port_t port);
|
||||
void disconnect();
|
||||
|
||||
/** Return the user account password.
|
||||
*
|
||||
* @return account password
|
||||
*/
|
||||
const string& getPassword() const;
|
||||
const bool isConnected() const;
|
||||
|
||||
void receive(string& buffer);
|
||||
const int receiveRaw(char* buffer, const int count);
|
||||
|
||||
void send(const string& buffer);
|
||||
void sendRaw(const char* buffer, const int count);
|
||||
|
||||
private:
|
||||
|
||||
string m_username;
|
||||
string m_password;
|
||||
ref <SASLSession> m_session;
|
||||
ref <net::socket> m_wrapped;
|
||||
|
||||
byte* m_pendingBuffer;
|
||||
int m_pendingPos;
|
||||
int m_pendingLen;
|
||||
|
||||
char m_recvBuffer[65536];
|
||||
};
|
||||
|
||||
|
||||
} // net
|
||||
} // sasl
|
||||
} // security
|
||||
} // vmime
|
||||
|
||||
|
||||
#endif // VMIME_NET_AUTHENTICATIONINFOS_HPP_INCLUDED
|
||||
#endif // VMIME_SECURITY_SASL_SASLSOCKET_HPP_INCLUDED
|
||||
|
82
vmime/security/sasl/builtinSASLMechanism.hpp
Normal file
82
vmime/security/sasl/builtinSASLMechanism.hpp
Normal file
@ -0,0 +1,82 @@
|
||||
//
|
||||
// VMime library (http://www.vmime.org)
|
||||
// Copyright (C) 2002-2005 Vincent Richard <vincent@vincent-richard.net>
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#ifndef VMIME_SECURITY_SASL_BUILTINSASLMECHANISM_HPP_INCLUDED
|
||||
#define VMIME_SECURITY_SASL_BUILTINSASLMECHANISM_HPP_INCLUDED
|
||||
|
||||
|
||||
#include "vmime/security/sasl/SASLMechanism.hpp"
|
||||
|
||||
|
||||
namespace vmime {
|
||||
namespace security {
|
||||
namespace sasl {
|
||||
|
||||
|
||||
class SASLContext;
|
||||
|
||||
|
||||
/** A built-in authentication mechanism that relies on
|
||||
* the GNU SASL library.
|
||||
*/
|
||||
class builtinSASLMechanism : public SASLMechanism
|
||||
{
|
||||
public:
|
||||
|
||||
builtinSASLMechanism(ref <SASLContext> ctx, const string& name);
|
||||
~builtinSASLMechanism();
|
||||
|
||||
|
||||
const string getName() const;
|
||||
|
||||
const bool step
|
||||
(ref <SASLSession> sess,
|
||||
const byte* challenge, const int challengeLen,
|
||||
byte** response, int* responseLen);
|
||||
|
||||
const bool isComplete() const;
|
||||
|
||||
void encode(ref <SASLSession> sess,
|
||||
const byte* input, const int inputLen,
|
||||
byte** output, int* outputLen);
|
||||
|
||||
void decode(ref <SASLSession> sess,
|
||||
const byte* input, const int inputLen,
|
||||
byte** output, int* outputLen);
|
||||
|
||||
private:
|
||||
|
||||
/** SASL context */
|
||||
ref <SASLContext> m_context;
|
||||
|
||||
/** Mechanism name */
|
||||
const string m_name;
|
||||
|
||||
/** Authentication process status. */
|
||||
bool m_complete;
|
||||
};
|
||||
|
||||
|
||||
} // sasl
|
||||
} // security
|
||||
} // vmime
|
||||
|
||||
|
||||
#endif // VMIME_SECURITY_SASL_BUILTINSASLMECHANISM_HPP_INCLUDED
|
||||
|
80
vmime/security/sasl/defaultSASLAuthenticator.hpp
Normal file
80
vmime/security/sasl/defaultSASLAuthenticator.hpp
Normal file
@ -0,0 +1,80 @@
|
||||
//
|
||||
// VMime library (http://www.vmime.org)
|
||||
// Copyright (C) 2002-2005 Vincent Richard <vincent@vincent-richard.net>
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
#ifndef VMIME_SECURITY_SASL_DEFAULTSASLAUTHENTICATOR_HPP_INCLUDED
|
||||
#define VMIME_SECURITY_SASL_DEFAULTSASLAUTHENTICATOR_HPP_INCLUDED
|
||||
|
||||
|
||||
#include "vmime/security/sasl/SASLAuthenticator.hpp"
|
||||
#include "vmime/security/defaultAuthenticator.hpp"
|
||||
|
||||
|
||||
namespace vmime {
|
||||
namespace security {
|
||||
namespace sasl {
|
||||
|
||||
|
||||
/** An authenticator that is capable of providing information
|
||||
* for simple authentication mechanisms (username and password).
|
||||
*/
|
||||
class defaultSASLAuthenticator : public SASLAuthenticator
|
||||
{
|
||||
public:
|
||||
|
||||
defaultSASLAuthenticator();
|
||||
~defaultSASLAuthenticator();
|
||||
|
||||
const std::vector <ref <SASLMechanism> > getAcceptableMechanisms
|
||||
(const std::vector <ref <SASLMechanism> >& available,
|
||||
ref <SASLMechanism> suggested) const;
|
||||
|
||||
const string getUsername() const;
|
||||
const string getPassword() const;
|
||||
const string getHostname() const;
|
||||
const string getAnonymousToken() const;
|
||||
const string getServiceName() const;
|
||||
|
||||
void setService(ref <net::service> serv);
|
||||
weak_ref <net::service> getService() const;
|
||||
|
||||
void setSASLSession(ref <SASLSession> sess);
|
||||
ref <SASLSession> getSASLSession() const;
|
||||
|
||||
void setSASLMechanism(ref <SASLMechanism> mech);
|
||||
ref <SASLMechanism> getSASLMechanism() const;
|
||||
|
||||
private:
|
||||
|
||||
defaultAuthenticator m_default;
|
||||
|
||||
|
||||
weak_ref <net::service> m_service;
|
||||
|
||||
ref <SASLSession> m_saslSession;
|
||||
ref <SASLMechanism> m_saslMech;
|
||||
};
|
||||
|
||||
|
||||
} // sasl
|
||||
} // security
|
||||
} // vmime
|
||||
|
||||
|
||||
#endif // VMIME_SECURITY_SASL_DEFAULTSASLAUTHENTICATOR_HPP_INCLUDED
|
||||
|
@ -23,6 +23,7 @@
|
||||
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "vmime/config.hpp"
|
||||
#include "vmime/utility/smartPtr.hpp"
|
||||
@ -40,6 +41,7 @@ namespace vmime
|
||||
typedef int char_t;
|
||||
|
||||
typedef vmime_uint8 byte;
|
||||
typedef std::vector <byte> byteArray;
|
||||
|
||||
// Some aliases
|
||||
namespace utils = utility;
|
||||
|
@ -326,6 +326,29 @@ private:
|
||||
};
|
||||
|
||||
|
||||
/** An adapter class for reading from an array of bytes.
|
||||
*/
|
||||
|
||||
class inputStreamByteBufferAdapter : public inputStream
|
||||
{
|
||||
public:
|
||||
|
||||
inputStreamByteBufferAdapter(const byte* buffer, size_type length);
|
||||
|
||||
const bool eof() const;
|
||||
void reset();
|
||||
const size_type read(value_type* const data, const size_type count);
|
||||
const size_type skip(const size_type count);
|
||||
|
||||
private:
|
||||
|
||||
const byte* m_buffer;
|
||||
const size_type m_length;
|
||||
|
||||
size_type m_pos;
|
||||
};
|
||||
|
||||
|
||||
#if VMIME_HAVE_MESSAGING_FEATURES
|
||||
|
||||
|
||||
|
@ -86,6 +86,21 @@
|
||||
#include "vmime/utility/datetimeUtils.hpp"
|
||||
#include "vmime/utility/filteredStream.hpp"
|
||||
|
||||
// Security
|
||||
#include "vmime/security/authenticator.hpp"
|
||||
#include "vmime/security/defaultAuthenticator.hpp"
|
||||
|
||||
// Security/digest
|
||||
#include "vmime/security/digest/messageDigestFactory.hpp"
|
||||
|
||||
// Security/SASL
|
||||
#if VMIME_HAVE_SASL_SUPPORT
|
||||
#include "vmime/security/sasl/SASLAuthenticator.hpp"
|
||||
#include "vmime/security/sasl/defaultSASLAuthenticator.hpp"
|
||||
#include "vmime/security/sasl/SASLContext.hpp"
|
||||
#include "vmime/security/sasl/SASLSession.hpp"
|
||||
#endif // VMIME_HAVE_SASL_SUPPORT
|
||||
|
||||
// Messaging features
|
||||
#if VMIME_HAVE_MESSAGING_FEATURES
|
||||
#include "vmime/net/socket.hpp"
|
||||
@ -95,9 +110,6 @@
|
||||
#include "vmime/net/transport.hpp"
|
||||
|
||||
#include "vmime/net/session.hpp"
|
||||
#include "vmime/net/authenticator.hpp"
|
||||
#include "vmime/net/defaultAuthenticator.hpp"
|
||||
#include "vmime/net/simpleAuthenticator.hpp"
|
||||
|
||||
#include "vmime/net/folder.hpp"
|
||||
#include "vmime/net/message.hpp"
|
||||
|
Loading…
Reference in New Issue
Block a user