SASL authentication.
This commit is contained in:
parent
e51fb0c931
commit
0edaa87860
@ -2,6 +2,11 @@
|
|||||||
VERSION 0.7.2cvs
|
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>
|
2005-09-06 Vincent Richard <vincent@vincent-richard.net>
|
||||||
|
|
||||||
* Created 'vmime::security' and 'vmime::security::digest' namespaces.
|
* Created 'vmime::security' and 'vmime::security::digest' namespaces.
|
||||||
|
136
SConstruct
136
SConstruct
@ -170,12 +170,26 @@ libvmime_sources = [
|
|||||||
# =============================== Misc ===============================
|
# =============================== Misc ===============================
|
||||||
'misc/importanceHelper.cpp', 'misc/importanceHelper.hpp',
|
'misc/importanceHelper.cpp', 'misc/importanceHelper.hpp',
|
||||||
# ============================= Security =============================
|
# ============================= Security =============================
|
||||||
|
'security/authenticator.hpp',
|
||||||
|
'security/defaultAuthenticator.cpp', 'security/defaultAuthenticator.hpp',
|
||||||
|
# -- digest
|
||||||
'security/digest/messageDigest.cpp', 'security/digest/messageDigest.hpp',
|
'security/digest/messageDigest.cpp', 'security/digest/messageDigest.hpp',
|
||||||
'security/digest/messageDigestFactory.cpp', 'security/digest/messageDigestFactory.hpp',
|
'security/digest/messageDigestFactory.cpp', 'security/digest/messageDigestFactory.hpp',
|
||||||
'security/digest/md5/md5MessageDigest.cpp', 'security/digest/md5/md5MessageDigest.hpp',
|
'security/digest/md5/md5MessageDigest.cpp', 'security/digest/md5/md5MessageDigest.hpp',
|
||||||
'security/digest/sha1/sha1MessageDigest.cpp', 'security/digest/sha1/sha1MessageDigest.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 = [
|
libvmime_examples_sources = [
|
||||||
'examples/README',
|
'examples/README',
|
||||||
# 'examples/Makefile.am', # not generated
|
# 'examples/Makefile.am', # not generated
|
||||||
@ -190,11 +204,8 @@ libvmime_examples_sources = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
libvmime_messaging_sources = [
|
libvmime_messaging_sources = [
|
||||||
'net/authenticator.cpp', 'net/authenticator.hpp',
|
|
||||||
'net/authenticationInfos.cpp', 'net/authenticationInfos.hpp',
|
|
||||||
'net/authHelper.cpp', 'net/authHelper.hpp',
|
'net/authHelper.cpp', 'net/authHelper.hpp',
|
||||||
'net/builtinServices.inl',
|
'net/builtinServices.inl',
|
||||||
'net/defaultAuthenticator.cpp', 'net/defaultAuthenticator.hpp',
|
|
||||||
'net/events.cpp', 'net/events.hpp',
|
'net/events.cpp', 'net/events.hpp',
|
||||||
'net/folder.cpp', 'net/folder.hpp',
|
'net/folder.cpp', 'net/folder.hpp',
|
||||||
'net/message.cpp', 'net/message.hpp',
|
'net/message.cpp', 'net/message.hpp',
|
||||||
@ -202,7 +213,6 @@ libvmime_messaging_sources = [
|
|||||||
'net/serviceFactory.cpp', 'net/serviceFactory.hpp',
|
'net/serviceFactory.cpp', 'net/serviceFactory.hpp',
|
||||||
'net/serviceInfos.cpp', 'net/serviceInfos.hpp',
|
'net/serviceInfos.cpp', 'net/serviceInfos.hpp',
|
||||||
'net/session.cpp', 'net/session.hpp',
|
'net/session.cpp', 'net/session.hpp',
|
||||||
'net/simpleAuthenticator.cpp', 'net/simpleAuthenticator.hpp',
|
|
||||||
'net/socket.hpp',
|
'net/socket.hpp',
|
||||||
'net/store.hpp',
|
'net/store.hpp',
|
||||||
'net/timeoutHandler.hpp',
|
'net/timeoutHandler.hpp',
|
||||||
@ -357,7 +367,7 @@ libvmime_autotools = [
|
|||||||
'vmime/Makefile.in'
|
'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)):
|
for i in range(len(libvmime_all_sources)):
|
||||||
f = libvmime_all_sources[i]
|
f = libvmime_all_sources[i]
|
||||||
@ -463,6 +473,14 @@ opts.AddOptions(
|
|||||||
+ 'Currently available platform handlers: posix.',
|
+ 'Currently available platform handlers: posix.',
|
||||||
'"posix"'
|
'"posix"'
|
||||||
),
|
),
|
||||||
|
EnumOption(
|
||||||
|
'with_sasl',
|
||||||
|
'Enable SASL support (requires GNU SASL library)',
|
||||||
|
'yes',
|
||||||
|
allowed_values = ('yes', 'no'),
|
||||||
|
map = { },
|
||||||
|
ignorecase = 1
|
||||||
|
),
|
||||||
(
|
(
|
||||||
'sendmail_path',
|
'sendmail_path',
|
||||||
'Specifies the path to sendmail.',
|
'Specifies the path to sendmail.',
|
||||||
@ -554,6 +572,8 @@ else:
|
|||||||
|
|
||||||
#env.Append(LIBS = ['additional-lib-here'])
|
#env.Append(LIBS = ['additional-lib-here'])
|
||||||
|
|
||||||
|
env.ParseConfig('pkg-config --cflags --libs libgsasl')
|
||||||
|
|
||||||
# Generate help text for command line options
|
# Generate help text for command line options
|
||||||
Help(opts.GenerateHelpText(env))
|
Help(opts.GenerateHelpText(env))
|
||||||
|
|
||||||
@ -642,6 +662,7 @@ if env['with_messaging'] == 'yes':
|
|||||||
print " * protocols : " + env['with_messaging_protocols']
|
print " * protocols : " + env['with_messaging_protocols']
|
||||||
print "File-system support : " + env['with_filesystem']
|
print "File-system support : " + env['with_filesystem']
|
||||||
print "Platform handlers : " + env['with_platforms']
|
print "Platform handlers : " + env['with_platforms']
|
||||||
|
print "SASL support : " + env['with_sasl']
|
||||||
|
|
||||||
if IsProtocolSupported(messaging_protocols, 'sendmail'):
|
if IsProtocolSupported(messaging_protocols, 'sendmail'):
|
||||||
print "Sendmail path : " + env['sendmail_path']
|
print "Sendmail path : " + env['sendmail_path']
|
||||||
@ -727,6 +748,12 @@ if env['with_filesystem'] == 'yes':
|
|||||||
else:
|
else:
|
||||||
config_hpp.write('#define VMIME_HAVE_FILESYSTEM_FEATURES 0\n')
|
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')
|
config_hpp.write('// -- Messaging support\n')
|
||||||
if env['with_messaging'] == 'yes':
|
if env['with_messaging'] == 'yes':
|
||||||
config_hpp.write('#define VMIME_HAVE_MESSAGING_FEATURES 1\n')
|
config_hpp.write('#define VMIME_HAVE_MESSAGING_FEATURES 1\n')
|
||||||
@ -800,6 +827,11 @@ if env['with_messaging'] == 'yes':
|
|||||||
for file in protosrc[1]:
|
for file in protosrc[1]:
|
||||||
libvmime_sel_sources.append(file)
|
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
|
# -- platform handlers
|
||||||
for platform in platforms:
|
for platform in platforms:
|
||||||
files = libvmime_platforms_sources[platform]
|
files = libvmime_platforms_sources[platform]
|
||||||
@ -852,12 +884,13 @@ Default(libVmime)
|
|||||||
# Tests
|
# Tests
|
||||||
if env['build_tests'] == 'yes':
|
if env['build_tests'] == 'yes':
|
||||||
if env['debug'] == 'yes':
|
if env['debug'] == 'yes':
|
||||||
|
env = env.Copy()
|
||||||
|
env.Append(LIBS = ['cppunit', 'dl', packageVersionedGenericName + '-debug'])
|
||||||
|
env.Append(LIBPATH=['.'])
|
||||||
Default(
|
Default(
|
||||||
env.Program(
|
env.Program(
|
||||||
target = 'run-tests',
|
target = 'run-tests',
|
||||||
source = libvmimetest_sources,
|
source = libvmimetest_sources
|
||||||
LIBS=['cppunit', 'dl', packageVersionedGenericName + '-debug'],
|
|
||||||
LIBPATH=['.']
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
@ -888,6 +921,13 @@ env.Install(includeDir, 'vmime/config.hpp')
|
|||||||
# Pkg-config support
|
# Pkg-config support
|
||||||
vmime_pc = open(packageVersionedGenericName + ".pc", 'w')
|
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("prefix=" + env['prefix'] + "\n")
|
||||||
vmime_pc.write("exec_prefix=" + env['prefix'] + "\n")
|
vmime_pc.write("exec_prefix=" + env['prefix'] + "\n")
|
||||||
vmime_pc.write("libdir=" + env['prefix'] + "/lib\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("Name: " + packageRealName + "\n")
|
||||||
vmime_pc.write("Description: " + packageDescription + "\n")
|
vmime_pc.write("Description: " + packageDescription + "\n")
|
||||||
vmime_pc.write("Version: " + packageVersion + "\n")
|
vmime_pc.write("Version: " + packageVersion + "\n")
|
||||||
vmime_pc.write("Requires:\n")
|
vmime_pc.write("Requires: " + vmime_pc_requires + "\n")
|
||||||
vmime_pc.write("Libs: -L${libdir} -l" + packageVersionedGenericName + "\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}/" + packageVersionedGenericName + "\n")
|
||||||
vmime_pc.write("Cflags: -I${includedir}/" + "\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("Name: @GENERIC_LIBRARY_NAME@\n")
|
||||||
vmime_pc_in.write("Description: " + packageDescription + "\n")
|
vmime_pc_in.write("Description: " + packageDescription + "\n")
|
||||||
vmime_pc_in.write("Version: @VERSION@\n")
|
vmime_pc_in.write("Version: @VERSION@\n")
|
||||||
vmime_pc_in.write("Requires:\n")
|
vmime_pc_in.write("Requires: @GSASL_REQUIRED@\n")
|
||||||
vmime_pc_in.write("Libs: -L${libdir} -l@GENERIC_VERSIONED_LIBRARY_NAME@\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}/@GENERIC_VERSIONED_LIBRARY_NAME@\n")
|
||||||
vmime_pc_in.write("Cflags: -I${includedir}/\n")
|
vmime_pc_in.write("Cflags: -I${includedir}/\n")
|
||||||
vmime_pc_in.close()
|
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(packageVersionedName + "_la_SOURCES += " + buildMakefileFileList(x, 1) + "\n")
|
||||||
Makefile_am.write("endif\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
|
# -- platform handlers
|
||||||
for platform in libvmime_platforms_sources:
|
for platform in libvmime_platforms_sources:
|
||||||
Makefile_am.write("\n")
|
Makefile_am.write("\n")
|
||||||
@ -1200,6 +1249,13 @@ else
|
|||||||
AC_ERROR(no usable version of iconv has been found)
|
AC_ERROR(no usable version of iconv has been found)
|
||||||
fi
|
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++)
|
# -- global constructors (stolen from 'configure.in' in libsigc++)
|
||||||
AC_MSG_CHECKING([if linker supports global constructors])
|
AC_MSG_CHECKING([if linker supports global constructors])
|
||||||
cat > mylib.$ac_ext <<EOF
|
cat > mylib.$ac_ext <<EOF
|
||||||
@ -1391,7 +1447,7 @@ esac
|
|||||||
# ** debug
|
# ** debug
|
||||||
|
|
||||||
AC_ARG_ENABLE(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
|
[case "${enableval}" in
|
||||||
yes) conf_debug=yes ;;
|
yes) conf_debug=yes ;;
|
||||||
no) conf_debug=no ;;
|
no) conf_debug=no ;;
|
||||||
@ -1410,8 +1466,7 @@ fi
|
|||||||
# ** messaging
|
# ** messaging
|
||||||
|
|
||||||
AC_ARG_ENABLE(messaging,
|
AC_ARG_ENABLE(messaging,
|
||||||
[ --enable-messaging Enable messaging support\
|
AC_HELP_STRING([--enable-messaging], [Enable messaging support and connection to mail servers, default: enabled]),
|
||||||
(connection to mail servers, default: enabled)],
|
|
||||||
[case "${enableval}" in
|
[case "${enableval}" in
|
||||||
yes) conf_messaging=yes ;;
|
yes) conf_messaging=yes ;;
|
||||||
no) conf_messaging=no ;;
|
no) conf_messaging=no ;;
|
||||||
@ -1427,6 +1482,38 @@ else
|
|||||||
VMIME_HAVE_MESSAGING_FEATURES=0
|
VMIME_HAVE_MESSAGING_FEATURES=0
|
||||||
fi
|
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
|
# ** platform handlers
|
||||||
|
|
||||||
VMIME_BUILTIN_PLATFORMS=''
|
VMIME_BUILTIN_PLATFORMS=''
|
||||||
@ -1452,9 +1539,9 @@ VMIME_BUILTIN_MESSAGING_PROTOS=''
|
|||||||
p = proto[0]
|
p = proto[0]
|
||||||
|
|
||||||
configure_in.write("AC_ARG_ENABLE(messaging-proto-" + p + ",\n")
|
configure_in.write("AC_ARG_ENABLE(messaging-proto-" + p + ",\n")
|
||||||
configure_in.write(" [ --enable-messaging-proto-" + p
|
configure_in.write(" AC_HELP_STRING([--enable-messaging-proto-" + p
|
||||||
+ " Enable built-in support for protocol '" + p + "' "
|
+ "], [Enable built-in support for protocol '" + p + "'"
|
||||||
+ " (default: enabled)],\n")
|
+ ", default: enabled]),\n")
|
||||||
configure_in.write(' [case "${enableval}" in\n')
|
configure_in.write(' [case "${enableval}" in\n')
|
||||||
configure_in.write(' yes) conf_messaging_proto_' + p + '=yes ;;\n')
|
configure_in.write(' yes) conf_messaging_proto_' + p + '=yes ;;\n')
|
||||||
configure_in.write(' no) conf_messaging_proto_' + p + '=no ;;\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('fi\n\n')
|
||||||
|
|
||||||
configure_in.write("AC_ARG_ENABLE(platform-" + p + ",\n")
|
configure_in.write("AC_ARG_ENABLE(platform-" + p + ",\n")
|
||||||
configure_in.write(" [ --enable-platform-" + p
|
configure_in.write(" AC_HELP_STRING([--enable-platform-" + p
|
||||||
+ " Compile built-in platform handler for '" + p + "' "
|
+ "], [Compile built-in platform handler for '" + p + "' "
|
||||||
+ " (default: disabled, except if default for your platform)],\n")
|
+ ", default: disabled, except if default for your platform]),\n")
|
||||||
configure_in.write(' [case "${enableval}" in\n')
|
configure_in.write(' [case "${enableval}" in\n')
|
||||||
configure_in.write(' yes) conf_platform_' + p + '=yes ;;\n')
|
configure_in.write(' yes) conf_platform_' + p + '=yes ;;\n')
|
||||||
configure_in.write(' no) conf_platform_' + p + '=no ;;\n')
|
configure_in.write(' no) conf_platform_' + p + '=no ;;\n')
|
||||||
@ -1551,7 +1638,7 @@ AC_SUBST(PKGCONFIG_CFLAGS)
|
|||||||
AC_SUBST(PKGCONFIG_LIBS)
|
AC_SUBST(PKGCONFIG_LIBS)
|
||||||
|
|
||||||
EXTRA_CFLAGS="$EXTRA_CFLAGS -D_REENTRANT=1"
|
EXTRA_CFLAGS="$EXTRA_CFLAGS -D_REENTRANT=1"
|
||||||
EXTRA_LIBS=""
|
EXTRA_LIBS="$GSASL_LIBS"
|
||||||
|
|
||||||
CFLAGS=""
|
CFLAGS=""
|
||||||
CXXFLAGS=""
|
CXXFLAGS=""
|
||||||
@ -1666,6 +1753,8 @@ typedef unsigned ${VMIME_TYPE_INT32} vmime_uint32;
|
|||||||
#define VMIME_WIDE_CHAR_SUPPORT 0
|
#define VMIME_WIDE_CHAR_SUPPORT 0
|
||||||
// -- File-system support
|
// -- File-system support
|
||||||
#define VMIME_HAVE_FILESYSTEM_FEATURES 1
|
#define VMIME_HAVE_FILESYSTEM_FEATURES 1
|
||||||
|
// -- SASL support
|
||||||
|
#define VMIME_HAVE_SASL_SUPPORT ${VMIME_HAVE_SASL_SUPPORT}
|
||||||
// -- Messaging support
|
// -- Messaging support
|
||||||
#define VMIME_HAVE_MESSAGING_FEATURES ${VMIME_HAVE_MESSAGING_FEATURES}
|
#define VMIME_HAVE_MESSAGING_FEATURES ${VMIME_HAVE_MESSAGING_FEATURES}
|
||||||
""")
|
""")
|
||||||
@ -1719,6 +1808,9 @@ Messaging support : $conf_messaging
|
|||||||
* protocols :$VMIME_BUILTIN_MESSAGING_PROTOS
|
* protocols :$VMIME_BUILTIN_MESSAGING_PROTOS
|
||||||
File-system support : yes
|
File-system support : yes
|
||||||
Platform handlers :$VMIME_BUILTIN_PLATFORMS
|
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 <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#include "vmime/vmime.hpp"
|
#include "vmime/vmime.hpp"
|
||||||
#include "vmime/platforms/posix/posixHandler.hpp"
|
#include "vmime/platforms/posix/posixHandler.hpp"
|
||||||
@ -31,27 +32,65 @@ static vmime::ref <vmime::net::session> g_session
|
|||||||
|
|
||||||
|
|
||||||
// Authentification handler
|
// 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;
|
for (unsigned int i = 0 ; i < available.size() ; ++i)
|
||||||
std::cout << "Please authenticate yourself:" << std::endl;
|
{
|
||||||
|
std::cout << " " << available[i]->getName();
|
||||||
|
|
||||||
std::cout << " Username: ";
|
if (suggested && available[i]->getName() == suggested->getName())
|
||||||
std::cout.flush();
|
std::cout << "(suggested)";
|
||||||
|
}
|
||||||
|
|
||||||
std::getline(std::cin, username);
|
std::cout << std::endl << std::endl;
|
||||||
|
|
||||||
std::cout << " Password: ";
|
return defaultSASLAuthenticator::getAcceptableMechanisms(available, suggested);
|
||||||
std::cout.flush();
|
|
||||||
|
|
||||||
std::getline(std::cin, password);
|
|
||||||
|
|
||||||
return (vmime::net::authenticationInfos(username, password));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
// You can also set some properties (see example7 to know the properties
|
||||||
// available for each service). For example, for SMTP:
|
// available for each service). For example, for SMTP:
|
||||||
// tr->setProperty("options.need-authentication", true);
|
tr->setProperty("options.need-authentication", true);
|
||||||
|
|
||||||
// Information about the mail
|
// Information about the mail
|
||||||
std::cout << "Enter email of the expeditor (eg. me@somewhere.com): ";
|
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() throw() {}
|
||||||
socket_exception::socket_exception(const string& what, const exception& other)
|
socket_exception::socket_exception(const string& what, const exception& other)
|
||||||
: net_exception(what.empty()
|
: net_exception(what.empty()
|
||||||
? "Socket error."
|
? "Socket error." : what, other) {}
|
||||||
: "Socket error: '" + what + "'.", other) {}
|
|
||||||
|
|
||||||
exception* socket_exception::clone() const { return new socket_exception(*this); }
|
exception* socket_exception::clone() const { return new socket_exception(*this); }
|
||||||
const char* socket_exception::name() const throw() { return "socket_exception"; }
|
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() throw() {}
|
||||||
connection_error::connection_error(const string& what, const exception& other)
|
connection_error::connection_error(const string& what, const exception& other)
|
||||||
: socket_exception(what.empty()
|
: socket_exception(what.empty()
|
||||||
? "Connection error."
|
? "Connection error." : what, other) {}
|
||||||
: "Connection error: '" + what + "'.", other) {}
|
|
||||||
|
|
||||||
exception* connection_error::clone() const { return new connection_error(*this); }
|
exception* connection_error::clone() const { return new connection_error(*this); }
|
||||||
const char* connection_error::name() const throw() { return "connection_error"; }
|
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
|
#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
|
} // 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/exception.hpp"
|
||||||
#include "vmime/platformDependant.hpp"
|
#include "vmime/platformDependant.hpp"
|
||||||
|
|
||||||
|
#if VMIME_HAVE_SASL_SUPPORT
|
||||||
|
#include "vmime/security/sasl/SASLContext.hpp"
|
||||||
|
#endif // VMIME_HAVE_SASL_SUPPORT
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
|
||||||
@ -42,7 +46,7 @@ namespace net {
|
|||||||
namespace imap {
|
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_store(store), m_auth(auth), m_socket(NULL), m_parser(NULL), m_tag(NULL),
|
||||||
m_hierarchySeparator('\0'), m_state(STATE_NONE), m_timeoutHandler(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()
|
IMAPConnection::~IMAPConnection()
|
||||||
{
|
{
|
||||||
if (isConnected())
|
try
|
||||||
disconnect();
|
{
|
||||||
else if (m_socket)
|
if (isConnected())
|
||||||
internalDisconnect();
|
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)
|
else if (greet->resp_cond_auth()->condition() != IMAPParser::resp_cond_auth::PREAUTH)
|
||||||
{
|
{
|
||||||
const authenticationInfos auth = m_auth->requestAuthInfos();
|
try
|
||||||
|
|
||||||
// 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())
|
|
||||||
{
|
{
|
||||||
internalDisconnect();
|
authenticate();
|
||||||
throw exceptions::command_error("LOGIN", m_parser->lastLine());
|
|
||||||
}
|
}
|
||||||
else if (resp->response_done()->response_tagged()->
|
catch (...)
|
||||||
resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
|
|
||||||
{
|
{
|
||||||
internalDisconnect();
|
m_state = STATE_NONE;
|
||||||
throw exceptions::authentication_error(m_parser->lastLine());
|
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
|
const bool IMAPConnection::isConnected() const
|
||||||
{
|
{
|
||||||
return (m_socket && m_socket->isConnected() &&
|
return (m_socket && m_socket->isConnected() &&
|
||||||
|
@ -133,7 +133,7 @@ void IMAPFolder::open(const int mode, bool failIfModeIsNotAvailable)
|
|||||||
|
|
||||||
// Open a connection for this folder
|
// Open a connection for this folder
|
||||||
ref <IMAPConnection> connection =
|
ref <IMAPConnection> connection =
|
||||||
vmime::create <IMAPConnection>(m_store, m_store->oneTimeAuthenticator());
|
vmime::create <IMAPConnection>(m_store, m_store->getAuthenticator());
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -32,67 +32,23 @@ namespace net {
|
|||||||
namespace imap {
|
namespace imap {
|
||||||
|
|
||||||
|
|
||||||
#ifndef VMIME_BUILDING_DOC
|
IMAPStore::IMAPStore(ref <session> sess, ref <security::authenticator> auth)
|
||||||
|
: store(sess, getInfosInstance(), auth), m_connection(NULL)
|
||||||
//
|
|
||||||
// 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()
|
IMAPStore::~IMAPStore()
|
||||||
{
|
{
|
||||||
if (isConnected())
|
try
|
||||||
disconnect();
|
{
|
||||||
}
|
if (isConnected())
|
||||||
|
disconnect();
|
||||||
|
}
|
||||||
ref <authenticator> IMAPStore::oneTimeAuthenticator()
|
catch (vmime::exception&)
|
||||||
{
|
{
|
||||||
return (m_oneTimeAuth);
|
// Ignore
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -140,10 +96,8 @@ void IMAPStore::connect()
|
|||||||
if (isConnected())
|
if (isConnected())
|
||||||
throw exceptions::already_connected();
|
throw exceptions::already_connected();
|
||||||
|
|
||||||
m_oneTimeAuth = vmime::create <IMAPauthenticator>(getAuthenticator());
|
|
||||||
|
|
||||||
m_connection = vmime::create <IMAPConnection>
|
m_connection = vmime::create <IMAPConnection>
|
||||||
(thisWeakRef().dynamicCast <IMAPStore>(), m_oneTimeAuth);
|
(thisWeakRef().dynamicCast <IMAPStore>(), getAuthenticator());
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -179,8 +133,6 @@ void IMAPStore::disconnect()
|
|||||||
|
|
||||||
m_connection->disconnect();
|
m_connection->disconnect();
|
||||||
|
|
||||||
m_oneTimeAuth = NULL;
|
|
||||||
|
|
||||||
m_connection = NULL;
|
m_connection = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,7 +215,10 @@ const IMAPStore::_infos::props& IMAPStore::_infos::getProperties() const
|
|||||||
static props p =
|
static props p =
|
||||||
{
|
{
|
||||||
// IMAP-specific options
|
// 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
|
// Common properties
|
||||||
property(serviceInfos::property::AUTH_USERNAME, serviceInfos::property::FLAG_REQUIRED),
|
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();
|
const props& p = getProperties();
|
||||||
|
|
||||||
// IMAP-specific options
|
// 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
|
// Common properties
|
||||||
list.push_back(p.PROPERTY_AUTH_USERNAME);
|
list.push_back(p.PROPERTY_AUTH_USERNAME);
|
||||||
|
@ -39,7 +39,7 @@ namespace net {
|
|||||||
namespace maildir {
|
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)
|
: store(sess, getInfosInstance(), auth), m_connected(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -47,8 +47,15 @@ maildirStore::maildirStore(ref <session> sess, ref <authenticator> auth)
|
|||||||
|
|
||||||
maildirStore::~maildirStore()
|
maildirStore::~maildirStore()
|
||||||
{
|
{
|
||||||
if (isConnected())
|
try
|
||||||
disconnect();
|
{
|
||||||
|
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();
|
const string& buf = name.getBuffer();
|
||||||
|
|
||||||
// Name cannot start/end with spaces
|
// Name cannot start/end with spaces
|
||||||
if (utility::stringUtils::trim(buf) != name.getBuffer())
|
if (utility::stringUtils::trim(buf) != buf)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Name cannot start with '.'
|
// Name cannot start with '.'
|
||||||
|
@ -25,6 +25,11 @@
|
|||||||
#include "vmime/messageId.hpp"
|
#include "vmime/messageId.hpp"
|
||||||
#include "vmime/security/digest/messageDigestFactory.hpp"
|
#include "vmime/security/digest/messageDigestFactory.hpp"
|
||||||
#include "vmime/utility/filteredStream.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>
|
#include <algorithm>
|
||||||
|
|
||||||
@ -41,7 +46,7 @@ namespace net {
|
|||||||
namespace pop3 {
|
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),
|
: store(sess, getInfosInstance(), auth), m_socket(NULL),
|
||||||
m_authentified(false), m_timeoutHandler(NULL)
|
m_authentified(false), m_timeoutHandler(NULL)
|
||||||
{
|
{
|
||||||
@ -50,10 +55,17 @@ POP3Store::POP3Store(ref <session> sess, ref <authenticator> auth)
|
|||||||
|
|
||||||
POP3Store::~POP3Store()
|
POP3Store::~POP3Store()
|
||||||
{
|
{
|
||||||
if (isConnected())
|
try
|
||||||
disconnect();
|
{
|
||||||
else if (m_socket)
|
if (isConnected())
|
||||||
internalDisconnect();
|
disconnect();
|
||||||
|
else if (m_socket)
|
||||||
|
internalDisconnect();
|
||||||
|
}
|
||||||
|
catch (vmime::exception&)
|
||||||
|
{
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -128,98 +140,319 @@ void POP3Store::connect()
|
|||||||
string response;
|
string response;
|
||||||
readResponse(response, false);
|
readResponse(response, false);
|
||||||
|
|
||||||
if (isSuccessResponse(response))
|
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
|
|
||||||
{
|
{
|
||||||
internalDisconnect();
|
internalDisconnect();
|
||||||
throw exceptions::connection_greeting_error(response);
|
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;
|
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
|
const bool POP3Store::isConnected() const
|
||||||
{
|
{
|
||||||
return (m_socket && m_socket->isConnected() && m_authentified);
|
return (m_socket && m_socket->isConnected() && m_authentified);
|
||||||
@ -259,7 +492,7 @@ void POP3Store::internalDisconnect()
|
|||||||
|
|
||||||
void POP3Store::noop()
|
void POP3Store::noop()
|
||||||
{
|
{
|
||||||
m_socket->send("NOOP");
|
sendRequest("NOOP");
|
||||||
|
|
||||||
string response;
|
string response;
|
||||||
readResponse(response, false);
|
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)
|
const bool POP3Store::isSuccessResponse(const string& buffer)
|
||||||
{
|
{
|
||||||
static const string OK("+OK");
|
return getResponseCode(buffer) == RESPONSE_OK;
|
||||||
|
|
||||||
return (buffer.length() >= 3 &&
|
|
||||||
std::equal(buffer.begin(), buffer.begin() + 3, OK.begin()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -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)
|
void POP3Store::stripResponseCode(const string& buffer, string& result)
|
||||||
{
|
{
|
||||||
const string::size_type pos = buffer.find_first_of(" \t");
|
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 =
|
static props p =
|
||||||
{
|
{
|
||||||
// POP3-specific options
|
// POP3-specific options
|
||||||
property("options.apop", serviceInfos::property::TYPE_BOOL, "false"),
|
property("options.apop", serviceInfos::property::TYPE_BOOL, "true"),
|
||||||
property("options.apop.fallback", serviceInfos::property::TYPE_BOOL, "false"),
|
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
|
// Common properties
|
||||||
property(serviceInfos::property::AUTH_USERNAME, serviceInfos::property::FLAG_REQUIRED),
|
property(serviceInfos::property::AUTH_USERNAME, serviceInfos::property::FLAG_REQUIRED),
|
||||||
@ -614,6 +900,10 @@ const std::vector <serviceInfos::property> POP3Store::_infos::getAvailableProper
|
|||||||
// POP3-specific options
|
// POP3-specific options
|
||||||
list.push_back(p.PROPERTY_OPTIONS_APOP);
|
list.push_back(p.PROPERTY_OPTIONS_APOP);
|
||||||
list.push_back(p.PROPERTY_OPTIONS_APOP_FALLBACK);
|
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
|
// Common properties
|
||||||
list.push_back(p.PROPERTY_AUTH_USERNAME);
|
list.push_back(p.PROPERTY_AUTH_USERNAME);
|
||||||
|
@ -46,7 +46,7 @@ namespace net {
|
|||||||
namespace sendmail {
|
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)
|
: transport(sess, getInfosInstance(), auth), m_connected(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -54,8 +54,15 @@ sendmailTransport::sendmailTransport(ref <session> sess, ref <authenticator> aut
|
|||||||
|
|
||||||
sendmailTransport::~sendmailTransport()
|
sendmailTransport::~sendmailTransport()
|
||||||
{
|
{
|
||||||
if (isConnected())
|
try
|
||||||
disconnect();
|
{
|
||||||
|
if (isConnected())
|
||||||
|
disconnect();
|
||||||
|
}
|
||||||
|
catch (vmime::exception&)
|
||||||
|
{
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -17,22 +17,33 @@
|
|||||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include "vmime/config.hpp"
|
||||||
#include "vmime/net/service.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 vmime {
|
||||||
namespace net {
|
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)
|
: m_session(sess), m_auth(auth)
|
||||||
{
|
{
|
||||||
if (!auth)
|
if (!auth)
|
||||||
{
|
{
|
||||||
m_auth = vmime::create <defaultAuthenticator>
|
#if VMIME_HAVE_SASL_SUPPORT
|
||||||
(sess, infos.getPropertyPrefix());
|
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);
|
return (m_auth);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ref <authenticator> service::getAuthenticator()
|
ref <security::authenticator> service::getAuthenticator()
|
||||||
{
|
{
|
||||||
return (m_auth);
|
return (m_auth);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void service::setAuthenticator(ref <security::authenticator> auth)
|
||||||
|
{
|
||||||
|
m_auth = auth;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // net
|
} // net
|
||||||
} // vmime
|
} // vmime
|
||||||
|
@ -48,14 +48,16 @@ serviceFactory* serviceFactory::getInstance()
|
|||||||
|
|
||||||
|
|
||||||
ref <service> serviceFactory::create
|
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));
|
return (getServiceByProtocol(protocol)->create(sess, auth));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ref <service> serviceFactory::create
|
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);
|
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));
|
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 <session> sess = thisRef().dynamicCast <session>();
|
||||||
ref <service> sv = serviceFactory::getInstance()->create(sess, protocol, auth);
|
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 <session> sess = thisRef().dynamicCast <session>();
|
||||||
ref <service> sv = serviceFactory::getInstance()->create(sess, url, auth);
|
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));
|
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 <session> sess = thisRef().dynamicCast <session>();
|
||||||
ref <service> sv = serviceFactory::getInstance()->create(sess, protocol, auth);
|
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 <session> sess = thisRef().dynamicCast <session>();
|
||||||
ref <service> sv = serviceFactory::getInstance()->create(sess, url, auth);
|
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/net/authHelper.hpp"
|
||||||
|
|
||||||
#include "vmime/utility/filteredStream.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
|
// Helpers for service properties
|
||||||
@ -41,7 +46,7 @@ namespace net {
|
|||||||
namespace smtp {
|
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),
|
: transport(sess, getInfosInstance(), auth), m_socket(NULL),
|
||||||
m_authentified(false), m_extendedSMTP(false), m_timeoutHandler(NULL)
|
m_authentified(false), m_extendedSMTP(false), m_timeoutHandler(NULL)
|
||||||
{
|
{
|
||||||
@ -50,10 +55,17 @@ SMTPTransport::SMTPTransport(ref <session> sess, ref <authenticator> auth)
|
|||||||
|
|
||||||
SMTPTransport::~SMTPTransport()
|
SMTPTransport::~SMTPTransport()
|
||||||
{
|
{
|
||||||
if (isConnected())
|
try
|
||||||
disconnect();
|
{
|
||||||
else if (m_socket)
|
if (isConnected())
|
||||||
internalDisconnect();
|
disconnect();
|
||||||
|
else if (m_socket)
|
||||||
|
internalDisconnect();
|
||||||
|
}
|
||||||
|
catch (vmime::exception&)
|
||||||
|
{
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -87,15 +99,16 @@ void SMTPTransport::connect()
|
|||||||
m_socket = sf->create();
|
m_socket = sf->create();
|
||||||
m_socket->connect(address, port);
|
m_socket->connect(address, port);
|
||||||
|
|
||||||
|
m_responseBuffer.clear();
|
||||||
|
|
||||||
// Connection
|
// Connection
|
||||||
//
|
//
|
||||||
// eg: C: <connection to server>
|
// eg: C: <connection to server>
|
||||||
// --- S: 220 smtp.domain.com Service ready
|
// --- S: 220 smtp.domain.com Service ready
|
||||||
|
|
||||||
string response;
|
string response;
|
||||||
readResponse(response);
|
|
||||||
|
|
||||||
if (responseCode(response) != 220)
|
if (readAllResponses(response) != 220)
|
||||||
{
|
{
|
||||||
internalDisconnect();
|
internalDisconnect();
|
||||||
throw exceptions::connection_greeting_error(response);
|
throw exceptions::connection_greeting_error(response);
|
||||||
@ -105,12 +118,12 @@ void SMTPTransport::connect()
|
|||||||
// First, try Extended SMTP (ESMTP)
|
// First, try Extended SMTP (ESMTP)
|
||||||
//
|
//
|
||||||
// eg: C: EHLO thismachine.ourdomain.com
|
// 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());
|
sendRequest("EHLO " + platformDependant::getHandler()->getHostName());
|
||||||
readResponse(response);
|
|
||||||
|
|
||||||
if (responseCode(response) != 250)
|
if (readAllResponses(response, true) != 250)
|
||||||
{
|
{
|
||||||
// Next, try "Basic" SMTP
|
// Next, try "Basic" SMTP
|
||||||
//
|
//
|
||||||
@ -118,9 +131,8 @@ void SMTPTransport::connect()
|
|||||||
// S: 250 OK
|
// S: 250 OK
|
||||||
|
|
||||||
sendRequest("HELO " + platformDependant::getHandler()->getHostName());
|
sendRequest("HELO " + platformDependant::getHandler()->getHostName());
|
||||||
readResponse(response);
|
|
||||||
|
|
||||||
if (responseCode(response) != 250)
|
if (readAllResponses(response) != 250)
|
||||||
{
|
{
|
||||||
internalDisconnect();
|
internalDisconnect();
|
||||||
throw exceptions::connection_greeting_error(response);
|
throw exceptions::connection_greeting_error(response);
|
||||||
@ -131,93 +143,231 @@ void SMTPTransport::connect()
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_extendedSMTP = true;
|
m_extendedSMTP = true;
|
||||||
|
m_extendedSMTPResponse = response;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Authentication
|
// Authentication
|
||||||
if (GET_PROPERTY(bool, PROPERTY_OPTIONS_NEEDAUTH))
|
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();
|
internalDisconnect();
|
||||||
throw exceptions::command_error("AUTH", "ESMTP not supported.");
|
throw e;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
#endif // VMIME_HAVE_SASL_SUPPORT
|
||||||
|
|
||||||
const authenticationInfos auth = getAuthenticator()->requestAuthInfos();
|
// No other authentication method is possible
|
||||||
bool authentified = false;
|
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,
|
if (word.length() == 4 &&
|
||||||
CRAM_MD5 = First,
|
(word[0] == 'A' || word[0] == 'a') ||
|
||||||
// TODO: more authentication methods...
|
(word[0] == 'U' || word[0] == 'u') ||
|
||||||
End
|
(word[0] == 'T' || word[0] == 't') ||
|
||||||
};
|
(word[0] == 'H' || word[0] == 'h'))
|
||||||
|
|
||||||
for (int currentMethod = First ; !authentified ; ++currentMethod)
|
|
||||||
{
|
|
||||||
switch (currentMethod)
|
|
||||||
{
|
{
|
||||||
case CRAM_MD5:
|
inAuth = true;
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
case End:
|
else if (inAuth)
|
||||||
{
|
{
|
||||||
// All authentication methods have been tried and
|
saslMechs.push_back(word);
|
||||||
// the server does not understand any.
|
|
||||||
throw exceptions::authentication_error(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
const bool SMTPTransport::isConnected() const
|
||||||
{
|
{
|
||||||
@ -250,12 +400,11 @@ void SMTPTransport::internalDisconnect()
|
|||||||
|
|
||||||
void SMTPTransport::noop()
|
void SMTPTransport::noop()
|
||||||
{
|
{
|
||||||
m_socket->send("NOOP");
|
sendRequest("NOOP");
|
||||||
|
|
||||||
string response;
|
string response;
|
||||||
readResponse(response);
|
|
||||||
|
|
||||||
if (responseCode(response) != 250)
|
if (readAllResponses(response) != 250)
|
||||||
throw exceptions::command_error("NOOP", response);
|
throw exceptions::command_error("NOOP", response);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,9 +423,8 @@ void SMTPTransport::send(const mailbox& expeditor, const mailboxList& recipients
|
|||||||
string response;
|
string response;
|
||||||
|
|
||||||
sendRequest("MAIL FROM: <" + expeditor.getEmail() + ">");
|
sendRequest("MAIL FROM: <" + expeditor.getEmail() + ">");
|
||||||
readResponse(response);
|
|
||||||
|
|
||||||
if (responseCode(response) != 250)
|
if (readAllResponses(response) != 250)
|
||||||
{
|
{
|
||||||
internalDisconnect();
|
internalDisconnect();
|
||||||
throw exceptions::command_error("MAIL", response);
|
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);
|
const mailbox& mbox = *recipients.getMailboxAt(i);
|
||||||
|
|
||||||
sendRequest("RCPT TO: <" + mbox.getEmail() + ">");
|
sendRequest("RCPT TO: <" + mbox.getEmail() + ">");
|
||||||
readResponse(response);
|
|
||||||
|
|
||||||
if (responseCode(response) != 250)
|
if (readAllResponses(response) != 250)
|
||||||
{
|
{
|
||||||
internalDisconnect();
|
internalDisconnect();
|
||||||
throw exceptions::command_error("RCPT TO", response);
|
throw exceptions::command_error("RCPT TO", response);
|
||||||
@ -299,9 +446,8 @@ void SMTPTransport::send(const mailbox& expeditor, const mailboxList& recipients
|
|||||||
|
|
||||||
// Send the message data
|
// Send the message data
|
||||||
sendRequest("DATA");
|
sendRequest("DATA");
|
||||||
readResponse(response);
|
|
||||||
|
|
||||||
if (responseCode(response) != 354)
|
if (readAllResponses(response) != 354)
|
||||||
{
|
{
|
||||||
internalDisconnect();
|
internalDisconnect();
|
||||||
throw exceptions::command_error("DATA", response);
|
throw exceptions::command_error("DATA", response);
|
||||||
@ -315,9 +461,8 @@ void SMTPTransport::send(const mailbox& expeditor, const mailboxList& recipients
|
|||||||
|
|
||||||
// Send end-of-data delimiter
|
// Send end-of-data delimiter
|
||||||
m_socket->sendRaw("\r\n.\r\n", 5);
|
m_socket->sendRaw("\r\n.\r\n", 5);
|
||||||
readResponse(response);
|
|
||||||
|
|
||||||
if (responseCode(response) != 250)
|
if (readAllResponses(response) != 250)
|
||||||
{
|
{
|
||||||
internalDisconnect();
|
internalDisconnect();
|
||||||
throw exceptions::command_error("DATA", response);
|
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;
|
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);
|
while (true)
|
||||||
std::string line;
|
|
||||||
|
|
||||||
while (std::getline(iss, line))
|
|
||||||
{
|
{
|
||||||
if (line.length() >= 4)
|
// Get a line from the response buffer
|
||||||
text += line.substr(4);
|
string::size_type lineEnd = currentBuffer.find_first_of('\n');
|
||||||
else
|
|
||||||
text += line;
|
|
||||||
|
|
||||||
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
|
// Check whether the time-out delay is elapsed
|
||||||
if (m_timeoutHandler && m_timeoutHandler->isTimeOut())
|
if (m_timeoutHandler && m_timeoutHandler->isTimeOut())
|
||||||
{
|
{
|
||||||
@ -393,40 +528,61 @@ void SMTPTransport::readResponse(string& buffer)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We have received data: reset the time-out counter
|
currentBuffer += receiveBuffer;
|
||||||
if (m_timeoutHandler)
|
}
|
||||||
m_timeoutHandler->resetTimeOut();
|
}
|
||||||
|
|
||||||
// Append the data to the response buffer
|
|
||||||
buffer += receiveBuffer;
|
|
||||||
|
|
||||||
// Check for terminator string (and strip it if present)
|
const int SMTPTransport::readResponse(string& text)
|
||||||
if (buffer.length() >= 2 && buffer[buffer.length() - 1] == '\n')
|
{
|
||||||
|
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;
|
if (allText)
|
||||||
bool end = false;
|
outText = text;
|
||||||
|
|
||||||
for ( ; !end ; --p)
|
return 0;
|
||||||
{
|
|
||||||
if (p == 0 || buffer[p] == '\n')
|
|
||||||
{
|
|
||||||
end = true;
|
|
||||||
|
|
||||||
if (p + 4 < buffer.length())
|
|
||||||
foundTerminator = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove [CR]LF at the end of the response
|
if (allText)
|
||||||
if (buffer.length() >= 2 && buffer[buffer.length() - 1] == '\n')
|
outText = text;
|
||||||
{
|
|
||||||
if (buffer[buffer.length() - 2] == '\r')
|
return firstCode;
|
||||||
buffer.resize(buffer.length() - 2);
|
|
||||||
else
|
|
||||||
buffer.resize(buffer.length() - 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -460,6 +616,10 @@ const SMTPTransport::_infos::props& SMTPTransport::_infos::getProperties() const
|
|||||||
{
|
{
|
||||||
// SMTP-specific options
|
// SMTP-specific options
|
||||||
property("options.need-authentication", serviceInfos::property::TYPE_BOOL, "false"),
|
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
|
// Common properties
|
||||||
property(serviceInfos::property::AUTH_USERNAME),
|
property(serviceInfos::property::AUTH_USERNAME),
|
||||||
@ -483,6 +643,10 @@ const std::vector <serviceInfos::property> SMTPTransport::_infos::getAvailablePr
|
|||||||
|
|
||||||
// SMTP-specific options
|
// SMTP-specific options
|
||||||
list.push_back(p.PROPERTY_OPTIONS_NEEDAUTH);
|
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
|
// Common properties
|
||||||
list.push_back(p.PROPERTY_AUTH_USERNAME);
|
list.push_back(p.PROPERTY_AUTH_USERNAME);
|
||||||
|
@ -28,7 +28,7 @@ namespace vmime {
|
|||||||
namespace net {
|
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)
|
: 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
|
#ifdef VMIME_HAVE_MESSAGING_FEATURES
|
||||||
|
|
||||||
|
|
||||||
|
@ -811,6 +811,58 @@ public:
|
|||||||
#endif // VMIME_HAVE_FILESYSTEM_FEATURES
|
#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
|
} // 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/config.hpp"
|
||||||
|
|
||||||
#include "vmime/net/authenticator.hpp"
|
|
||||||
#include "vmime/net/socket.hpp"
|
#include "vmime/net/socket.hpp"
|
||||||
#include "vmime/net/timeoutHandler.hpp"
|
#include "vmime/net/timeoutHandler.hpp"
|
||||||
#include "vmime/net/session.hpp"
|
#include "vmime/net/session.hpp"
|
||||||
|
|
||||||
#include "vmime/net/imap/IMAPParser.hpp"
|
#include "vmime/net/imap/IMAPParser.hpp"
|
||||||
|
|
||||||
|
#include "vmime/security/authenticator.hpp"
|
||||||
|
|
||||||
|
|
||||||
namespace vmime {
|
namespace vmime {
|
||||||
namespace net {
|
namespace net {
|
||||||
@ -44,7 +45,7 @@ class IMAPConnection : public object
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
IMAPConnection(weak_ref <IMAPStore> store, ref <authenticator> auth);
|
IMAPConnection(weak_ref <IMAPStore> store, ref <security::authenticator> auth);
|
||||||
~IMAPConnection();
|
~IMAPConnection();
|
||||||
|
|
||||||
|
|
||||||
@ -83,11 +84,21 @@ public:
|
|||||||
|
|
||||||
ref <session> getSession();
|
ref <session> getSession();
|
||||||
|
|
||||||
|
const std::vector <string> getCapabilities();
|
||||||
|
|
||||||
|
ref <security::authenticator> getAuthenticator();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
void authenticate();
|
||||||
|
#if VMIME_HAVE_SASL_SUPPORT
|
||||||
|
void authenticateSASL();
|
||||||
|
#endif // VMIME_HAVE_SASL_SUPPORT
|
||||||
|
|
||||||
|
|
||||||
weak_ref <IMAPStore> m_store;
|
weak_ref <IMAPStore> m_store;
|
||||||
|
|
||||||
ref <authenticator> m_auth;
|
ref <security::authenticator> m_auth;
|
||||||
|
|
||||||
ref <socket> m_socket;
|
ref <socket> m_socket;
|
||||||
|
|
||||||
|
@ -1401,22 +1401,32 @@ public:
|
|||||||
|
|
||||||
string::size_type pos = *currentPos;
|
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);
|
if (name == "marked")
|
||||||
const string name = utility::stringUtils::toLower(at->value());
|
m_type = MARKED;
|
||||||
delete (at);
|
else if (name == "noinferiors")
|
||||||
|
m_type = NOINFERIORS;
|
||||||
if (name == "marked")
|
else if (name == "noselect")
|
||||||
m_type = MARKED;
|
m_type = NOSELECT;
|
||||||
else if (name == "noinferiors")
|
else if (name == "unmarked")
|
||||||
m_type = NOINFERIORS;
|
m_type = UNMARKED;
|
||||||
else if (name == "noselect")
|
else
|
||||||
m_type = NOSELECT;
|
{
|
||||||
else if (name == "unmarked")
|
m_type = UNKNOWN;
|
||||||
m_type = UNMARKED;
|
m_name = "\\" + name;
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
atom* at = parser.get <atom>(line, &pos);
|
||||||
|
const string name = utility::stringUtils::toLower(at->value());
|
||||||
|
delete (at);
|
||||||
|
|
||||||
m_type = UNKNOWN;
|
m_type = UNKNOWN;
|
||||||
m_name = name;
|
m_name = name;
|
||||||
}
|
}
|
||||||
@ -1989,40 +1999,13 @@ public:
|
|||||||
string::size_type pos = *currentPos;
|
string::size_type pos = *currentPos;
|
||||||
|
|
||||||
parser.checkWithArg <special_atom>(line, &pos, "capability");
|
parser.checkWithArg <special_atom>(line, &pos, "capability");
|
||||||
parser.check <SPACE>(line, &pos);
|
|
||||||
|
|
||||||
bool IMAP4rev1 = false;
|
while (parser.check <SPACE>(line, &pos, true))
|
||||||
|
|
||||||
for (bool end = false ; !end && !IMAP4rev1 ; )
|
|
||||||
{
|
{
|
||||||
if (parser.checkWithArg <special_atom>(line, &pos, "imap4rev1", true))
|
capability* cap = parser.get <capability>(line, &pos);
|
||||||
{
|
if (cap == NULL) break;
|
||||||
IMAP4rev1 = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
capability* cap = parser.get <capability>(line, &pos);
|
|
||||||
end = (cap == NULL);
|
|
||||||
|
|
||||||
if (cap)
|
m_capabilities.push_back(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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*currentPos = pos;
|
*currentPos = pos;
|
||||||
|
@ -52,7 +52,7 @@ class IMAPStore : public store
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
IMAPStore(ref <session> sess, ref <authenticator> auth);
|
IMAPStore(ref <session> sess, ref <security::authenticator> auth);
|
||||||
~IMAPStore();
|
~IMAPStore();
|
||||||
|
|
||||||
const string getProtocolName() const;
|
const string getProtocolName() const;
|
||||||
@ -79,13 +79,6 @@ private:
|
|||||||
// Connection
|
// Connection
|
||||||
ref <IMAPConnection> m_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();
|
ref <IMAPConnection> connection();
|
||||||
@ -106,7 +99,10 @@ private:
|
|||||||
struct props
|
struct props
|
||||||
{
|
{
|
||||||
// IMAP-specific options
|
// 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
|
// Common properties
|
||||||
serviceInfos::property PROPERTY_AUTH_USERNAME;
|
serviceInfos::property PROPERTY_AUTH_USERNAME;
|
||||||
|
@ -49,7 +49,7 @@ class maildirStore : public store
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
maildirStore(ref <session> sess, ref <authenticator> auth);
|
maildirStore(ref <session> sess, ref <security::authenticator> auth);
|
||||||
~maildirStore();
|
~maildirStore();
|
||||||
|
|
||||||
const string getProtocolName() const;
|
const string getProtocolName() const;
|
||||||
|
@ -48,7 +48,7 @@ class POP3Store : public store
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
POP3Store(ref <session> sess, ref <authenticator> auth);
|
POP3Store(ref <session> sess, ref <security::authenticator> auth);
|
||||||
~POP3Store();
|
~POP3Store();
|
||||||
|
|
||||||
const string getProtocolName() const;
|
const string getProtocolName() const;
|
||||||
@ -72,9 +72,24 @@ public:
|
|||||||
|
|
||||||
private:
|
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 isSuccessResponse(const string& buffer);
|
||||||
static const bool stripFirstLine(const string& buffer, string& result, string* firstLine = NULL);
|
static const bool stripFirstLine(const string& buffer, string& result, string* firstLine = NULL);
|
||||||
static void stripResponseCode(const string& buffer, string& result);
|
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 sendRequest(const string& buffer, const bool end = true);
|
||||||
void readResponse(string& buffer, const bool multiLine, utility::progressionListener* progress = NULL);
|
void readResponse(string& buffer, const bool multiLine, utility::progressionListener* progress = NULL);
|
||||||
@ -108,6 +123,10 @@ private:
|
|||||||
// POP3-specific options
|
// POP3-specific options
|
||||||
serviceInfos::property PROPERTY_OPTIONS_APOP;
|
serviceInfos::property PROPERTY_OPTIONS_APOP;
|
||||||
serviceInfos::property PROPERTY_OPTIONS_APOP_FALLBACK;
|
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
|
// Common properties
|
||||||
serviceInfos::property PROPERTY_AUTH_USERNAME;
|
serviceInfos::property PROPERTY_AUTH_USERNAME;
|
||||||
|
@ -43,7 +43,7 @@ class sendmailTransport : public transport
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
sendmailTransport(ref <session> sess, ref <authenticator> auth);
|
sendmailTransport(ref <session> sess, ref <security::authenticator> auth);
|
||||||
~sendmailTransport();
|
~sendmailTransport();
|
||||||
|
|
||||||
const string getProtocolName() const;
|
const string getProtocolName() const;
|
||||||
|
@ -24,7 +24,6 @@
|
|||||||
#include "vmime/types.hpp"
|
#include "vmime/types.hpp"
|
||||||
|
|
||||||
#include "vmime/net/session.hpp"
|
#include "vmime/net/session.hpp"
|
||||||
#include "vmime/net/authenticator.hpp"
|
|
||||||
|
|
||||||
#include "vmime/net/serviceFactory.hpp"
|
#include "vmime/net/serviceFactory.hpp"
|
||||||
#include "vmime/net/serviceInfos.hpp"
|
#include "vmime/net/serviceInfos.hpp"
|
||||||
@ -43,7 +42,7 @@ class service : public object
|
|||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
service(ref <session> sess, const serviceInfos& infos, ref <authenticator> auth);
|
service(ref <session> sess, const serviceInfos& infos, ref <security::authenticator> auth);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -110,13 +109,19 @@ public:
|
|||||||
*
|
*
|
||||||
* @return authenticator object
|
* @return authenticator object
|
||||||
*/
|
*/
|
||||||
ref <const authenticator> getAuthenticator() const;
|
ref <const security::authenticator> getAuthenticator() const;
|
||||||
|
|
||||||
/** Return the authenticator object used with this service instance.
|
/** Return the authenticator object used with this service instance.
|
||||||
*
|
*
|
||||||
* @return authenticator object
|
* @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).
|
/** Set a property for this service (service prefix is added automatically).
|
||||||
*
|
*
|
||||||
@ -150,7 +155,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
|
|
||||||
ref <session> m_session;
|
ref <session> m_session;
|
||||||
ref <authenticator> m_auth;
|
ref <security::authenticator> m_auth;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -30,9 +30,10 @@
|
|||||||
#include "vmime/utility/url.hpp"
|
#include "vmime/utility/url.hpp"
|
||||||
|
|
||||||
#include "vmime/net/serviceInfos.hpp"
|
#include "vmime/net/serviceInfos.hpp"
|
||||||
#include "vmime/net/authenticator.hpp"
|
|
||||||
#include "vmime/net/timeoutHandler.hpp"
|
#include "vmime/net/timeoutHandler.hpp"
|
||||||
|
|
||||||
|
#include "vmime/security/authenticator.hpp"
|
||||||
|
|
||||||
#include "vmime/utility/progressionListener.hpp"
|
#include "vmime/utility/progressionListener.hpp"
|
||||||
|
|
||||||
|
|
||||||
@ -69,7 +70,9 @@ public:
|
|||||||
|
|
||||||
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 string& getName() const = 0;
|
||||||
virtual const serviceInfos& getInfos() const = 0;
|
virtual const serviceInfos& getInfos() const = 0;
|
||||||
@ -92,7 +95,9 @@ private:
|
|||||||
|
|
||||||
public:
|
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);
|
return vmime::create <S>(sess, auth);
|
||||||
}
|
}
|
||||||
@ -137,7 +142,10 @@ public:
|
|||||||
* @throw exceptions::no_service_available if no service is registered
|
* @throw exceptions::no_service_available if no service is registered
|
||||||
* for this protocol
|
* 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.
|
/** Create a new service instance from a URL.
|
||||||
*
|
*
|
||||||
@ -149,7 +157,10 @@ public:
|
|||||||
* @throw exceptions::no_service_available if no service is registered
|
* @throw exceptions::no_service_available if no service is registered
|
||||||
* for this protocol
|
* 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.
|
/** Return information about a registered protocol.
|
||||||
*
|
*
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
#define VMIME_NET_SESSION_HPP_INCLUDED
|
#define VMIME_NET_SESSION_HPP_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
#include "vmime/net/authenticator.hpp"
|
#include "vmime/security/authenticator.hpp"
|
||||||
|
|
||||||
#include "vmime/utility/url.hpp"
|
#include "vmime/utility/url.hpp"
|
||||||
|
|
||||||
@ -60,7 +60,8 @@ public:
|
|||||||
* credentials by reading the session properties "auth.username" and "auth.password".
|
* credentials by reading the session properties "auth.username" and "auth.password".
|
||||||
* @return a new transport service
|
* @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.
|
/** 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".
|
* credentials by reading the session properties "auth.username" and "auth.password".
|
||||||
* @return a new transport service
|
* @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.
|
/** 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".
|
* credentials by reading the session properties "auth.username" and "auth.password".
|
||||||
* @return a new transport service
|
* @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
|
/** Return a transport service instance for the protocol specified
|
||||||
* in the session properties.
|
* in the session properties.
|
||||||
@ -92,7 +97,7 @@ public:
|
|||||||
* credentials by reading the session properties "auth.username" and "auth.password".
|
* credentials by reading the session properties "auth.username" and "auth.password".
|
||||||
* @return a new store service
|
* @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.
|
/** 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".
|
* credentials by reading the session properties "auth.username" and "auth.password".
|
||||||
* @return a new store service
|
* @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.
|
/** 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".
|
* credentials by reading the session properties "auth.username" and "auth.password".
|
||||||
* @return a new store service
|
* @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.
|
/** 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:
|
public:
|
||||||
|
|
||||||
SMTPTransport(ref <session> sess, ref <authenticator> auth);
|
SMTPTransport(ref <session> sess, ref <security::authenticator> auth);
|
||||||
~SMTPTransport();
|
~SMTPTransport();
|
||||||
|
|
||||||
const string getProtocolName() const;
|
const string getProtocolName() const;
|
||||||
@ -58,18 +58,30 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
static const int responseCode(const string& response);
|
static const int getResponseCode(const string& response);
|
||||||
static const string responseText(const string& response);
|
|
||||||
|
|
||||||
void sendRequest(const string& buffer, const bool end = true);
|
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 internalDisconnect();
|
||||||
|
|
||||||
|
void authenticate();
|
||||||
|
#if VMIME_HAVE_SASL_SUPPORT
|
||||||
|
void authenticateSASL();
|
||||||
|
#endif // VMIME_HAVE_SASL_SUPPORT
|
||||||
|
|
||||||
|
|
||||||
ref <socket> m_socket;
|
ref <socket> m_socket;
|
||||||
bool m_authentified;
|
bool m_authentified;
|
||||||
|
|
||||||
bool m_extendedSMTP;
|
bool m_extendedSMTP;
|
||||||
|
string m_extendedSMTPResponse;
|
||||||
|
|
||||||
|
string m_responseBuffer;
|
||||||
|
bool m_responseContinues;
|
||||||
|
|
||||||
ref <timeoutHandler> m_timeoutHandler;
|
ref <timeoutHandler> m_timeoutHandler;
|
||||||
|
|
||||||
@ -83,6 +95,10 @@ private:
|
|||||||
{
|
{
|
||||||
// SMTP-specific options
|
// SMTP-specific options
|
||||||
serviceInfos::property PROPERTY_OPTIONS_NEEDAUTH;
|
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
|
// Common properties
|
||||||
serviceInfos::property PROPERTY_AUTH_USERNAME;
|
serviceInfos::property PROPERTY_AUTH_USERNAME;
|
||||||
|
@ -37,7 +37,7 @@ class store : public service
|
|||||||
{
|
{
|
||||||
protected:
|
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) { }
|
: service(sess, infos, auth) { }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -42,7 +42,7 @@ class transport : public service
|
|||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
transport(ref <session> sess, const serviceInfos& infos, ref <authenticator> auth);
|
transport(ref <session> sess, const serviceInfos& infos, ref <security::authenticator> auth);
|
||||||
|
|
||||||
public:
|
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.
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef VMIME_NET_DEFAULTAUTHENTICATOR_HPP_INCLUDED
|
#ifndef VMIME_SECURITY_DEFAULTAUTHENTICATOR_HPP_INCLUDED
|
||||||
#define VMIME_NET_DEFAULTAUTHENTICATOR_HPP_INCLUDED
|
#define VMIME_SECURITY_DEFAULTAUTHENTICATOR_HPP_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
#include "vmime/net/authenticator.hpp"
|
#include "vmime/security/authenticator.hpp"
|
||||||
#include "vmime/propertySet.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
namespace vmime {
|
namespace vmime {
|
||||||
namespace net {
|
namespace security {
|
||||||
|
|
||||||
|
|
||||||
class session;
|
/** An authenticator that can provide some basic information by
|
||||||
|
* reading in the messaging session properties.
|
||||||
|
|
||||||
/** 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.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class defaultAuthenticator : public authenticator
|
class defaultAuthenticator : public authenticator
|
||||||
{
|
{
|
||||||
public:
|
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:
|
private:
|
||||||
|
|
||||||
weak_ref <session> m_session;
|
weak_ref <net::service> m_service;
|
||||||
const string m_prefix;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
} // net
|
} // security
|
||||||
} // vmime
|
} // 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.
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef VMIME_NET_AUTHENTICATIONINFOS_HPP_INCLUDED
|
#ifndef VMIME_SECURITY_SASL_SASLSOCKET_HPP_INCLUDED
|
||||||
#define VMIME_NET_AUTHENTICATIONINFOS_HPP_INCLUDED
|
#define VMIME_SECURITY_SASL_SASLSOCKET_HPP_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
#include "vmime/types.hpp"
|
#include "vmime/types.hpp"
|
||||||
|
|
||||||
|
#include "vmime/net/socket.hpp"
|
||||||
|
|
||||||
|
|
||||||
namespace vmime {
|
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 SASLSocket : public net::socket
|
||||||
class authenticationInfos : public object
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
authenticationInfos(const string& username, const string& password);
|
SASLSocket(ref <SASLSession> sess, ref <net::socket> wrapped);
|
||||||
authenticationInfos(const authenticationInfos& infos);
|
~SASLSocket();
|
||||||
|
|
||||||
/** Return the user account name.
|
void connect(const string& address, const port_t port);
|
||||||
*
|
void disconnect();
|
||||||
* @return account name
|
|
||||||
*/
|
|
||||||
const string& getUsername() const;
|
|
||||||
|
|
||||||
/** Return the user account password.
|
const bool isConnected() const;
|
||||||
*
|
|
||||||
* @return account password
|
void receive(string& buffer);
|
||||||
*/
|
const int receiveRaw(char* buffer, const int count);
|
||||||
const string& getPassword() const;
|
|
||||||
|
void send(const string& buffer);
|
||||||
|
void sendRaw(const char* buffer, const int count);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
string m_username;
|
ref <SASLSession> m_session;
|
||||||
string m_password;
|
ref <net::socket> m_wrapped;
|
||||||
|
|
||||||
|
byte* m_pendingBuffer;
|
||||||
|
int m_pendingPos;
|
||||||
|
int m_pendingLen;
|
||||||
|
|
||||||
|
char m_recvBuffer[65536];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
} // net
|
} // sasl
|
||||||
|
} // security
|
||||||
} // vmime
|
} // 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 <limits>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "vmime/config.hpp"
|
#include "vmime/config.hpp"
|
||||||
#include "vmime/utility/smartPtr.hpp"
|
#include "vmime/utility/smartPtr.hpp"
|
||||||
@ -40,6 +41,7 @@ namespace vmime
|
|||||||
typedef int char_t;
|
typedef int char_t;
|
||||||
|
|
||||||
typedef vmime_uint8 byte;
|
typedef vmime_uint8 byte;
|
||||||
|
typedef std::vector <byte> byteArray;
|
||||||
|
|
||||||
// Some aliases
|
// Some aliases
|
||||||
namespace utils = utility;
|
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
|
#if VMIME_HAVE_MESSAGING_FEATURES
|
||||||
|
|
||||||
|
|
||||||
|
@ -86,6 +86,21 @@
|
|||||||
#include "vmime/utility/datetimeUtils.hpp"
|
#include "vmime/utility/datetimeUtils.hpp"
|
||||||
#include "vmime/utility/filteredStream.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
|
// Messaging features
|
||||||
#if VMIME_HAVE_MESSAGING_FEATURES
|
#if VMIME_HAVE_MESSAGING_FEATURES
|
||||||
#include "vmime/net/socket.hpp"
|
#include "vmime/net/socket.hpp"
|
||||||
@ -95,9 +110,6 @@
|
|||||||
#include "vmime/net/transport.hpp"
|
#include "vmime/net/transport.hpp"
|
||||||
|
|
||||||
#include "vmime/net/session.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/folder.hpp"
|
||||||
#include "vmime/net/message.hpp"
|
#include "vmime/net/message.hpp"
|
||||||
|
Loading…
Reference in New Issue
Block a user