aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/sasl
diff options
context:
space:
mode:
authormolotkov-and <molotkov-and@ydb.tech>2023-08-18 17:20:47 +0300
committermolotkov-and <molotkov-and@ydb.tech>2023-08-18 19:42:07 +0300
commit73215359bc33e76f5b94d1832a377072bf245cfc (patch)
tree9cb8ad61d8c3cd107353d42951560ff3cf1b966d /contrib/libs/sasl
parent1cbfd34a55732f7b1d407986b45e40853f01f2c2 (diff)
downloadydb-73215359bc33e76f5b94d1832a377072bf245cfc.tar.gz
KIKIMR-18220: Enrich token with groups from LDAP
Add ldap functions wrapper and separate in different files for compatibility with different OS. Add user groups fetching from ldap server. Limitations: - Fixed 'memberOf' attribute - No tests to check how filter for search created - Fetched groups are returned in event as is.
Diffstat (limited to 'contrib/libs/sasl')
-rw-r--r--contrib/libs/sasl/AUTHORS58
-rw-r--r--contrib/libs/sasl/CMakeLists.darwin-x86_64.txt53
-rw-r--r--contrib/libs/sasl/CMakeLists.linux-aarch64.txt54
-rw-r--r--contrib/libs/sasl/CMakeLists.linux-x86_64.txt54
-rw-r--r--contrib/libs/sasl/CMakeLists.txt15
-rw-r--r--contrib/libs/sasl/CONTRIBUTING.md6
-rw-r--r--contrib/libs/sasl/COPYING44
-rw-r--r--contrib/libs/sasl/ChangeLog3490
-rw-r--r--contrib/libs/sasl/INSTALL.TXT1
-rw-r--r--contrib/libs/sasl/README1
-rw-r--r--contrib/libs/sasl/README.GS23
-rw-r--r--contrib/libs/sasl/README.ldapdb53
-rw-r--r--contrib/libs/sasl/README.md27
-rw-r--r--contrib/libs/sasl/README.release89
-rw-r--r--contrib/libs/sasl/common/plugin_common.c920
-rw-r--r--contrib/libs/sasl/common/plugin_common.h230
-rw-r--r--contrib/libs/sasl/config-linux.h782
-rw-r--r--contrib/libs/sasl/config-osx.h3
-rw-r--r--contrib/libs/sasl/config-win.h221
-rw-r--r--contrib/libs/sasl/config.h9
-rw-r--r--contrib/libs/sasl/include/exits.h118
-rw-r--r--contrib/libs/sasl/include/gai.h108
-rw-r--r--contrib/libs/sasl/include/hmac-md5.h59
-rw-r--r--contrib/libs/sasl/include/md5.h42
-rw-r--r--contrib/libs/sasl/include/md5global.h38
-rw-r--r--contrib/libs/sasl/include/prop.h170
-rw-r--r--contrib/libs/sasl/include/sasl.h1332
-rw-r--r--contrib/libs/sasl/include/sasl/prop.h170
-rw-r--r--contrib/libs/sasl/include/sasl/sasl.h1332
-rw-r--r--contrib/libs/sasl/include/saslplug.h986
-rw-r--r--contrib/libs/sasl/include/saslutil.h99
-rw-r--r--contrib/libs/sasl/lib/auxprop.c1202
-rw-r--r--contrib/libs/sasl/lib/canonusr.c465
-rw-r--r--contrib/libs/sasl/lib/checkpw.c1110
-rw-r--r--contrib/libs/sasl/lib/client.c1317
-rw-r--r--contrib/libs/sasl/lib/common.c2674
-rw-r--r--contrib/libs/sasl/lib/config.c168
-rw-r--r--contrib/libs/sasl/lib/dlopen.c569
-rw-r--r--contrib/libs/sasl/lib/external.c407
-rw-r--r--contrib/libs/sasl/lib/md5.c527
-rw-r--r--contrib/libs/sasl/lib/saslint.h544
-rw-r--r--contrib/libs/sasl/lib/saslutil.c790
-rw-r--r--contrib/libs/sasl/lib/server.c2406
-rw-r--r--contrib/libs/sasl/lib/seterror.c263
-rw-r--r--contrib/libs/sasl/lib/staticopen.h188
-rw-r--r--contrib/libs/sasl/plugins/anonymous.c387
-rw-r--r--contrib/libs/sasl/plugins/cram.c687
-rw-r--r--contrib/libs/sasl/plugins/digestmd5.c4778
-rw-r--r--contrib/libs/sasl/plugins/otp.c1895
-rw-r--r--contrib/libs/sasl/plugins/otp.h311
-rw-r--r--contrib/libs/sasl/plugins/plain.c489
-rw-r--r--contrib/libs/sasl/plugins/sasldb.c317
-rw-r--r--contrib/libs/sasl/plugins/scram.c3087
-rw-r--r--contrib/libs/sasl/sasldb/db_none.c103
-rw-r--r--contrib/libs/sasl/sasldb/sasldb.h134
-rw-r--r--contrib/libs/sasl/ya.make68
56 files changed, 35453 insertions, 0 deletions
diff --git a/contrib/libs/sasl/AUTHORS b/contrib/libs/sasl/AUTHORS
new file mode 100644
index 0000000000..cb70ed8315
--- /dev/null
+++ b/contrib/libs/sasl/AUTHORS
@@ -0,0 +1,58 @@
+Rob Siemborski <rjs3+@andrew.cmu.edu> wrote and tested the conversion
+to the SASLv2 API.
+
+Ken Murchison <murch@andrew.cmu.edu> worked on the OTP, NTLM, SRP and SQL
+plugins, as well as helping to track down bugs as they appear. He also
+added support for HTTP authentication.
+
+Rob Earhart <earhart@cmu.edu> wrote the build/installation procedure,
+wrote and tested some of the code, and provided general guidance and
+coding advice.
+
+Leif Johansson <leifj@matematik.su.se> wrote the GSSAPI plugin, with
+contributions from Sam Hartman <hartmans@fundsxpress.com>.
+
+Leandro Santi <lesanti@sinectis.com.ar> added Courier authdaemon support.
+
+Alexey Melnikov <alexey.melnikov@isode.com> wrote the first pass of the
+DIGEST-MD5 and SCRAM plugins and continues to work on them. He also wrote
+a good deal of the current Windows support.
+
+Rainer Schoepf <schoepf@uni-mainz.de> contributed the LOGIN plugin,
+based on Tim Martin's PLAIN plugin.
+
+Simon Loader <simon@surf.org.uk> wrote the MySQL auxprop module.
+
+Rolf Braun <rbraun@andrew.cmu.edu> wrote the MacOS ports.
+
+Howard Chu <hyc@highlandsun.com> put a good deal of work into OS/390
+portability, correct building of static libraries, and a slew
+of misc. bugfixes.
+
+Tim Martin <tmartin@andrew.cmu.edu> wrote, debugged, and tested
+most of the SASLv1 code.
+
+Larry Greenfield <leg+sasl@andrew.cmu.edu> complained. a lot.
+
+Chris Newman <chris.newman@oracle.com> wrote the initial version of the
+SASL API, as well as the version 2 SASL API (documented in sasl.h,
+saslutil.h, saslplug.h, and prop.h).
+
+Ryan Troll <ryan@andrew.cmu.edu> started the Windows port,
+and both Larry Greenfield and Alexey Melnikov have done more work on it.
+
+getaddrinfo.c was written by Hajimu UMEMOTO <ume@mahoroba.org>
+which is based on the IPv6 code written by KIKUCHI Takahiro
+<kick@kyoto.wide.ad.jp>
+
+Igor Brezac <igor@ipass.net> has done a good deal of work on the saslauthd
+LDAP module.
+
+Jeremy Rumpf <jrumpf@heavyload.net> implemented the credential cache, unified
+the different IPC methods under a common framework.
+
+Fabian Knittel <fknittel@gmx.de> wrote auth_pam plugin, based on
+Debian's pwcheck_pam daemon by Michael-John Turner <mj@debian.org>.
+
+saslauthd was originally contributed by Lyndon Nerenberg on
+behalf of MessagingDirect Ltd.
diff --git a/contrib/libs/sasl/CMakeLists.darwin-x86_64.txt b/contrib/libs/sasl/CMakeLists.darwin-x86_64.txt
new file mode 100644
index 0000000000..ef6e652888
--- /dev/null
+++ b/contrib/libs/sasl/CMakeLists.darwin-x86_64.txt
@@ -0,0 +1,53 @@
+
+# This file was generated by the build system used internally in the Yandex monorepo.
+# Only simple modifications are allowed (adding source-files to targets, adding simple properties
+# like target_include_directories). These modifications will be ported to original
+# ya.make files by maintainers. Any complex modifications which can't be ported back to the
+# original buildsystem will not be accepted.
+
+
+find_package(OpenSSL REQUIRED)
+
+add_library(contrib-libs-sasl)
+target_compile_options(contrib-libs-sasl PRIVATE
+ -DCONFIGDIR="/tmp/yamaker/sasl/out/lib/sasl2:/var/empty/cyrus-sasl-2.1.28/etc/sasl2"
+ -DHAVE_CONFIG_H
+ -DOBSOLETE_CRAM_ATTR=1
+ -DOBSOLETE_DIGEST_ATTR=1
+ -DPLUGINDIR="/tmp/yamaker/sasl/out/lib/sasl2"
+ $<IF:$<CXX_COMPILER_ID:MSVC>,,-Wno-everything>
+)
+target_include_directories(contrib-libs-sasl PRIVATE
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/common
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/include
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/lib
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/plugins
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/sasldb
+)
+target_link_libraries(contrib-libs-sasl PUBLIC
+ OpenSSL::OpenSSL
+)
+target_sources(contrib-libs-sasl PRIVATE
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/common/plugin_common.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/lib/auxprop.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/lib/canonusr.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/lib/checkpw.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/lib/client.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/lib/common.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/lib/config.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/lib/dlopen.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/lib/external.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/lib/md5.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/lib/saslutil.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/lib/server.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/lib/seterror.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/plugins/anonymous.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/plugins/cram.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/plugins/digestmd5.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/plugins/otp.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/plugins/plain.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/plugins/sasldb.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/plugins/scram.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/sasldb/db_none.c
+)
diff --git a/contrib/libs/sasl/CMakeLists.linux-aarch64.txt b/contrib/libs/sasl/CMakeLists.linux-aarch64.txt
new file mode 100644
index 0000000000..f73f25503a
--- /dev/null
+++ b/contrib/libs/sasl/CMakeLists.linux-aarch64.txt
@@ -0,0 +1,54 @@
+
+# This file was generated by the build system used internally in the Yandex monorepo.
+# Only simple modifications are allowed (adding source-files to targets, adding simple properties
+# like target_include_directories). These modifications will be ported to original
+# ya.make files by maintainers. Any complex modifications which can't be ported back to the
+# original buildsystem will not be accepted.
+
+
+find_package(OpenSSL REQUIRED)
+
+add_library(contrib-libs-sasl)
+target_compile_options(contrib-libs-sasl PRIVATE
+ -DCONFIGDIR="/tmp/yamaker/sasl/out/lib/sasl2:/var/empty/cyrus-sasl-2.1.28/etc/sasl2"
+ -DHAVE_CONFIG_H
+ -DOBSOLETE_CRAM_ATTR=1
+ -DOBSOLETE_DIGEST_ATTR=1
+ -DPLUGINDIR="/tmp/yamaker/sasl/out/lib/sasl2"
+ $<IF:$<CXX_COMPILER_ID:MSVC>,,-Wno-everything>
+)
+target_include_directories(contrib-libs-sasl PRIVATE
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/common
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/include
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/lib
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/plugins
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/sasldb
+)
+target_link_libraries(contrib-libs-sasl PUBLIC
+ contrib-libs-linux-headers
+ OpenSSL::OpenSSL
+)
+target_sources(contrib-libs-sasl PRIVATE
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/common/plugin_common.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/lib/auxprop.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/lib/canonusr.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/lib/checkpw.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/lib/client.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/lib/common.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/lib/config.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/lib/dlopen.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/lib/external.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/lib/md5.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/lib/saslutil.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/lib/server.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/lib/seterror.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/plugins/anonymous.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/plugins/cram.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/plugins/digestmd5.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/plugins/otp.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/plugins/plain.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/plugins/sasldb.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/plugins/scram.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/sasldb/db_none.c
+)
diff --git a/contrib/libs/sasl/CMakeLists.linux-x86_64.txt b/contrib/libs/sasl/CMakeLists.linux-x86_64.txt
new file mode 100644
index 0000000000..f73f25503a
--- /dev/null
+++ b/contrib/libs/sasl/CMakeLists.linux-x86_64.txt
@@ -0,0 +1,54 @@
+
+# This file was generated by the build system used internally in the Yandex monorepo.
+# Only simple modifications are allowed (adding source-files to targets, adding simple properties
+# like target_include_directories). These modifications will be ported to original
+# ya.make files by maintainers. Any complex modifications which can't be ported back to the
+# original buildsystem will not be accepted.
+
+
+find_package(OpenSSL REQUIRED)
+
+add_library(contrib-libs-sasl)
+target_compile_options(contrib-libs-sasl PRIVATE
+ -DCONFIGDIR="/tmp/yamaker/sasl/out/lib/sasl2:/var/empty/cyrus-sasl-2.1.28/etc/sasl2"
+ -DHAVE_CONFIG_H
+ -DOBSOLETE_CRAM_ATTR=1
+ -DOBSOLETE_DIGEST_ATTR=1
+ -DPLUGINDIR="/tmp/yamaker/sasl/out/lib/sasl2"
+ $<IF:$<CXX_COMPILER_ID:MSVC>,,-Wno-everything>
+)
+target_include_directories(contrib-libs-sasl PRIVATE
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/common
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/include
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/lib
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/plugins
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/sasldb
+)
+target_link_libraries(contrib-libs-sasl PUBLIC
+ contrib-libs-linux-headers
+ OpenSSL::OpenSSL
+)
+target_sources(contrib-libs-sasl PRIVATE
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/common/plugin_common.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/lib/auxprop.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/lib/canonusr.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/lib/checkpw.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/lib/client.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/lib/common.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/lib/config.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/lib/dlopen.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/lib/external.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/lib/md5.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/lib/saslutil.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/lib/server.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/lib/seterror.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/plugins/anonymous.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/plugins/cram.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/plugins/digestmd5.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/plugins/otp.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/plugins/plain.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/plugins/sasldb.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/plugins/scram.c
+ ${CMAKE_SOURCE_DIR}/contrib/libs/sasl/sasldb/db_none.c
+)
diff --git a/contrib/libs/sasl/CMakeLists.txt b/contrib/libs/sasl/CMakeLists.txt
new file mode 100644
index 0000000000..606ff46b4b
--- /dev/null
+++ b/contrib/libs/sasl/CMakeLists.txt
@@ -0,0 +1,15 @@
+
+# This file was generated by the build system used internally in the Yandex monorepo.
+# Only simple modifications are allowed (adding source-files to targets, adding simple properties
+# like target_include_directories). These modifications will be ported to original
+# ya.make files by maintainers. Any complex modifications which can't be ported back to the
+# original buildsystem will not be accepted.
+
+
+if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA)
+ include(CMakeLists.linux-aarch64.txt)
+elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
+ include(CMakeLists.darwin-x86_64.txt)
+elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA)
+ include(CMakeLists.linux-x86_64.txt)
+endif()
diff --git a/contrib/libs/sasl/CONTRIBUTING.md b/contrib/libs/sasl/CONTRIBUTING.md
new file mode 100644
index 0000000000..6180cc7d9f
--- /dev/null
+++ b/contrib/libs/sasl/CONTRIBUTING.md
@@ -0,0 +1,6 @@
+The Cyrus-SASL project isn't using the Github workflows at the moment.
+
+It's okay (and helpful!) to open Issues and Pull Requests here, but please
+also contact the
+[Cyrus-SASL mailing list](https://cyrus.topicbox.com/groups/sasl)
+or they may not be noticed by anyone who can action them.
diff --git a/contrib/libs/sasl/COPYING b/contrib/libs/sasl/COPYING
new file mode 100644
index 0000000000..3f56f3059c
--- /dev/null
+++ b/contrib/libs/sasl/COPYING
@@ -0,0 +1,44 @@
+/* CMU libsasl
+ * Tim Martin
+ * Rob Earhart
+ * Rob Siemborski
+ */
+/*
+ * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For permission or any other legal
+ * details, please contact
+ * Office of Technology Transfer
+ * Carnegie Mellon University
+ * 5000 Forbes Avenue
+ * Pittsburgh, PA 15213-3890
+ * (412) 268-4387, fax: (412) 268-7395
+ * tech-transfer@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Computing Services
+ * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
diff --git a/contrib/libs/sasl/ChangeLog b/contrib/libs/sasl/ChangeLog
new file mode 100644
index 0000000000..6a547fa8ea
--- /dev/null
+++ b/contrib/libs/sasl/ChangeLog
@@ -0,0 +1,3490 @@
+2016-10-18 Ken Murchison <murch@andrew.cmu.edu>
+ * Fixed potential DoS attack on saslauthd/doors (from Oracle)
+
+2016-06-30 Ken Murchison <murch@andrew.cmu.edu>
+ * plugins/ntlm.c, otp.c: support OpenSSL 1.1
+
+2016-06-14 Ken Murchison <murch@andrew.cmu.edu>
+ * plugins/digestmd5.c: Fix memory leak in client step 2
+
+2016-03-24 Ken Murchison <murch@andrew.cmu.edu>
+ * auth_rimap.c: Don't hang when IMAP server closes connection
+
+2016-01-29 Ken Murchison <murch@andrew.cmu.edu>
+ * Build fixes from Ignacio Casal Quinteiro
+
+2015-12-26 Ken Murchison <murch@andrew.cmu.edu>
+ * Build fixes from Ignacio Casal Quinteiro
+
+2015-11-16 Ken Murchison <murch@andrew.cmu.edu>
+ * Build fixes from Ignacio Casal Quinteiro
+
+2015-10-14 Ken Murchison <murch@andrew.cmu.edu>
+ * Build fixes from Ignacio Casal Quinteiro
+
+2015-07-17 Ken Murchison <murch@andrew.cmu.edu>
+ * auth_krb5.c: added krb5_conv_krb4_instance option
+
+2014-11-17 Ken Murchison <murch@andrew.cmu.edu>
+ * plugins/digestmd5.c: Fix memory leaks
+
+2014-11-17 Ken Murchison <murch@andrew.cmu.edu>
+ * plugins/digestmd5.c: prevent going from step 3 to step 2
+
+2013-09-13 Alexey Melnikov <alexey.melnikov@isode.com>
+ * Fix memory leaks in DIGEST
+
+2013-08-30 Ken Murchison <murch@andrew.cmu.edu>
+ * plugins/digestmd5.c: only locate reauth cache when reauth is
+ enabled
+
+2013-07-11 Alexey Melnikov <alexey.melnikov@isode.com>
+ * Treat SCRAM and DIGEST as more secure than PLAIN when selecting
+ client-side mechanism
+
+2013-07-11 Alexey Melnikov <alexey.melnikov@isode.com>
+ * Handle NULL return from crypt()
+
+2012-11-20 Alexey Melnikov <alexey.melnikov@isode.com>
+ * Added support for lmdb
+
+2012-11-19 Alexey Melnikov <alexey.melnikov@isode.com>
+ * Final 2.1.26 tagged and released by Ken.
+
+2012-07-06 Alexey Melnikov <alexey.melnikov@isode.com>
+ * saslauthd/auth_krb5.c: Fixed a crash in the auth_krb5.c
+ (bug # 2706). Patch by Nalin Dahyabhai.
+
+2012-07-03 Alexey Melnikov <alexey.melnikov@isode.com>
+ * config/ltconfig: Fixed incorrect Darwin version matching in ltconfig
+ (bug # 3713). Patch by Joshua Root.
+
+2012-06-08 Alexey Melnikov <alexey.melnikov@isode.com>
+ * Fixed PLAIN/LOGIN authentication failure when using saslauthd
+ with no auxprop plugins (bug # 3590).
+
+2012-06-08 Alexey Melnikov <alexey.melnikov@isode.com>
+ * Added generation of pkg-config .pc file for Cyrus SASL.
+ Patch by Dilyan Palauzov.
+
+2012-06-03 Alexey Melnikov <alexey.melnikov@isode.com>
+ * Correctly updated libtool version for libsasl and its plugins due
+ to ABI changes (bug # 3692).
+
+2012-06-02 Alexey Melnikov <alexey.melnikov@isode.com>
+ * Better error reporting from auth_getpwent.c/auth_shadow.c
+ (bug # 3134). Based on a patch by Greg A. Woods.
+
+2012-06-02 Alexey Melnikov <alexey.melnikov@isode.com>
+ * Improved error logging on failure to load plugins.
+ Patch by Greg A. Woods.
+
+2012-05-30 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/otp.c, plugins/srp.c: Removed calling of EVP_cleanup()
+ on SRP/OTP plugin shutdown
+
+2012-05-30 Alexey Melnikov <alexey.melnikov@isode.com>
+ * saslauthd/auth_httpform.c: Encode the parameter values passed to
+ auth_httpform, not the whole POST data.
+
+2012-05-30 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/config.c, saslauthd/cfile.c: Fixed file descriptor leaks
+ throughout the code (bug # 3702). Slightly reformatted patch
+ by Manfred Weichel.
+
+2012-05-29 Alexey Melnikov <alexey.melnikov@isode.com>
+ * bug in "saslauthd -a rimap" - not reading the whole IMAP greeting
+ (bug # 3211). Patch from Lutz Mark (via Red Hat)
+
+2012-05-29 Alexey Melnikov <alexey.melnikov@isode.com>
+ * Modernize SASL malloc/realloc callback prototypes
+
+2012-05-29 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/saslutil.c: Fixed broken logic in get_fqhostname() when
+ abort_if_no_fqdn is 0 (bug # 3589). Patch by baggins@pld-linux.org
+
+2012-05-28 Alexey Melnikov <alexey.melnikov@isode.com>
+ * sasldb/db_berkeley.c, utils/dbconverter-2.c: Added support for
+ BerkleyDB 5.X or later (Patch by Howard Chu)
+
+2012-04-20 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/client.c, lib/server.c, lib/saslint.h: Make server and client
+ side global callbacks private to server.c/client.c respectively
+
+2012-02-10 Ken Murchison <murch@andrew.cmu.edu>
+ * plugins/digestmd5.c: better handling of HTTP reauth cases.
+
+2012-01-28 Ken Murchison <murch@andrew.cmu.edu>
+ * plugins/digestmd5.c: Correctly send "stale" directive to prevent
+ clients from (re)promtping for password
+
+2011-11-25 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/gs2.c: Updated GS2 plugin not to lose minor GSS-API
+ status codes on errors (based on a patch from Ralf Haferkamp
+ <rhafer@suse.de>)
+
+2011-11-21 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/gssapi.c: Only check out_flags once authentication is
+ successfully completed
+
+2011-11-09 Ken Murchison <murch@andrew.cmu.edu>
+ * cmulocal/sasl2.m4, plugins/gssapi.c, utils/testsuite.c:
+ Added GSS-SPNEGO plugin which can also be used for HTTP
+ Negotiate authentication (RFC 4559)
+
+2011-11-08 Ken Murchison <murch@andrew.cmu.edu>
+ * plugins/ntlm.c: Flag client-side of NTLM plugin as HTTP-ready
+
+2011-11-08 Ken Murchison <murch@andrew.cmu.edu>
+ * include/saslutil.h, lib/config.c, lib/server.c
+ Added sasl_config_done() to plug a memory leak when using an
+ application specific config file
+
+2011-10-07 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/gssapi.c: Fixed a segfault in gssapi.c
+ (patch by Phil Pennock)
+
+2011-09-22 Alexey Melnikov <alexey.melnikov@isode.com>
+ * config/ltconfig, saslauthd/config/ltconfig: Fixed Cyrus SASL
+ build on some versions of Mac OS.
+
+2011-09-22 Alexey Melnikov <alexey.melnikov@isode.com>
+ * saslauthd/auth_rimap.c: qstring incorrectly appending
+ the closing double quote. (Merge from RedHat)
+
+2011-09-22 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/common.c: unlock the mutex in sasl_dispose if the context
+ was freed by another thread. (Merge from RedHat)
+
+2011-09-22 Alexey Melnikov <alexey.melnikov@isode.com>
+ * Makefile.am: "lib" should be built before "plugins"
+ (Patch from marcandre.lureau@redhat.com)
+
+2011-09-22 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/saslutil.c: MINGW32 doesn't have rand_s
+ (Patch from marcandre.lureau@redhat.com)
+
+2011-09-22 Alexey Melnikov <alexey.melnikov@isode.com>
+ * configure.in: Various build fixes for MINGW32
+ (including defining sleep())
+ (Patch from marcandre.lureau@redhat.com)
+
+2011-09-15 Alexey Melnikov <alexey.melnikov@isode.com>
+ * sample/client.c: Added additional typecasts to kill warnings
+ about incompatible callback types
+
+2011-09-13 Alexey Melnikov <alexey.melnikov@isode.com>
+ * configure.in, config/ltconfig, config/ltmain.sh:
+ MacOS X related build fixes: use .plugin when building
+ SASL plugins, fixed version number calculation,
+ don't generate multiple symlinks.
+ Also use LD_RUN_PATH as rpath. (patches by Chris Ridd)
+
+2011-09-12 Alexey Melnikov <alexey.melnikov@isode.com>
+ * win32/common.mak: Add _CRT_SECURE_NO_DEPRECATE define
+ to suppress warnings about use of strdup, snprintf, etc.
+
+2011-09-12 Alexey Melnikov <alexey.melnikov@isode.com>
+ * sasldb/db_berkeley.c:
+ Fixed warnings about incompatible callback types.
+
+2011-09-12 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/NTMakefile plugins/NTMakefile:
+ Make sure that copied .c files are only rebuilt when changed.
+
+2011-09-07 Ken Murchison <murch@andrew.cmu.edu>
+ * plugins/scram.c:
+ Fixed 3 memory leaks in SCRAM. Final 2.1.25.
+
+2011-09-07 Alexey Melnikov <alexey.melnikov@isode.com>
+ * configure.in, plugins/NTMakefile, plugins/cram.c:
+ Allow use of cmusaslsecretCRAM-MD5 property to be disabled.
+
+2011-09-02 Alexey Melnikov <alexey.melnikov@isode.com>
+ * config/config.guess, config/config.sub,
+ saslauthd/config/config.guess, saslauthd/config/config.sub:
+ Updated config to the latest GNU snapshot.
+
+2011-09-01 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/server.c: Make sure that a failed authorization doesn't preclude
+ further SASL authentication attempts from working.
+
+2011-09-01 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/server.c: Fixed some aspects of mech_avail callback handling
+ in the server side SASL code.
+
+2011-09-01 Alexey Melnikov <alexey.melnikov@isode.com>
+ * config/ltconfig, saslauthd/config/ltconfig: Fix SASL's libtool
+ MacOS/X 64-bit file magic. (Patch by Kurt Zeilenga)
+
+2011-09-01 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/scram.c: Fixed some additional Windows warnings and
+ a memory leak in SCRAM.
+
+2011-09-01 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/scram.c: Fix size_t * v. unsigned * bug.
+ (Patch by Kurt Zeilenga)
+
+2011-09-01 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/server.c: Fixed a crash caused by aborted SASL authentication
+ and initiation of another one using the same SASL context.
+
+2011-09-01 Alexey Melnikov <alexey.melnikov@isode.com>
+ * include/md5.h, include/sasl.h, include/saslplug.h, lib/auxprop.c,
+ lib/canonusr.c, lib/client.c, lib/common.c, lib/saslint.h, lib/server.c,
+ lib/seterror.c, plugins/otp.c, plugins/plugin_common.c,
+ sasldb/db_berkeley.c, sample/sample-client.c, sample/sample-server.c,
+ utils/pluginviewer.c, utils/sasldblistusers.c, utils/saslpasswd.c,
+ utils/testsuite.c: Many of the SASL includes define function pointers
+ without specifying arguments. In C, the () is treated as unspecified,
+ rather than (void), hence this is technically not a prototype,
+ and gcc warns about it. (Patch by Dave Cridland and Alexey Melnikov)
+
+2011-09-01 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/server.c: Better server plugin API mismatch reporting
+
+2011-05-23 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/gs2.c, plugins/gs2_token.c, plugins/gs2_token.h,
+ cmulocal/sasl2.m4: Use draft-josefsson-gss-capsulate-01 if present.
+ Negative SASL errors are fatal. (Patch from Luke Howard.)
+
+2011-05-13 Ken Murchison <murch@andrew.cmu.edu>
+ * include/sasl.h, plugins/digest-md5.c:
+ Allow for non-persistent connections when using DIGEST-MD5 plugin
+ for server-side HTTP Digest (RFC 2617). Also make sure that an
+ HTTP request is handed to plugin when required.
+
+2011-04-19 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/gssapi.c: Fix to build GSSAPI with Heimdal (patch from
+ Russ Allbery from Debian)
+
+2011-04-18 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/gs2_token.h: Added gs2_token.h for the "make dist" target
+ (patch by Dan White)
+
+2011-04-13 Alexey Melnikov <alexey.melnikov@isode.com>
+ * cmulocal/sasl2.m4: Only enable GS2 plugin if
+ gss_inquire_mech_for_saslname is defined in gssapi.h
+
+2011-04-12 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/Makefile.am, plugins/makeinit.sh, plugins/ldapdb.c:
+ LDAPDB build fixes from Dan White
+
+2011-04-05 Alexey Melnikov <alexey.melnikov@isode.com>
+ * configure.in, plugins/Makefile.am, plugins/NTMakefile,
+ plugins/makeinit.sh, lib/staticopen.h, win32/include/config.h:
+ Enabled SCRAM plugin build
+
+2011-03-25 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/Makefile.am, plugins/makeinit.sh, plugins/gs2_token.h,
+ plugins/gs2_token.c, README.GS2, cmulocal/sasl2.m4: GS2 plugin
+ from Luke Howard
+
+2011-01-25 Ken Murchison <murch@andrew.cmu.edu>
+ * include/sasl.h, include/saslplug.h, lib/client.c, lib/common.c,
+ plugins/digest-md5.c sample/http_digest_client.c:
+ Allow DIGEST-MD5 plugin to be used for client-side
+ HTTP Digest (RFC 2617)
+
+2011-01-21 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/scram.c: Added support for channel bindings to SCRAM-SHA-1.
+
+2011-01-21 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/client.c, lib/server.c, lib/common.c, lib/saslint.h: Fixed libsasl
+ to accept *-PLUS SASL mechanism names in client_mech_list/mech_list
+ options. As *-PLUS mechanism names were synthesized and didn't
+ correspond to real plugin names, setting client_mech_list to
+ "SCRAM-SHA-1-PLUS" (for example) was resulting in authentication
+ failure due to inability to find a matching SASL plugin.
+
+2011-01-21 Alexey Melnikov <alexey.melnikov@isode.com>
+ * include/saslplug.h, lib/client.c: Fixed handling of channel bindings
+ on the client side. The client side was failing to select a suitable
+ SASL mechanism when the application specified channel bindings, but
+ didn't make them mandatory to use. In such a configuration, if a
+ non channel binding capable mechanism was selected through
+ "client_mech_list" SASL option, sasl_client_start would fail.
+ For example if the server supports both SCRAM-SHA-1[-PLUS] and
+ PLAIN and "client_mech_list" was set to "PLAIN", authentication
+ would never work.
+
+2011-01-21 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/client.c, lib/server.c: Better default ordering of SASL mechanisms.
+ Ordering by plugins max_ssf produces wrong result in case an application
+ using SASL doesn't care about SASL security layers. Before this change
+ DIGEST-MD5 was always preferred over SCRAM-SHA-1[-PLUS]. In particular
+ this change takes support for channel bindings into considerations.
+
+2011-01-19 Ken Murchison <murch@andrew.cmu.edu>
+ * include/sasl.h, include/saslplug.h,
+ lib/common.c, lib/server.c, plugins/digest-md5.c:
+ Changed server-side of HTTP Digest so that the application
+ must pass an HTTP Request structure (Method/URI/Entity-Body)
+ rather than just the HTTP Method
+
+2011-01-19 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/server.c: Server side SASL context should list *-PLUS SASL
+ mechanisms before the corresponding non-PLUS mechanisms for naive
+ SASL clients.
+
+2011-01-19 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/common.c: Fixed some Windows warnings in SASL security layer
+ handling.
+
+2011-01-19 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/scram.c: Made the default number of SCRAM hash iterations
+ configurable using a new SASL option called "scram_iteration_counter".
+ Also fixed a couple of error messages.
+
+2011-01-19 Alexey Melnikov <alexey.melnikov@isode.com>
+ * utils/pluginviewer.c: Fixed some Linux warnings in pluginviewer.
+
+2011-01-19 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/scram.c: Added support for storing SCRAM secrets in
+ authPassword attribute. Also added the "scram_secret_generate" option
+ for controlling if authPassword SCRAM secret should be generated
+ or not. By default (when not specified) the authPassword SCRAM secret
+ is NOT generated.
+
+2011-01-19 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/scram.c: Updated the SCRAM plugin not to use the hardcoded
+ SCRAM-SHA-1 plugin name in logging.
+
+2011-01-18 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/digestmd5.c: Use the same username for reauthentication
+ cache lookup and update. Thanks to Ken for pointing out the
+ problem.
+
+2011-01-14 Ken Murchison <murch@andrew.cmu.edu>
+ * plugins/ntlm.c: Flag NTLM plugin as HTTP-ready
+
+2011-01-14 Ken Murchison <murch@andrew.cmu.edu>
+ * include/sasl.h, include/saslplug.h,
+ lib/common.c, lib/server.c, plugins/digest-md5.c:
+ Allow DIGEST-MD5 plugin to be used for server-side
+ HTTP Digest (RFC 2617)
+
+2010-12-01 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/server.c: Some reformatting and safer handling of 'free
+ after SASL server shutdown' condition in server_dispose.
+
+2010-12-01 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/server.c: server_idle needs to obey server's SASL mechanism
+ list from the server context.
+
+2010-12-01 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/client.c, lib/saslint.h: Added support for ordering
+ SASL mechanisms by strength (on the client side),
+ or using the client_mech_list option.
+
+2010-12-01 Alexey Melnikov <alexey.melnikov@isode.com>
+ * include/sasl.h, include/saslplug.h, lib/client.c, lib/common.c,
+ lib/saslint.h, lib/server.c, sample/Makefile.am, sample/client.c,
+ sample/server.c: Added support for channel bindings
+ (patch by Luke Howard).
+
+2010-12-01 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/saslutil.c: Fixed the random number generator on Windows
+ to actually produce random output on each run.
+
+2010-12-01 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/common.c: Updated textual representations of some error
+ messages
+
+2010-11-30 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/digestmd5.c: Eliminated some "signed/unsigned mismatch"
+ warnings.
+
+2010-11-30 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/digestmd5.c, plugins/srp.c, plugins/otp.c,
+ plugins/ntlm.c, plugins/login.c, plugins/cram.c:
+ Be protective against calling sasl_server_step
+ once authentication has failed.
+
+2010-11-30 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/digestmd5.c: Minimize the number of auxprop lookups
+ in the server side DIGEST-MD5 plugin for the most common
+ case when authentication and authorization identities are
+ the same.
+
+2010-11-30 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/digestmd5.c: Updated digestmd5_server_mech_step2()
+ to be more defensive against empty client input.
+
+2010-11-30 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/digestmd5.c: Fixed some memory leaks on failed
+ plugin initialization. Prevent potential race condition
+ when freeding plugin state. Set the freed reauthentication
+ cache mutex to NULL, to make errors due to mutex access
+ after free more obvious.
+
+2010-11-30 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/digestmd5.c: Test against broken UTF-8 based hashes
+ if calculation using special ISO-8859-1 code fails.
+ This affected some XMPP clients. Patch by Dave Cridland
+ <dave.cridland@isode.com>.
+
+2010-11-30 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/digestmd5.c: Fixed an interop problem with some
+ LDAP clients ignoring server advertised realm
+ and providing their own.
+
+2009-08-14 Alexey Melnikov <alexey.melnikov@isode.com>
+ * saslauthd/auth_shadow.c: Rolled back the previous commit
+ (#define _XOPEN_SOURCE before including unistd.h),
+ as this seems to break Solaris 8 build. Note that crypt.h
+ should be present on a Solaris 8 machine, as well is on Debian,
+ so this shouldn't be a problem.
+
+2009-08-04 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/gssapi.c: Properly set serveroutlen to 0 in one place.
+ Don't send empty challenge once server context establishment is done,
+ as this is in violation of the RFC 2222 and its successor.
+
+2009-07-24 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/gssapi.c: Don't send maxbuf, if no security layer
+ can be established. Added additional checks for buffer lengths.
+
+2009-05-20 Ken Murchison <murch@andrew.cmu.edu>
+ * configure.in, cmulocal/sasl2.m4,
+ config/kerberos_v4.m4, config/plain.m4, config/sasldb.m4,
+ lib/Makefile.am: Fixes to allow static libs to be built in the
+ CMU build environment
+
+2009-05-07 Ken Murchison <murch@andrew.cmu.edu>
+ * configure.in, include/sasl.h, lib/Makefile.am,
+ plugins/Makefile.am, saslauthd/configure.in, sasldb/Makefile.am,
+ win32/common.mak, win32/include/config.h: 2.1.24
+
+2009-05-03 Alexey Melnikov <alexey.melnikov@isode.com>
+ * sample/sample-client.c, sample/sample-server.c, utils/smtptest.c:
+ Fixed bug # 2895 (passing LF to sasl_decode64)
+
+2009-05-03 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/NTMakefile: Disabled annoying warnings about use of
+ deprecated standard C library functions, enabled
+ warnings about Windows64 portability
+
+2009-05-03 Alexey Melnikov <alexey.melnikov@isode.com>
+ * configure.in: Added support for SQLite3
+ (patch by Maxim Gorbachyov)
+
+2009-04-27 Ken Murchison <murch@andrew.cmu.edu>
+ * lib/saslutil.c: Fixed CERT VU#238019 (make sure sasl_encode64()
+ always NUL terminates output or returns SASL_BUFOVER).
+
+2009-04-11 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/sql.c: Fixed SQLite lookup function.
+ Also fixed SASL PLAIN authentication when used with
+ SQLite auxprop backend.
+
+2009-04-11 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/dlopen.c: Updated to use .plugin extension on MacOS
+
+2009-04-08 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/client.c, lib/server.c: Removed unused mutexes
+ (bug # 3141)
+
+2009-03-10 Alexey Melnikov <alexey.melnikov@isode.com>
+ * include/sasl.h, include/saslplug.h, lib/canonusr.c,
+ lib/checkpw.c, plugins/sasldb.c, plugins/sql.c:
+ Added direct support for hashed password to auxprop API
+
+2009-03-10 Alexey Melnikov <alexey.melnikov@isode.com>
+ * include/sasl.h, lib/canonusr.c, lib/external.c,
+ plugins/gssapi.c, plugins/kerberos4.c: Make auxprop lookup
+ calls in SASL GSSAPI/EXTERNAL optional
+
+2009-03-10 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/sasldb.c: A better fix for spurious 'user not found'
+ errors caused by an attempt to delete a non-existent property
+
+2009-02-21 Alexey Melnikov <alexey.melnikov@isode.com>
+ * include/saslutil.h, lib/saslint.h: Made sasl_config_init public
+
+2009-02-20 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/saslint.h, lib/client.c, lib/common.c, lib/server.c:
+ Make sure that sasl_set_alloc() has no effect once sasl_client_init()
+ or sasl_server_init() is called [patch from Debian by
+ fabbe@debian.org]
+
+2009-02-20 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/digestmd5.c: GCC 4.4 requires that the #elif
+ preprocessor directive have a test condition [patch from Debian by
+ fabbe@paniq.net]
+
+2009-02-20 Alexey Melnikov <alexey.melnikov@isode.com>
+ * saslauthd/lak.c: Define LDAP_DEPRECATED so that ldap_get_values
+ is properly defined when compiling [patch from Debian by
+ Dann Frazier <dannf@debian.org>]
+
+2009-02-20 Alexey Melnikov <alexey.melnikov@isode.com>
+ * saslauthd/auth_sasldb.c: pid_file_lock is created with a mask
+ of 644 instead of 0644 [patch from Debian by Sam Hocevar <sam@zoy.org>]
+
+2009-02-20 Alexey Melnikov <alexey.melnikov@isode.com>
+ * saslauthd/auth_sasldb.c: Include config.h so that MAXHOSTNAMELEN
+ is available when building on hurd-i386 [patch from Debian
+ by mbanck@debian.org]
+
+2009-02-20 Alexey Melnikov <alexey.melnikov@isode.com>
+ * saslauthd/auth_shadow.c: Define _XOPEN_SOURCE before including
+ unistd.h, so that crypt is correctly defined [patch from Debian
+ by dannf@debian.org]
+
+2009-02-14 Alexey Melnikov <alexey.melnikov@isode.com>
+ * utils/pluginviewer.c: Code cleanup, improved human readable messages
+
+2009-02-14 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/config.c: Strip trailing spaces from config file option
+ values (bug # 3139, bug # 3041)
+
+2009-02-14 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/otp.c: Don't use a stack variable for an OTP prompt
+ (bug # 2822)
+
+2009-02-13 Alexey Melnikov <alexey.melnikov@isode.com>
+ * saslauthd/auth_getpwent.c: Fixed Solaris build (patch by Leena
+ Heino for bug # 2666)
+
+2009-02-13 Alexey Melnikov <alexey.melnikov@isode.com>
+ * include/saslplug.h, lib/server.c, plugins/anonymous.c,
+ plugins/gssapi.c, plugins/otp.c: Partial support for the
+ SASL_FEAT_DONTUSE_USERPASSWD feature
+
+2009-01-28 Alexey Melnikov <alexey.melnikov@isode.com>
+ * include/sasl.h, lib/auxprop.c, lib/common.c, lib/server.c:
+ Don't treat a constraint violation as an error to store an auxprop
+ property
+
+2009-01-28 Alexey Melnikov <alexey.melnikov@isode.com>
+ * include/sasl.h, lib/server.c: Extended libsasl (auxprop) to support
+ user deletion
+
+2009-01-28 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/otp.c: Downgrade the failure to store OTP secret to debug level
+
+2009-01-25 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/windlopen.c: Free handles of shared libraries on Windows
+ that were loaded but are not SASL plugins (patch by Petr Prazak)
+ [Bug # 2089].
+
+2008-11-23 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/NTMakefile, win32/common.mak: Added support for building
+ SQLite3 on Windows.
+
+2008-11-23 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/ldapdb.c: Updated LDAPDB lookup function to match auxprop
+ API changes
+
+2008-11-15 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/sql.c: Added SQLITE3 support (patch by Maxim Gorbachyov)
+
+2008-10-31 Ken Murchison <murch@andrew.cmu.edu>
+ * lib/saslint.h, lib/server.c: order advertised mechanisms
+ per the specified 'mech_list' option or by relative "strength"
+
+2008-10-30 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/digestmd5.c: Fixed more portability warnings.
+ Fixed some rare memory leaks. More detailed error reporting.
+
+2008-10-30 Alexey Melnikov <alexey.melnikov@isode.com>
+ * win32/include/config.h, lib/canonusr.c, lib/config.c,
+ sasldb/allockey.c, utils/saslpasswd.c, utils/testsuite.c,
+ sample/sample-server.c, plugins/anonymous.c, plugins/digestmd5.c,
+ plugins/login.c, plugins/ntlm.c, plugins/otp.c:
+ Fixed Windows 64 portability and other types of warnings
+
+2008-10-29 Alexey Melnikov <alexey.melnikov@isode.com>
+ * win32/common.mak: Added support for building libraries.
+ Added support for Windows64.
+
+2008-10-29 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/common.c: Prevent freeing of common state on a subsequent
+ call to _sasl_common_init. Make sure that the last global callback
+ always wins.
+
+2008-10-29 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/saslint.h, lib/canonusr.c, lib/checkpw.c, lib/client.c,
+ lib/server.c: Further fixes to auxprop lookup and _sasl_canon_user
+ cleanup
+
+2008-10-29 Alexey Melnikov <alexey.melnikov@isode.com>
+ * include/saslplug.h, lib/auxprop.c, lib/canonusr.c, lib/saslint.h,
+ plugins/sasldb.c, plugins/sql.c:
+ Extended SASL auxprop_lookup to return error code
+
+2008-10-29 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/saslutil.c: Fixed Mac OS X 10.3 build.
+
+2008-10-29 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/sql.c: Uninitialized variables cause crash when
+ the searched user is not found (patch from
+ Maxim Gorbachyov <maxim.gorbachyov@gmail.com>)
+
+2008-10-23 Alexey Melnikov <alexey.melnikov@isode.com>
+ * sasldb/db_berkeley.c: Return SASL_NOUSER instead of SASL_FAIL
+ when the database file doesn't exist
+
+2008-10-23 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/checkpw.c: Updated sasl_user_exists so that it can handle
+ passwordless accounts (e.g. disabled)
+
+2008-10-23 Alexey Melnikov <alexey.melnikov@isode.com>
+ * include/saslutil.h, lib/saslint.h, lib/client.c, lib/common.c,
+ lib/saslutil.c, lib/server.c: Added hostname canonicalization
+
+2008-10-22 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/NTMakefile, utils/NTMakefile, sample/NTMakefile,
+ plugins/NTMakefile: Updated to build with VC 8.0 (VC++ 2005)
+
+2008-10-22 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/NTMakefile: Don't install .exp and .manifest files.
+ Updated build dependencies.
+
+2008-10-21 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/saslint.h, lib/client.c, lib/common.c, lib/server.c:
+ Implemented sasl_client_done/sasl_server_done
+
+2008-10-19 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/login.c, plugins/plain.c: Advertise
+ SASL_SEC_PASS_CREDENTIALS feature in PLAIN and LOGIN
+
+2008-10-02 Ken Murchison <murch@andrew.cmu.edu>
+ * lib/checkpw.c: Fixed potential buffer overflow in
+ saslautd_verify_password().
+
+2008-09-30 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/common.c: Fixed sasl_set_mutex() to disallow changing
+ mutex management functions once sasl_server_init/
+ sasl_client_init is called. Failure to do this is causing
+ a crash while locking mutexes. [Bug # 3083]
+
+2008-01-24 Ken Murchison <murch@andrew.cmu.edu>
+ * plugins/ntlm.c: Fixed crash in calculating NTv2 reponse
+ (patch from Tim Costen from Isode)
+
+2008-01-23 Ken Murchison <murch@andrew.cmu.edu>
+ * plugins/ntlm.c, doc/options.html: allow a comma separated
+ list of servernames in 'ntlm_server' option
+ (patch from Enrico Persiani <enrico@ninfea-soft.org>)
+
+2008-01-23 Ken Murchison <murch@andrew.cmu.edu>
+ * plugins/ldapdb.c, plugins/makeinit.sh, doc/options.html:
+ Added code to extend ldapdb into a canon_user plugin
+ in addition to its existing auxprop plugin functionality
+ (patch from Howard Chu <hyc@symas.com>
+ and Torsten Schlabach <tschlabach@gmx.net>)
+
+2008-01-23 Ken Murchison <murch@andrew.cmu.edu>
+ * saslauthd/auth_rimap.c: fixed bug counting double-quotes in
+ username/password. Also fixed bug zeroing password.
+ (patch from Robert Sanderson <rwsiv1@gmail.com>)
+
+2008-01-23 Ken Murchison <murch@andrew.cmu.edu>
+ * saslauthd/auth_krb.c: improved diagnostic in the
+ k5support_verify_tgt() function. Now, detailed krb5 error
+ information will be given out in the LOG_DEBUG syslog
+ channel (based on patch from Enrico Scholz
+ <enrico.scholz@informatik.tu-chemnitz.de>)
+
+2007-06-13 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/dlopen.c: 64bit HP-UX uses .so for shared libraries
+ (patch by Nathan Kinder <nkinder@redhat.com>).
+
+2007-06-13 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/digestmd5.c: Fixed a memory leak in the DIGEST-MD5
+ security layer (based on patch from Nathan Kinder
+ <nkinder@redhat.com>).
+
+2007-05-14 Alexey Melnikov <alexey.melnikov@isode.com>
+ * man/*: updated to reference RFC 4422 instead of
+ RFC 2222.
+
+2007-03-02 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/sasldb.c, plugins/sql.c: Ignore properties
+ starting with '*' in the auxprop store function.
+
+2007-02-14 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/digestmd5.c: Fixed parsing of challenges/
+ responses with extra commas.
+
+2007-01-29 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/gssapi.c: Check that params->serverFQDN is
+ not NULL before using strlen on it (reported by
+ Steven Simon <simon.s@apple.com>)
+
+2006-12-01 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/common.c: Typecast iov_base to (char *),
+ in case it is defined as "void *" on a platform
+ like HPUX (Olaf Flebbe).
+
+2006-11-27 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/digestmd5.c: Cleaned up comments and
+ some error messages.
+
+2006-08-24 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/dlopen.c: Fixed segfault in dlclose on HPUX,
+ based on feedback from <biswatosh2001@yahoo.com>.
+
+2006-07-16 Alexey Melnikov <alexey.melnikov@isode.com>
+ * win32/common.mak: Abstracted out compiler command
+ line options for exception handling.
+
+2006-07-04 Alexey Melnikov <alexey.melnikov@isode.com>
+ * saslauthd/auth_shadow.c: Include crypt.h, so that crypt()
+ is defined. This fixes crash on x64 Suse where
+ sizeof(int) != sizeof(char *). Based on patch from
+ rhafer@suse.de.
+
+2006-06-26 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/digestmd5.c: Allow for multiple qop options
+ from the server and require a single qop option
+ from the client.
+
+2006-05-19 Ken Murchison <murch@andrew.cmu.edu>
+ * Makefile.am: include INSTALL.TXT in distro
+ *** Ready for 2.1.22
+
+2006-05-18 Ken Murchison <murch@andrew.cmu.edu>
+ * cmulocal/sasl2.m4: patch to compile with MIT krb5 1.4.3
+ (Philip Guenther <guenther@sendmail.com>)
+
+2006-05-18 Alexey Melnikov <alexey.melnikov@isode.com>
+ * configure.in: Fixed default value in help for the
+ --with-authdaemond command line option (Philip Guenther).
+
+2006-05-17 Alexey Melnikov <alexey.melnikov@isode.com>
+ * NEWS: Ready for 2.1.22
+
+2006-05-17 Alexey Melnikov <alexey.melnikov@isode.com>
+ * utils/Makefile.am: enable pluginviewer in the default build.
+
+2006-04-26 Ken Murchison <murch@andrew.cmu.edu>
+ * lib/server.c: call do_authorization() after successful APOP
+
+2006-04-26 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/digestmd5.c: If neither DES nor RC4 cipher is selected,
+ advertise maxssf of 1 (integrity protection).
+
+2006-04-26 Alexey Melnikov <alexey.melnikov@isode.com>
+ * utils/pluginviewer.c: Must set fully qualified domain name
+ in sasl_client_new, or some plugins will not be shown.
+
+2006-04-26 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/client.c: Replaced wrong "break" statement with
+ "continue" in the client side list function.
+
+2006-04-25 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/NTMakefile: Enable RC4 cipher in Windows build.
+
+2006-04-25 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/digestmd5.c: Make sure that SASL packets
+ shorter than 16 bytes don't cause buffer overrun.
+ Also prevent an error report from BoundsChecker
+ regarding pointer being out of range.
+
+2006-04-25 Alexey Melnikov <alexey.melnikov@isode.com>
+ * win32/common.mak: Fixed bug of not setting CODEGEN
+ (code generation option) if STATIC is set.
+
+2006-04-24 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/passdss.c, plugins/srp.c: Added include files required
+ by OpenSSL 0.9.8 (original patch by Dan Nicholson).
+
+2006-04-24 Alexey Melnikov <alexey.melnikov@isode.com>
+ * utils/NTMakefile: testsuite.exe doesn't depend on saslSASLDB.dll.
+
+2006-04-24 Alexey Melnikov <alexey.melnikov@isode.com>
+ * doc/windows.html: Updated Windows build instructions.
+
+2006-04-20 Alexey Melnikov <alexey.melnikov@isode.com>
+ * utils/testsuite.c: Removed sasl_encode test which is no longer
+ valid due to changed in sasl_encodev.
+ Also properly terminated all property request lists with NULL.
+
+2006-04-19 Ken Murchison <murch@andrew.cmu.edu>
+ * saslauthd/auth_shadow.c, saslauthd/configure.in: Check for 4/5
+ argument versions of getXXname_r().
+
+2006-04-19 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/common.c: Andrey V. Malyshev pointed out that the SASL
+ context is always NULL when the default logging callback
+ _sasl_syslog is called. In particular this means that
+ the log_level configuration option is always ignored.
+
+2006-04-19 Alexey Melnikov <alexey.melnikov@isode.com>
+ * configure.in: Search for application configuration
+ files in /usr/lib/sasl2 by default and fall back to
+ /etc/sasl2 if not found.
+
+2006-04-19 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/digestmd5.c: Handle missing realm option from
+ the client as the empty string. This match the behavior
+ prescribed in RFC 2831.
+
+2006-04-19 Alexey Melnikov <alexey.melnikov@isode.com>
+ * saslauthd/Makefile.am: Enable testsaslauthd build
+ by default.
+
+2006-04-18 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/saslint.h, lib/common.c: Added support for spliting
+ big data blocks (bigger than maxbuf) into multiple SASL
+ packets in sasl_encodev.
+
+2006-04-10 Alexey Melnikov <alexey.melnikov@isode.com>
+ * utils/Makefile.am: Added the pluginviewer man page.
+ Reordered link dependencies for saslpasswds/sasldblistusers2.
+
+2006-04-10 Alexey Melnikov <alexey.melnikov@isode.com>
+ * utils/pluginviewer.8: Added man page for pluginviewer.
+
+2006-04-10 Alexey Melnikov <alexey.melnikov@isode.com>
+ * utils/pluginviewer.c: Deleted unused command line parameters
+ and cleaned up usage output.
+
+2006-04-10 Alexey Melnikov <alexey.melnikov@isode.com>
+ * include/gai.h: Use HAVE_GETADDRINFO (instead of HAVE_GETNAMEINFO)
+ to protect definition of getaddrinfo().
+
+2006-04-10 Alexey Melnikov <alexey.melnikov@isode.com>
+ * include/sasl.h: Allocated some GSSAPI specific properties
+ for Nico Williams (Sun)
+
+2006-04-10 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/common.c: Free default_plugin_path and
+ default_conf_path variables in sasl_done.
+
+2006-04-10 Alexey Melnikov <alexey.melnikov@isode.com>
+ * sasldb/allockey.c: Cleaned up some warnings
+
+2006-04-10 Alexey Melnikov <alexey.melnikov@isode.com>
+ * win32/include/config.h: Deleted a misleading comment
+
+2006-04-06 Jeffrey Teaton <jeaton@cmu.edu>
+ * saslauthd/auth_rimap.c: patch from Dale Sedivec to prevent
+ segfault when saslauth free()s returned string
+ * plugins/sql.c: patch from Matthew Hardin to do better
+ error checking for mysql_real_query
+
+2006-04-03 Alexey Melnikov <alexey.melnikov@isode.com>
+ * configure.in, plugins/NTMakefile, plugins/sasldb.c,
+ sasldb/db_berkeley.c, sasldb/sasldb.h:
+ Patch to keep BerkleyDB handle open between operations
+ (for performance reason). New behavior can be enabled
+ with --enable-keep-db-open. Original patch by Curtis King.
+
+2006-03-14 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/server.c: Fixed bug # 2796: load_config now
+ looks in all directories for the config file,
+ not just in the first one.
+
+2006-03-14 Alexey Melnikov <alexey.melnikov@isode.com>
+ * include/saslplug.h, lib/auxprop.c, lib/client.c
+ lib/server.c, utils/Makefile.am, utils/NTMakefile,
+ utils/pluginviewer.c [new]:
+ Added support for reporting information about
+ loaded auxprop plugins. Changed the first parameter
+ to sasl_server_plugin_info/sasl_client_plugin_info
+ to be "const char *". Added new utility for
+ reporting information about client and server side
+ authentication plugins and auxprop plugins (e.g.
+ supported features, methods, etc.).
+
+2006-03-13 Alexey Melnikov <alexey.melnikov@isode.com>
+ * saslauthd/Makefile.am, saslauthd/auth_httpform.c,
+ saslauthd/auth_httpform.h, saslauthd/configure.in,
+ saslauthd/mechanisms.c, saslauthd/mechanisms.h:
+ Added support for HTTP POST password validation
+ in saslauthd (patch by Joe Ammann <joe@pyx.ch>)
+
+2006-03-13 Alexey Melnikov <alexey.melnikov@isode.com>
+ * cmulocal/openldap.m4: Allow for compilation
+ with OpenLDAP 2.3+.
+
+2006-03-13 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/saslutil.c, utils/testsuite.c: Various
+ fixes to sasl_decode64: don't ignore partial
+ base64 data, don't allow any data after the '='
+ sign, etc.).
+
+2006-03-13 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/saslint.h: Increase canonicalization buffer
+ size to 1024 bytes, as Luke Howard has reported
+ that 256 is too small for some certificates.
+
+2006-03-13 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/NTMakefile: Include Cyrus version of
+ getnameinfo() when compiling with Visual Studio 6,
+ as Windows SDK emulation is not available.
+
+2006-02-13 Alexey Melnikov <alexey.melnikov@isode.com>
+ * include/sasl.h, lib/common.c: Added sasl_set_path
+ function (for a more convenient way of setting
+ plugin and config paths. Changed the default
+ sasl_getpath_t/sasl_getconfpath_t callbacks to
+ calculate the value only once and cache it
+ for later use.
+
+2006-02-13 Alexey Melnikov <alexey.melnikov@isode.com>
+ * configure.in, include/sasl.h, lib/common.c,
+ lib/saslinit.h, lib/server.c, man/Makefile.am,
+ man/sasl_callbacks.3, man/sasl_getconfpath_t.3,
+ win32/include/config.h: Added a new sasl_getconf_t
+ callback for specifying where SASL configuration files
+ can be found. Based on patch from Artur Frysiak
+ <wiget@pld.org.pl> for SASL v1, updated by Gentoo
+ folks for SASL v2 and further modified by
+ Andreas Hasenack <andreas@conectiva.com.br>.
+
+2006-01-31 Alexey Melnikov <alexey.melnikov@isode.com>
+ * INSTALL, INSTALL.TXT: Renamed INSTALL to INSTALL.TXT
+ as the former conflicts with Windows "install" target
+ (and Windows file names are case-insensitive).
+
+2005-08-11 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/sasldb.c: Return SASL_NOUSER only if all calls to
+ _sasldb_putdata() return SASL_NOUSER. This prevents spurious
+ SASL_NOUSER errors.
+
+2005-07-07 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/ntlm.c: Added <openssl/md5.h> include in order to fix
+ building with OpenSSL 0.9.8.
+
+2005-05-19 Derrick Brashear <shadow@andrew.cmu.edu>
+ * config/libtool.m4: do proper quoting, from Andreas Winkelmann
+ * configure.in: clean up enable switches, from Patrick Welche
+ * config/sasldb.m4: fix macro names, from Andreas Winkelmann
+ * lib/client.c: deal with gcc4 strictness, from Steven Simon
+
+2005-05-16 Derrick Brashear <shadow@andrew.cmu.edu>
+ * configure.in, include/sasl.h, lib/Makefile.am,
+ plugins/Makefile.am, saslauthd/configure.in, sasldb/Makefile.am,
+ win32/common.mak, win32/include/config.h: 2.1.21
+ * Makefile.am: fix dist-hook to run makeinit.sh in plugins/
+
+2005-05-15 Derrick Brashear <shadow@andrew.cmu.edu>
+ * saslauthd/lak.c: leak fix from Igor Brezac
+
+2005-05-15 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/NTMakefile: ldapdb on Windows might depend on OpenSSL.
+
+2005-05-06 Derrick Brashear <shadow@andrew.cmu.edu>
+ * configure.in, saslauthd/auth_pam.c: detect pam header location also
+ where MacOS provides it, and use it there
+ * utils/Makefile.am: change link order for MacOS
+ * configure.in: provide option to disable installing MacOS SASL2
+ framework
+ * configure.in, config/kerberos_v4.m4, config/plain.m4,
+ config/sasldb.m4, lib/Makefile.am, sasldb/Makefile.am,
+ (cmulocal/sasl2.m4): fix case where we are building
+ --enable-static --with-dblib=none causing automake's dependancy
+ stuff to screw us when we try to build files with .. in their path
+
+2005-04-11 Derrick Brashear <shadow@andrew.cmu.edu>
+ * configure.in, plugins/digestmd5.c: detect and include des.h if it
+ exists, otherwise assume we don't need it (Solaris 9)
+
+2005-04-11 Derrick Brashear <shadow@andrew.cmu.edu>
+ * sasldb/Makefile.am, config/sasldb.m4: work around HP-UX make's
+ inability to have pipes in $(shell ...) by setting
+ LOCAL_SASL_DB_BACKEND_STATIC at the same time as
+ SASL_DB_BACKEND_STATIC.
+
+2005-03-15 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/dlopen.c: log the reason for opendir() failure
+ when loading plugin.
+
+2005-03-08 Alexey Melnikov <alexey.melnikov@isode.com>
+ * man/sasl_auxprop.3, man/sasl_auxprop_getctx.3,
+ man/sasl_auxprop_request.3, man/sasl_canon_user_t.3,
+ man/sasl_client_init.3, man/sasl_client_new.3,
+ man/sasl_client_start.3, man/sasl_client_step.3,
+ man/sasl_decode.3, man/sasl_errdetail.3, man/sasl_errstring.3,
+ man/sasl_getpath_t.3, man/sasl_getrealm_t.3,
+ man/sasl_getsecret_t.3, man/sasl_server_init.3,
+ man/sasl_server_new.3, man/sasl_server_start.3,
+ man/sasl_server_step.3, man/sasl_setpass.3,
+ man/sasl_user_exists.3, man/sasl_verifyfile_t.3: multiple
+ spelling corrections from Steven Simon <steven_si@sbcglobal.net>.
+
+2005-03-07 Alexey Melnikov <alexey.melnikov@isode.com>
+ * utils/saslpasswd2.8, utils/sasldblistusers2.8: updated manpages.
+
+2005-03-01 Derrick Brashear <shadow@andrew.cmu.edu>
+ * lib/common.c: honor log level setting
+
+2005-02-28 Derrick Brashear <shadow@andrew.cmu.edu>
+ * README.ldapdb: ldapdb license info
+
+2005-02-25 Alexey Melnikov <alexey.melnikov@isode.com>
+ * include/sasl.h, lib/common.c: Added SASL_VERSION_FULL
+ define
+
+2005-02-22 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/NTMakefile, win32/common.mak: Windows build of the ldapdb
+ auxprop plugin
+
+2005-02-16 Derrick Brashear <shadow@andrew.cmu.edu>
+ * configure.in, doc/install.html, doc/options.html, doc/readme.html,
+ doc/sysadmin.html, lib/staticopen.h, plugins/Makefile.am,
+ plugins/ldapdb.c, plugins/makeinit.sh: pull in ldapdb auxprop
+ plugin, from Igor Brezac (Howard Chu's plugin)
+
+2005-02-14 Derrick Brashear <shadow@andrew.cmu.edu>
+ * saslauthd/krbtf.c: updated from CMUCS
+ * saslauthd/auth_krb5.c: log the krb5 error return if get_creds fails
+
+2005-02-01 Alexey Melnikov <alexey.melnikov@isode.com>
+ * win32/include/config.h: Updated to match gai.h changes.
+ * win32/include/config.h: added define for the OTP plugin.
+
+2005-01-27 Derrick Brashear <shadow@andrew.cmu.edu>
+ * configure.in, include/gai.h: move AI_NUMERICHOSTS definitions
+ to config.h because gai.h is not always included.
+
+2005-01-10 Derrick Brashear <shadow@andrew.cmu.edu>
+ * saslauthd/auth_krb5.c, saslauthd/auth_krb4.c,
+ saslauthd/krbtf.h (added), saslauthd/krbtf.c (added),
+ saslauthd/cfile.h (added), saslauthd/cfile.c (added),
+ saslauthd/Makefile.am: Kerberos V4/V5 alternate keytab
+ in saslauthd, plus common code merging (from David Eckhardt
+ via Dale Moore)
+
+2004-12-08 Alexey Melnikov <alexey.melnikov@isode.com>
+ * doc/windows.html: Updated as per recent build changes.
+ * plugins/ntlm.c: Fixed NTLM build on Windows,
+ as compiler was complaining about array size not being
+ a const.
+ * lib/NTMakefile, plugins/NTMakefile, win32/common.mak,
+ win32/include/config.h: Use native IPv6 support on Windows,
+ falling back to Microsoft emulation. Cleaner support
+ for Visual Studio 6.
+
+2004-11-24 Ken Murchison <ken@oceana.com>
+ * plugins/sql.c: squashed unused parameter warnings
+
+2004-11-24 Ken Murchison <ken@oceana.com>
+ * plugins/passdss.c: added; PASSDSS-3DES-1 implementation
+ * configure.in, plugins/Makefile.am, plugins/makeinit.sh:
+ added support for PASSDSS
+ * doc/draft-newman-sasl-passdss-xx.txt: added
+ * doc/index.html, doc/Makefile.am: added PASSDSS draft
+
+2004-11-19 Derrick Brashear <shadow@andrew.cmu.edu>
+ * saslauthd/auth_krb5.c: verify against the service we
+ were passed. needs to be made configurable.
+
+2004-11-10 Alexey Melnikov <alexey.melnikov@isode.com>
+ * doc/draft-burdis-cat-srp-sasl-08.txt: deleted
+ * doc/draft-ietf-sasl-anon-02.txt: deleted
+ * doc/draft-ietf-sasl-crammd5-01.txt: deleted
+ * doc/draft-ietf-sasl-gssapi-00.txt: deleted
+ * doc/draft-ietf-sasl-plain-03.txt: deleted
+ * doc/draft-ietf-sasl-rfc2222bis-03.txt: deleted
+ * doc/draft-ietf-sasl-rfc2831bis-02.txt: deleted
+ * doc/draft-ietf-sasl-saslprep-04.txt: deleted
+ * doc/draft-newman-sasl-c-api-01.txt: deleted
+ * doc/draft-burdis-cat-srp-sasl-xx.txt: added
+ * doc/draft-ietf-sasl-anon-xx.txt: added
+ * doc/draft-ietf-sasl-crammd5-xx.txt: added
+ * doc/draft-ietf-sasl-gssapi-xx.txt: added
+ * doc/draft-ietf-sasl-plain-xx.txt: added
+ * doc/draft-ietf-sasl-rfc2222bis-xx.txt: added
+ * doc/draft-ietf-sasl-rfc2831bis-xx.txt: added
+ * doc/draft-ietf-sasl-saslprep-xx.txt: added
+ * doc/draft-newman-sasl-c-api-xx.txt: added
+ * doc/index.html, doc/Makefile.am: Renamed the files
+
+2004-11-02 Alexey Melnikov <alexey.melnikov@isode.com>
+ * include/saslplug.h, lib/common.c, lib/saslint.h,
+ lib/client.c: Added sasl_client_plugin_info().
+
+2004-10-26 Alexey Melnikov <alexey.melnikov@isode.com>
+ * sample/sample-client.c, sample/sample-server.c: Fixed several
+ 64 bit portability warnings.
+ * utils/testsuite.c: Fixed several 64 bit portability warnings.
+ * utils/saslpasswd.c: Fixed typo in an auxprop name.
+ * include/saslplug.h, lib/common.c, lib/saslint.h,
+ lib/server.c: Added sasl_server_plugin_info().
+
+2004-10-24 Derrick Brashear <shadow@andrew.cmu.edu>
+ * lib/common.c: initialize path in case caller didn't.
+
+2004-10-24 Derrick Brashear <shadow@andrew.cmu.edu>
+ * Prep for 2.1.20
+
+2004-10-19 Derrick Brashear <shadow@dementia.org>
+ * Makefile.am, saslauthd/Makefile.am: require automake 1.7;
+ prior versions require AM_CONFIG_HEADER and dislike AM_LDFLAGS
+
+2004-10-14 Ken Murchison <ken@oceana.com>
+ * plugins/ntlm.c: portability fixes from Alexey, and squashed a
+ signed/unsigned warning
+
+2004-10-14 Alexey Melnikov <alexey.melnikov@isode.com>
+ * lib/NTMakefile: Don't install intermediate file libsasl.res
+
+2004-09-22 Derrick Brashear <shadow@andrew.cmu.edu>
+ * lib/common.c: don't honor SASL_PATH in setuid environment.
+ from Gentoo
+
+2004-09-08 Alexey Melnikov <alexey.melnikov@isode.com>
+ * plugins/cram.c, plugins/anonymous.c, plugins/login.c,
+ plugins/plain.c, plugins/sasldb.c: Fixed several 64 bit
+ portability warnings
+
+2004-09-02 Derrick Brashear <shadow@andrew.cmu.edu>
+ * plugins/kerberosv4.c: simple explanation in the code of one
+ possible error you might see in strange circumstances;
+ i should probably make openssl's des unable to be used if
+ mit krb5 is being used.
+
+2004-08-06 Derrick Brashear <shadow@andrew.cmu.edu>
+ * plugins/cram.c: initialize authid to null so stack garbage
+ is not pushed into _sasl_canon_user
+
+2004-07-29 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * plugins/digestmd5.c: Fix handling of client realm callback
+ (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2004-07-21 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * plugins/gssapi.c: Memory management cleanup
+ (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2004-07-15 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * configure.in, plugins/gssapi.c: Wrap all GSS calls
+ in mutexes when required by the implementation.
+ (based on a patch by Simon Wilkinson <simon@sxw.org.uk>)
+
+2004-07-06 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * plugins/digestmd5.c: Fix potential buffer overflow, call
+ add_to_challenge in 2 more places (Alexey Melnikov
+ <Alexey.Melnikov@isode.com>)
+ * lib/server.c, lib/saslint.h, lib/common.c: don't directly
+ store buffers in the params structure
+ * plugins/gssapi.c: Fix server side maxoutbuf calculation
+ (Sam Hartman <hartmans@mit.edu>)
+ * plugins/gssapi.c: Use gss_wrap_size_limit on client side too
+ * Ready for 2.1.19
+
+2004-07-01 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * Prep for 2.1.19
+
+2004-06-30 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * saslauthd/auth_rimap.c: Fix Tru64 compilation problem
+ * plugins/sql.c: Don't leak settings variable if init fails
+ * utils/testsuite.c: Update for current library
+ * plugins/digestmd5.c: Quoting fixes for client side
+ (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2004-06-23 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * saslauthd/lak.c: Minor bugfixes, support %R token
+ (Igor Brezac <igor@ypass.net>)
+ * plugins/otp.c: Use plugin supplied authid for mech calculations
+ (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+ * lib/auxprop.c: Use getopt callback from connection context when
+ storing auxprops (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+ * plugins/otp.c, plugins/srp.c, plugins/plugin_common.c: Use correct
+ form of userid (user@realm) when running setpass methods
+ (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+ * saslauthd/configure.in: Handle LTLIBOBJS
+
+2004-06-18 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * plugins/NTMakefile: Remove only recognized (generated) .rc files,
+ not just *.rc. This will allow for plugins with own resource files.
+ Also corrected spelling mistake in OPENSSL (Alexey Melnikov
+ <Alexey.Melnikov@isode.com>)
+ * lib/server.c, include/sasl.h: Support for SASL_SET_CURMECH_ONLY
+ flag to sasl_setpass() (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2004-06-16 Ken Murchison <ken@oceana.com>
+ * lib/server.c: use more accurate errors codes for mech_permitted()
+
+2004-06-16 Ken Murchison <ken@oceana.com>
+ * plugins/srp.c: don't used the parsed authid for calculations
+ (Alexey Melnikov <alexey.melnikov@isode.com>)
+
+2004-06-16 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * Support for forwarding of GSSAPI credentials
+ (Morten Olsen <mso@medical-insight.com &
+ Alexey Melnikov <alexey.melnikov@isode.com>)
+
+2004-06-03 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * win32/config.mak: Remove unneeded libraries
+ (Alexey Melnikov <alexey.melnikov@isode.com>)
+
+2004-06-02 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * Spelling Fixes (selsky@columbia.edu)
+
+2004-05-27 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * SQLite support (Norikatsu Shigemura <nork@ninth-nine.com>)
+ * SQLite support on windows (Alexey Melnikov
+ <Alexey.Melnikov@isode.com>)
+
+2004-05-25 Ken Murchison <ken@oceana.com>
+ * plugins/digest-md5.c: use separate global contexts for client/server
+
+2004-05-21 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * configure.in, lib/Makefile.am: Better handling of -ldoor library
+ addition (only add it to base library, don't add -lpthread)
+ * saslauthd/auth_krb5.c: zero out the krb5_data structure
+ before use
+
+2004-05-20 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * include/sasl.h, lib/common.c, lib/saslint.h, lib/server.c:
+ Add SASL_APPNAME to sasl_getprop/sasl_setprop for further
+ compatibilty with SASL C API draft
+ (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2004-05-18 Ken Murchison <ken@oceana.com>
+ * plugins/digest-md5.c: made the global context a struct
+ containing the reauth_cache so we can NULL it after we free it
+
+2004-05-07 Ken Murchison <ken@oceana.com>
+ * contrib/stripplus_canonuser.patch: added
+
+2004-04-27 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * saslauthd/auth_shadow.c: Make thread-safe
+ (Steve Barber <steveb@cme.nist.gov>)
+
+2004-04-26 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * saslauthd/auth_krb5.c: Alternate realm support for Kerberos 5
+
+2004-04-16 Ken Murchison <ken@oceana.com>
+ * plugins/ntlm.c: Mac OS X fix
+ (Chris Ridd <chris.ridd@isode.com>)
+
+2004-04-14 Ken Murchison <ken@oceana.com>
+ * plugins/plain.c: don't include authzid in response unless
+ specified by client
+
+2004-03-29 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * sample/server.c: Ensure that len has a value
+
+2004-03-25 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * saslauthd/saslauthd-main.c: add -r option to saslauthd for combining
+ user and realm into user@realm (for the userid). Based on a patch
+ by Jeremy Rumpf <jrumpf@heavyload.net>.
+
+2004-03-17 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * lib/checkpw.c: Include errno.h when HAVE_AUTHDAEMON is defined
+ * doc/windows.html: Updates (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2004-03-16 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * configure.in: Properly use CMU_ADD_LIBPATH_TO for pgsql and mysql
+
+2004-03-10 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * lib/dlopen.c: HPUX 11 Fix (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+ * Add sasl_version_info() (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+ * Add a bunch of NTMakefile files to EXTRA_DIST in Makefile.am's
+ * Ready for 2.1.18
+
+2004-03-08 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * NI_WITHSCOPEID fixes (Hajimu UMEMOTO <ume@mahoroba.org>) - correct
+ Solaris 9 IPLOCALPORT/IPREMOTEPORT issue
+
+2004-02-24 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * acinclude.m4: move to config/libtool.m4
+ * saslauthd/lak.[ch]: Added filter based group membership check
+ (Paul Bender <pbender@qualcomm.com>, Igor Brezac <igor@ipass.net>)
+
+2004-02-23 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * plugins/NTMakefile: Enable DO_SRP_SETPASS on windows
+ (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+ * doc/windows.html: Updates
+ (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+ * win32/: Add version resource info to plugins
+ (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+ * plugins/digestmd5.c: Comments and other cleanup
+
+2004-02-20 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * lib/server.c, include/saslplug.h: Allow "temporary failure"
+ return values from mech_avail
+ * lib/canonusr.c, lib/server.c: Comment Nits
+ (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+ * plugins/NTMakefile, plugins/plugin_common.h,
+ plugins/plugin_common.c, plugins/otp.c: build OTP on Windows
+ (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2004-02-19 Ken Murchison <ken@oceana.com>
+ * plugins/ntlm.c, sample/server.c, sample/client.c:
+ error checking of getnameinfo() (Paul Kranenburg <pk@cs.few.eur.nl>)
+ * plugins/ntlm.c: alignment and endian fixes in load_session_setup()
+ (Paul Kranenburg <pk@cs.few.eur.nl>)
+
+2004-02-18 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * doc/NTMakefile, NTMakefile: nmake install support
+ for doc/ (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+ * plugins/digestmd5.c: Check that digest-uri is only sent once
+ (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+ * utils/Makefile.am: add LIB_PGSQL to static link line
+
+2004-02-17 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * win32/include/config.h: caddr_t might be already defined
+ elsewhere (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+ * lib/NTMakefile, include/saslutil.h: getopt might be already
+ defined elsewhere. The change will produce libsasl.dll which exports
+ getopt, buat a define can be used to prevent import of getopt from
+ libsasl.dll. (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2004-02-16 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * configure.in: Remove deprecated AC_PROG_RANLIB, CMU_PROG_LIBTOOL
+ (Patrick Welche <prlw1@newn.cam.ac.uk>)
+ * lib/dlopen.c: OpenBSD ELF patch (J.C. Roberts)
+
+2004-02-06 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * lib/NTMakefile, utils/NTMakefile: fix "clean" target
+ (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+ * General winsock.h -> winsock2.h conversion
+ (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+ * plugins/plugin_common.h: add extern "C" wrapper
+ (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2004-01-23 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * Remove "experimental" designation from saslauthd/ldap
+ * Correct handling of sasl_setpass errors when no
+ mechanisms implement the setpass interface
+ (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2004-01-20 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * configure.in: minor sql nit (Edward Rudd <eddie@omegaware.com>)
+ * lib/staticopen.h: MYSQL should be SQL
+ (Edward Rudd <eddie@omegaware.com>)
+
+2004-01-12 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * win32/include/config.h: fix VC++ 6.0 compiles
+ (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+ * configure.in: Correct use of AC_LIBOBJ, quote macro names
+ defined by AC_DEFUN, Use enable_shared to determine whether
+ to enable the shared plugin.
+ (Maciej W. Rozycki <macro@ds2.pg.gda.pl>)
+ * plugins/srp.c: Fix typos
+ (Maciej W. Rozycki <macro@ds2.pg.gda.pl>)
+ * saslauthd/configure.in: Correct use of AC_LIBOBJ
+ (Maciej W. Rozycki <macro@ds2.pg.gda.pl>)
+
+2004-01-08 Ken Murchison <ken@oceana.com>
+ * plugins/sql.c: better error logging
+
+2004-01-07 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * lib/checkpw.c & others: Support for Courier-IMAP authdaemond
+ use during password verification (Leandro Santi
+ <lesanti@uolsinectis.com.ar>)
+
+2003-12-30 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * saslauthd/lak.c: Fix NULL pointer dereference
+ (Simon Brady <simon.brady@otago.ac.nz>)
+ * saslauthd/lak.c, lak.h, LDAP_SASLAUTHD: Improved retry handler,
+ Improved logging/debug messages, Fixed String checks, config
+ option changes (Igor Brezac <igor@ipass.net>)
+
+2003-12-22 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * plugins/digestmd5.c: Fix memory leak
+ (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2003-12-18 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * plugins/plugin_common.c: Fix handling of blob unwrapping
+ in _plug_decode
+ * lib/checkpw.c: Fix some file descriptor leaks during failures
+ in the saslauthd code.
+
+2003-12-15 Rob Siemborksi <rjs3@andrew.cmu.edu>
+ * utils/saslauthd.c: Fix Typo
+ (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+ * plugins/plugin_common.c: Fix potential memory leak
+ * lib/external.c: Limit size of authzids in EXTERNAL
+ * plugins/gssapi.c: Pre-init some variables
+ * lib/cram.c: Detect possible buffer overrun
+ * lib/checkpw.c: Post-fence bug
+ (Leandro Santi <lesanti@uolsinectis.com.ar>)
+
+2003-12-12 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * saslauthd/lak.c: assign null to free
+ variables (Juan Felipe Garcia <fgc@usal.es>)
+ * saslauthd/lak.c: Improve retry when ldap connection is reset
+ (1st pass) (Igor Brezac <igor@ipass.net>)
+
+2003-12-11 Rolf Braun <rbraun@andrew.cmu.edu>
+ * Several MacOS X Fixes
+
+2003-12-06 Ken Murchison <ken@oceana.com>
+ * lib/checkpw.c, lib/server.c,
+ plugins/cram.c, plugins/digestmd5.c, plugins/ntlm.c,
+ plugins/otp.c, plugins/srp.c: erase the plaintext password
+ property from the context when we're done with it
+
+2003-12-01 Ken Murchison <ken@oceana.com>
+ * doc/draft-ietf-sasl-crammd5-01.txt: added
+ * doc/draft-ietf-sasl-gssapi-00.txt: added
+ * doc/draft-ietf-sasl-plain-03.txt: added
+ * doc/draft-ietf-sasl-rfc2222bis-03.txt: added
+ * doc/draft-ietf-sasl-saslprep-04.txt: added
+ * doc/draft-ietf-sasl-crammd5-00.txt: deleted
+ * doc/draft-ietf-cat-sasl-gssapi-05.txt: deleted
+ * doc/draft-ietf-sasl-plain-02.txt: deleted
+ * doc/draft-ietf-sasl-rfc2222bis-02.txt: deleted
+ * doc/draft-ietf-sasl-saslprep-03.txt: deleted
+ * doc/index.html, doc/Makefile.am: updated to latest version of
+ SASL drafts
+
+2003-12-01 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * Fix build nit in IRIX.
+ * Actual 2.1.17 release.
+
+2003-11-28 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * Ready for 2.1.17
+
+2003-11-19 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * config/kerberos_v4.m4: Disable KERBEROS_V4 support by default
+
+2003-11-14 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * lib/server.c: do authorization callback in sasl_checkpass()
+ (Chris Newman <chris.newman@sun.com>)
+
+2003-11-11 Ken Murchison <ken@oceana.com>
+ * lib/client.c: allow serverFDQN to be NULL in sasl_client_new()
+ * plugins/digestmd5.c, gssapi.c: require that we have serverFQDN
+ for the client side of the plugin
+
+2003-11-07 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * --with-gss_impl configure option
+ (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2003-11-06 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * nmake install support for Win32
+ (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2003-11-03 Ken Murchison <ken@oceana.com>
+ * include/saslplug.h, lib/server.c, plugins/cram.c,
+ plugins/digestmd5.c, plugins/ntlm.c, plugins/otp.c,
+ plugins/srp.c: return SASL_TRANS to the application where
+ appropriate (auto_transition enabled with writable auxprop)
+
+2003-10-30 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * saslauthd/lak.c: OpenLDAP 2.0 Compatability Fix
+ (Igor Brezac <igor@ypass.net>)
+ * saslauthd/ipc_unix.c: Fix buglet of not using saved errno
+ value (Jeremy Rumpf <jrumpf@heavyload.net>)
+
+2003-10-20 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * Win64 warning squashing (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+ * GSSAPI cleanups and fixes (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2003-10-14 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * Ready for 2.1.16-BETA
+
+2003-10-08 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * Support for autoconf 2.57, automake 1.7
+ * Minor m4 quoting fixes (Patrick Welche <prlw1@cam.ac.uk>)
+
+2003-10-07 Ken Murchison <ken@oceana.com>
+ * plugins/sql.c: removed sql_delete - don't DELETE rows from the
+ table, just set the properties to NULL;
+ fix a stupid logic error in my PgSQL changes
+ * doc/options.html: removed sql_delete option; clarifications
+ * doc/install.html: note that we require PostgreSQL v7.2+
+
+2003-10-06 Ken Murchison <ken@oceana.com>
+ * plugins/sql.c: use the correct propctx in sql_auxprop_store()
+
+2003-10-06 Maya Nigrosh <mnigrosh@andrew.cmu.edu>
+ * plugins/sql.c: tiny bugfix to begin pgsql transactions
+
+2003-10-04 Ken Murchison <ken@oceana.com>
+ * plugins/sql.c: only do a txn when we have a property to fetch;
+ _pgsql_open() cleanup/fixes; more intelligient sql_usessl parsing;
+ require sql_select option
+ * doc/options.html: reorganized SQL option descriptions
+
+2003-10-03 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * sasldb/allockey.c, sasldb/sasldb.h, utils/sasldblistusers.c:
+ Add enumeration capability to the sasldb API
+ (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2003-10-02 Ken Murchison <ken@oceana.com>
+ * plugins/sql.c: changed abstraction layer for transactions
+
+2003-10-01 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * doc/: Documentation Update
+ (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+ * plugins/NTMakefile, plugins/srp.c: Win32 SRP Support
+ (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2003-09-30 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * plugins/digestmd5.c: Clean up some warnings
+ * lib/canonusr.c, win32/include/config.h, win32/common.mak,
+ include/saslplug.h: Minor Cleanup
+ (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+ * utils/NTMakefile, utils/sasldblistusers.c, utils/saslpasswd.c:
+ Add version options to command line utilities
+ (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2003-09-29 Ken Murchison <ken@oceana.com>
+ * plugins/sql.c, doc/options.html: added sql_update and sql_delete
+ for a complete auxprop_store() implementation; logic cleanup
+
+2003-09-25 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * utils/saslpasswd.c: Win32 perror() related patch
+ (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2003-09-25 Ken Murchison <ken@oceana.com>
+ * plugins/sql.c: renamed sql_statement to sql_select,
+ cleanup and bugfixes
+
+2003-09-23 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * doc/gssapi.html: Misc updates
+ (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+ * lib/Makefile.am, plugins/Makefile.am, saslauthd/Makefile.am,
+ sasldb/Makefile.am: Cleanup INCLUDES for different build
+ directories. (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2003-09-23 Maya Nigrosh <mnigrosh@andrew.cmu.edu>
+ * plugins/sql.c: put transaction handling around the entirety of
+ the queries, and not just per-property; return the result status
+ of bad postgres tuples
+
+2003-09-22 Maya Nigrosh <mnigrosh@andrew.cmu.edu>
+ * plugins/sql.c: added semicolon at the end of each sql statement
+
+2003-09-19 Maya Nigrosh <mnigrosh@andrew.cmu.edu>
+ * plugins/sql.c: moved transaction handling to a more useful place,
+ minor bugfixes
+
+2003-09-18 Ken Murchison <ken@oceana.com>
+ * lib/server.c: log a message when no password change is attempted
+ (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2003-09-17 Ken Murchison <ken@oceana.com>
+ * plugins/sql.c: misc fixes from Patrick Welche <prlw1@newn.cam.ac.uk>
+
+2003-09-16 Ken Murchison <ken@oceana.com>
+ * doc/mechanisms.html: updated to latest versions of LOGIN and
+ SRP drafts
+
+2003-09-15 Ken Murchison <ken@oceana.com>
+ * doc/draft-ietf-sasl-rfc2222bis-02.txt: added
+ * doc/draft-ietf-sasl-rfc2222bis-01.txt: deleted
+ * doc/index.html, doc/Makefile.am: updated to latest version of
+ SASL draft
+
+2003-09-14 Ken Murchison <ken@oceana.com>
+ * plugins/ntlm.c, plugins/plugin_common.[ch]: Win32 support
+ (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2003-09-12 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * plugins/sql.c: Log errors on connect failures
+ (based on patch from Bruce M Simpson <bms@spc.org>)
+ * plugins/NTMakefile: Add support for GSSAPI=CyberSafe
+ (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2003-09-10 Maya Nigrosh <mnigrosh@andrew.cmu.edu>
+ * plugins/sql.c: created generic sql store function, added
+ transaction handling to sql statements
+ * doc/options.html: put pretty new options in the documentation
+
+2003-09-10 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * plugins/gssapi.c, win32/config.mak, sample/: Win32 Fixes
+ (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2003-09-09 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * lib/NTMakefile: Minor nit
+ (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2003-09-09 Ken Murchison <ken@oceana.com>
+ * plugins/ntlm.c: use retry_read() instead of just read()
+ * lib/checkpw.c, plugins/ntlm.c, saslauthd/utils.c:
+ squash signed/unsigned warning
+
+2003-09-08 Ken Murchison <ken@oceana.com>
+ * plugins/ntlm.c: fix byte-alignment and password handling problems
+
+2003-09-03 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * lib/checkpw.c: Check return value of door_call
+ (Gary Mills <mills@cc.umanitoba.ca>)
+ * saslauthd/ipc_doors.c: Implement thread limiting,
+ minor cleanup and error checking
+ (Gary Mills <mills@cc.umanitoba.ca>)
+ * plugins/digestmd5.c: Fix minor interop issues, limit maxbuf
+ (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2003-09-02 Ken Murchison <ken@oceana.com>
+ * plugins/ntlm.c, doc/options.html: added support for NTLMv2 responses;
+ fixed potential buffer overflow
+
+2003-09-02 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * lib/common.c, lib/server.c, lib/NTMakefile, include/md5.h:
+ more windows compatibility
+ (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+ * plugins/NTMakefile: Add ability to build NTLM plugin under
+ Win32 (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+ * utils/NTMakefile: Add ability to build testsuite
+ (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+ * saslauthd/lak.c: Minor error message fix
+ (Igor Brezac <igor@ypass.net>)
+
+2003-08-29 Ken Murchison <ken@oceana.com>
+ * doc/draft-murchison-sasl-login-00.txt: added
+ * doc/draft-sasl-login.txt: deleted
+ * doc/index.html, doc/Makefile.am: updated to "official" LOGIN draft
+
+2003-08-29 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * plugins/gssapi.c: properly compute GSSAPI MAXOUTBUF
+ (Paul Turgyan <pturgyan@umich.edu>)
+ * Further Win32 cleanup + HIER_DELIMITER usage
+ (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+
+2003-08-28 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * include/md5.h, lib/md5.c: Misc cleanup
+ (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+ * utils/sasldblistusers.c: UI Cleanup, Win32 support
+ (Alexey Melnikov <Alexey.Melnikov@isode.com>)
+ * acconfig.h: add HIER_DELIMITER
+
+2003-08-27 Ken Murchison <ken@oceana.com>
+ * plugins/digestmd5.c: handle OpenSSL 0.9.7+ w/o old DES support
+
+2003-08-26 Ken Murchison <ken@oceana.com>
+ * plugins/ntlm.c: only send one NT/LM response to server
+ (NT preferred); don't use canonified authid when proxying
+
+2003-08-24 Ken Murchison <ken@oceana.com>
+ * plugins/ntlm.c, doc/options.html: allow NTLM authentication to
+ be optionally proxied to an NT server (ntlm_server option)
+
+2003-08-24 Ken Murchison <ken@oceana.com>
+ * lib/common.c: added support for unsigned int types in _sasl_log()
+
+2003-08-18 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * Improvements in Win32 build system from Alexey Melnikov
+ <Alexey.Melnikov@isode.com>
+
+2003-08-14 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * doc/*: Massive documentation updates.
+
+2003-08-13 Ken Murchison <ken@oceana.com>
+ * doc/index.html: added reference to a CIFS (SMB/NTLM) document
+
+2003-08-12 Ken Murchison <ken@oceana.com>
+ * doc/index.html: added reference to a good NTLM document
+
+2003-07-29 Ken Murchison <ken@oceana.com>
+ * plugins/cram.c: don't truncate long secrets to 64 bytes on the
+ client-side of CRAM-MD5 (jiang_xiong@yahoo.com)
+
+2003-07-28 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * plugins/gssapi.c: another missed pointer init
+ (Will Fiveash <william.fiveash@sun.com>)
+
+2003-07-26 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * lib/server.c: Missed pointer initialization fix
+ ("Dave Cridland [Home]" <dave@cridland.net>)
+
+2003-07-26 Ken Murchison <ken@oceana.com>
+ * plugins/digestmd5.c: merged privacy and integrity security layer
+ code and removed use of tmp buffers for security layer
+
+2003-07-25 Ken Murchison <ken@oceana.com>
+ * plugins/srp.c: removed use of tmp buffer for security layer;
+ don't make a big buffer out of iovecs when encoding
+ * lib/server.c, plugins/login.c, plugins/plain.c: better handling
+ of auto_transition -- doesn't try to transition from auxprop to
+ auxprop
+
+2003-07-25 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * configure.in: Fix up some mysql/pgsql detection
+ * plugins/gssapi.c: improved error reporting
+ (William Fiveash <William.Fiveash@sun.com>)
+ * cmulocal/sasl2.m4, saslauthd/mechanisms.h: Improved
+ GSSAPI detection (don't default to MIT, require HAVE_KRB5_H
+ for the kerberos5 saslauthd module)
+ (Rainer Orth <ro@TechFak.Uni-Bielefeld.DE>)
+
+2003-07-24 Ken Murchison <ken@oceana.com>
+ * plugins/srp.c: updated security layer code to be closer to draft -08
+
+2003-07-23 Rob Siemborksi <rjs3@andrew.cmu.edu>
+ * saslauthd/utils.[ch], saslauthd/configure.in: Detect/replace
+ strlcpy and strlcat (based on ideas from
+ Igor Brezac <igor@ipass.net>)
+
+2003-07-22 Ken Murchison <ken@oceana.com>
+ * plugins/digestmd5.c, plugins/gssapi.c, plugins/kerberos4.c,
+ plugins/plugin_common.[ch]: moved encoded packet buffering into
+ _plug_decode()
+
+2003-07-21 Ken Murchison <ken@oceana.com>
+ * plugins/srp.c: updated auth code to draft -08 (layers still need
+ to be updated)
+ * configure.in, plugins/srp.c: use auxprop_store() instead of
+ direct sasldb access
+
+2003-07-21 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * configure.in: add runpath information for MySQL and Postgres;
+ better behavior for the interaction of --enable-sql and
+ --with-mysql / --with-pgsql
+ * saslauthd/lak.[ch]: %d to be derived from %u if it can be,
+ otherwise use %r (to account for the recent change in the
+ core library). Add ldap_default_realm parameter
+ (Igor Brezac <igor@ipass.net>)
+
+2003-07-18 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * plugins/digestmd5.c: Client side of digest md5 doesn't
+ have quotes around its cypher= directive (Bug 2113).
+ * saslauthd/lak.[ch]: support for ldap sasl binds,
+ support for tls (Igor Brezac <igor@ipass.net>)
+
+2003-07-17 Ken Murchison <ken@oceana.com>
+ * include/sasl.h, include/saslplug.h,
+ * lib/auxprop.c, lib/common.c, lib/server.c, plugins/sasldb.c:
+ implemented writable auxprops
+ * configure.in, plugins/otp.c, utils/saslpasswd: use
+ auxprop_store() instead of direct sasldb access
+ * doc/options.html, lib/server.c: implemented 'noplain' option for
+ auto_transition
+
+2003-07-17 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * lib/config.c: Remove sasl_config_getint and sasl_config_getswitch
+ because they are unused and confusing
+ * lib/checkpw.c: Correctly split realm from username in
+ saslauthd_verify_password
+
+2003-07-15 Ken Murchison <ken@oceana.com>
+ * plugins/sql.c, doc/options.html: added sql_usessl option
+
+2003-07-15 Ken Murchison <ken@oceana.com>
+ * plugins/mysql.c: deleted
+ * plugins/sql.c: added
+ * acconfig.h, configure.in,
+ doc/components.html, doc/options.html, doc/sysadmin.html,
+ plugins/Makefile.am, plugins/makeinit.sh: deprecated MySQL plugin
+ in favor of a new generic SQL plugin (currently supports MySQL and
+ PostgreSQL)
+
+2003-07-15 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * Ready for 2.1.15
+
+2003-07-03 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * doc/components.html: added in the hopes that this gives a better
+ description of how all the components interact
+
+2003-07-02 Ken Murchison <ken@oceana.com>
+ * doc/draft-ietf-sasl-anon-02.txt: added
+ * doc/draft-ietf-sasl-plain-02.txt: added
+ * doc/draft-ietf-sasl-saslprep-03.txt: added
+ * doc/draft-ietf-sasl-anon-01.txt: deleted
+ * doc/draft-ietf-sasl-plain-01.txt: deleted
+ * doc/index.html, doc/Makefile.am: updated to latest versions of
+ PLAIN, ANONYMOUS, SASLprep drafts
+
+2003-07-02 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * acconfig.h, cmulocal/sasl2.m4, plugins/gssapi.c:
+ Properly detect HAVE_GSS_C_NT_USER_NAME
+ (Rainer Orth <ro@TechFak.Uni-Bielefeld.DE>)
+
+2003-07-01 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * plugins/kerberos4.c: Fix some maxoutbuf handling issues
+
+2003-07-01 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * plugins/mysql.c: Check return value of mysql_init
+ (Ivan Kelly <ivan@ivankelly.net>)
+
+2003-07-01 Ken Murchison <ken@oceana.com>
+ * doc/draft-burdis-cat-srp-sasl-08.txt: added
+ * doc/draft-ietf-sasl-rfc2222bis-01.txt: added
+ * doc/draft-ietf-sasl-rfc2831bis-02.txt: added
+ * doc/draft-burdis-cat-srp-sasl-06.txt: deleted
+ * doc/draft-ietf-sasl-rfc2222bis-00.txt: deleted
+ * doc/draft-ietf-sasl-rfc2831bis-01.txt: deleted
+ * doc/index.html, doc/Makefile.am: updated to latest versions of
+ SASL, SRP, DIGEST-MD5 drafts
+
+2003-06-30 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * plugins/mysql.c: Call mysql_init() too
+ (Hajimu UMEMOTO <ume@mahoroba.org>)
+
+2003-06-28 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * doc/sysadmin.html: Add more text about how to use realms.
+
+2003-06-27 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * Ready for 2.1.14
+
+2003-06-11 Rolf Braun <rbraun@andrew.cmu.edu>
+ * config/kerberos_v4.m4:
+ fix fallback to -lkrb4 when --enable-krb4 is specified
+ * config/ltconfig:
+ * config/ltmain.sh:
+ make the darwin libtool work on OS X v10.2
+ (bash/zsh shell syntax, and don't link bundles with extra args)
+ * dlcompat-20010505/dlopen.c: back out bogus delimiter change
+ * doc/macosx.html: update for 10.2 and add known problems section
+ * mac/osx_cfm_glue/cfmglue.c: fix sasl_done followed by client_init
+
+2003-06-11 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * man/sasl_client_new.3, man/sasl_server_new.3:
+ Security flags don't belong here, connection flags do.
+
+2003-06-10 Ken Murchison <ken@oceana.com>
+ * doc/draft-ietf-sasl-crammd5-00.txt: added
+ * doc/draft-nerenberg-sasl-crammd5-03.txt: deleted
+ * doc/index.html, doc/Makefile.am: updated to WG version of
+ CRAM-MD5 draft
+
+2003-05-30 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * plugins/gssapi.c: If we get an empty output token back
+ from gss_accept_sec_context, return
+ an empty string to transmit to the client.
+
+2003-05-30 Ken Murchison <ken@oceana.com>
+ * doc/draft-ietf-sasl-rfc2831bis-01.txt: added
+ * doc/draft-ietf-sasl-rfc2831bis-00.txt: deleted
+ * doc/index.html, doc/Makefile.am: updated to latest version of
+ DIGEST-MD5 draft
+
+2003-05-28 Ken Murchison <ken@oceana.com>
+ * doc/draft-ietf-sasl-anon-01.txt: added
+ * doc/draft-ietf-sasl-plain-01.txt: added
+ * doc/draft-ietf-sasl-rfc2222bis-00.txt: added
+ * doc/draft-ietf-sasl-anon-00.txt: deleted
+ * doc/draft-ietf-sasl-plain-00.txt: deleted
+ * doc/draft-myers-saslrev-02.txt: deleted
+ * doc/index.html, doc/Makefile.am: updated to latest versions of
+ SASL, PLAIN, ANONYMOUS drafts
+
+2003-05-21 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * saslauthd/ipc_unix.c: Accept File Descriptor Locking
+ Fixes (found by Leena Heino <Leena.Heino@uta.fi>)
+ * saslauthd/cache.c: Similar fixes
+ (Jeremy Rumpf <jrumpf@heavyload.net>)
+
+2003-05-15 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * configure.in: Actually listen to --disable-java
+ (Maciej W. Rozycki <macro@ds2.pg.gda.pl>)
+ * saslauthd/saslauthd-main.h: Increase listen backlog to
+ match Cyrus master process (Igor Brezac <igor@ipass.net>)
+
+2003-05-14 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * config/kerberos_v4.m4: Minor nit
+ (Carlos Velasco <carlosev@newipnet.com>)
+ * plugins/gssapi.c: Use GSS_C_NT_USER_NAME
+ to work around Solaris 8/9 libgss bug.
+ (gssapi_client_mech_step): Pass GSS_C_NO_BUFFER to first
+ invocation of gss_init_sec_context to work around Solaris 8/9
+ mech_krb5 bug. (Rainer Orth <ro@TechFak.Uni-Bielefeld.DE>)
+ * cmulocal/sasl2.m4: Check for Sun SEAM GSS-API implementation
+ (Rainer Orth <ro@TechFak.Uni-Bielefeld.DE>)
+ * saslauthd/configure.in: Check for krb5.h. Don't define if GSSAPI
+ is present. (Rainer Orth <ro@TechFak.Uni-Bielefeld.DE>)
+ * saslauthd/mechanisms.h: Test for HAVE_KRB5_H instead of HAVE_GSSAPI_H
+ to activate AUTH_KRB5. (Rainer Orth <ro@TechFak.Uni-Bielefeld.DE>)
+ * plugins/mysql.c: Use mysql_real_connect() instead of mysql_connect()
+ (Petri Riihikallio <Petri.Riihikallio@Metis.fi>)
+ * saslauthd/: Misc ANSI C cleanups (Jeremy Rumpf <jrumpf@heavyload.net>)
+
+2003-05-13 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * config/sasldb.m4, utils/Makefile.am: fix installation of man
+ pages that are homed in the utils/ directory
+ * include/*.h: Add extern "C" blocks for C++ compiles
+
+2003-05-06 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * saslauthd/saslauthd-main.c: misc spelling and UI cleanups
+
+2003-04-16 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * saslauthd/saslauthd-main.c: Don't set the auth mech until
+ all options have been processed. (Peter Stamfest <peter@stamfest.at>)
+ * lib/client.c, lib/common.c, lib/saslint.h, lib/server.c: Do
+ reference counting of the number of times sasl has been inited/doned.
+
+2003-04-15 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * config/ltmain.sh: fix some portability problems in the use of expr
+ (Oliver Eikemeier <eikemeier@fillmore-labs.com>)
+
+2003-04-14 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * Ready for 2.1.13
+
+2003-04-08 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * lib/external.c, lib/server.c: use mech_avail to disable
+ EXTERNAL instead of special casing it (Chris Newman
+ <Chris.Newman@Sun.COM>)
+
+2003-03-31 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * saslauthd/ipc_unix.c, saslauthd/saslauthd-main.c,
+ saslauthd/saslauthd-main.h: use the pidfile locking from
+ the Cyrus IMAPd master process (implemented for saslauthd by
+ Igor Brezac <igor@ipass.net>)
+ * configure.in, acconfig.h: Add configure option to set what
+ we use for /dev/random
+
+2003-03-28 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * saslauthd/: Unify the source files so that the IPC methods
+ are broken out into a separate API. Cacheing of authentication
+ credentials is also available as a command-line option.
+ Other changes include: Remove Time of Day Flag, omit
+ SO_REUSEADDR on AF_UNIX sockets, make using the accept-socket
+ locking runtime configurable, and misc other cleanup.
+ (Jeremy Rumpf <jrumpf@heavyload.net>)
+
+2003-03-26 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * plugins/plain.c: Defend against memory leak on canon_user
+ failure (Chris Newman <chris.newman@sun.com>)
+
+2003-03-19 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * lib/auxprop.c, lib/checkpw.c, lib/common.c, lib/saslutil.c,
+ lib/server.c: Assorted minor fixes from Sun Microsystems
+ (provided by Chris Newman <chris.newman@sun.com>)
+
+2003-03-13 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * saslauthd/lak.c: Fix a memset length. (Igor Brezac <igor@ipass.net>)
+
+2003-03-06 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * plugins/digestmd5.c: fix parity of digest-uri test
+ * lib/client.c, common.c, saslint.h, server.c: Pass global
+ callbacks to global utils structure
+ (Howard Chu <hyc@highlandsun.com>)
+ * saslauthd/auth_krb5.c: Fix memory/file descriptor leak
+ in krb5 authentication (Jonathen Chen <jon@spock.org>)
+ * saslauthd/lak.c, lak.h, LDAP_SASLAUTHD: Remove ldap_cache
+ code, and rename MAX() to LAK_MAX()
+
+2003-02-20 Ken Murchison <ken@oceana.com>
+ * doc/draft-ietf-sasl-rfc2831bis-00.txt: added
+ * doc/draft-melnikov-rfc2831bis-02.txt: deleted
+ * doc/draft-newman-sasl-c-api-01.txt: added
+ * doc/draft-newman-sasl-c-api-00.txt: deleted
+ * doc/index.html: updated to WG version of DIGEST-MD5 draft,
+ updated to latest C API draft
+ * doc/Makefile.am: updated to WG version of DIGEST-MD5 draft,
+ updated to latest C API draft
+
+2003-02-12 Lawrence Greenfield <leg+@andrew.cmu.edu>
+ * plugins/digestmd5.c: verify the service component of digest-uri
+
+2003-02-11 Ken Murchison <ken@oceana.com>
+ * doc/draft-ietf-sasl-anon-00.txt: added
+ * doc/draft-ietf-sasl-plain-00.txt: added
+ * doc/draft-zeilenga-sasl-anon-01.txt: deleted
+ * doc/draft-zeilenga-sasl-plain-01.txt: deleted
+ * doc/index.html: updated to WG versions of ANONYMOUS, PLAIN drafts
+
+2003-02-03 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * cmulocal/sasl2.m4: Don't use -ldes to check for Heimdal
+ * saslauthd/auth_krb4.c, saslauthd/auth_shadow.c,
+ saslauthd/auth_getpwent.c, lib/kerberos4.c:
+ Smarter checking of #includs for des.h
+ (Mark Keasling <mark@air.co.jp>)
+ * saslauthd/testsaslauthd.c, saslauthd/saslauthd-doors.c:
+ retry_read() should use a char * buffer not a void *
+ buffer (Mark Keasling <mark@air.co.jp>)
+ * cmulocal/berkdb.m4: Set CPPFLAGS around tests
+ (based on patch from Leena Heino <Leena.Heino@uta.fi>)
+ * config/sasldb.m4: Actually use results of Berkeley DB tests
+ (Leena Heino <Leena.Heino@uta.fi>)
+ * Ready for 2.1.12
+
+2003-01-31 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * Ready for 2.1.11
+ * utils/Makefile.am: Ensure that dbconverter-2 can see the sasldb
+ include directory.
+
+2003-01-29 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * plugins/digestmd5.c: Fix a situation where the realm wasn't
+ being set for the client context, causing a segfault
+ * config/kerberos_v4.m4: first check des_* then check DES_*
+ during OpenSSL tests (based on ideas from
+ Leena Heino <Leena.Heino@uta.fi>)
+
+2003-01-28 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * config/sasldb.m4: Don't build sasldb plugin if compiling
+ --with-dblib=none, since it will only fail to load anyway.
+
+2003-01-27 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * saslauthd/configure.in: use CMU_ADD_LIBPATH for LDAP support
+ (Simon Brady <simon.brady@otago.ac.nz>)
+
+2003-01-23 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * saslauthd/acconfig.h: protect file from being included more than
+ once (reported by Jeremy Rumpf <jrumpf@heavyload.net>)
+ * saslauthd/configure.in, configure.in: Move OpenSSL detection into
+ cmulocal, detect openssl for use with lak.c
+
+2003-01-21 Ken Murchison <ken@oceana.com>
+ * plugins/ntlm.c: only _require_ one response (LM and/or NT), not both
+
+2003-01-09 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * saslauthd/lak.c, saslauthd/lak.h: Add the fastbind auth method
+ (Simon Brady <simon.brady@otago.ac.nz>)
+
+2003-01-01 Ken Murchison <ken@oceana.com>
+ * saslauthd/configure.in, saslauthd/Makefile.am: don't make
+ -lcrypt dependent upon --enable-plain
+
+2002-12-11 Ken Murchison <ken@oceana.com>
+ * plugins/otp.c: set SASL_FEAT_ALLOWS_PROXY on client side
+
+2002-12-10 Ken Murchison <ken@oceana.com>
+ * plugins/otp.c: explicitly #include <openssl/md5.h> to resolve
+ OpenBSD/OpenSSL cruftiness
+
+2002-12-10 Rob Siemborksi <rjs3@andrew.cmu.edu>
+ * saslauthd/saslauthd-doors.c: Fix a potential memory leak when
+ we call door_return()
+
+2002-12-09 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * lib/auxprop.c: Correct leak in prop_clear, also update list_end
+ in prop_request.
+ * doc/options.html: Update use of saslauthd_path to be correct
+
+2002-12-06 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * Ready for 2.1.10
+
+2002-12-05 Larry Greenfield <leg@andrew.cmu.edu>
+ * plugins/digestmd5.c: DES key fixes. stupid DES libraries want
+ the key in the stupid DES parity format.
+ * plugins/digestmd5.c: refactored some of the cipher code so that
+ there isn't RC4 state around when we're using DES and vice versa
+
+2002-12-05 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * saslauthd/lak.c: Allocate a large enough buffer to account for
+ a completely escaped username. (lak_escape and lak_filter)
+ * lib/common.c: Ensure there is enough space for the trailing \0
+ in _sasl_log
+
+2002-12-04 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * lib/canonusr.c: Check for potential buffer overflow
+
+2002-12-03 Ken Murchison <ken@oceana.com>
+ * plugins/digestmd5.c: major fast reauth rewrite, mech_step cleanup
+ * doc/options.html: server-side reauth is disabled by default
+
+2002-11-24 Ken Murchison <ken@oceana.com>
+ * plugins/login.c: allow authid to be passed in initial response
+ * doc/draft-sasl-login.txt, doc/mechanisms.html:
+ documentation updates re: initial response
+
+2002-11-07 Ken Murchison <ken@oceana.com>
+ * doc/draft-nerenberg-sasl-crammd5-03.txt: added
+ * doc/draft-nerenberg-sasl-crammd5-02.txt: deleted
+ * doc/draft-zeilenga-sasl-anon-01.txt: added
+ * doc/draft-zeilenga-sasl-anon-00.txt: deleted
+ * doc/draft-zeilenga-sasl-plain-01.txt: added
+ * doc/draft-zeilenga-sasl-plain-00.txt: deleted
+ * doc/index.html: updated to latest CRAM-MD5, ANONYMOUS, PLAIN drafts
+
+2002-11-01 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * plugins/kerberos4.c: Make at most 1 canon_user call, not two.
+ (Howard Chu <hyc@highlandsun.com>)
+
+2002-10-25 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * saslauthd/lak.c: minor cleanups
+
+2002-10-24 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * saslauthd/lak.c: fix problem where saslauthd stops LDAP
+ authentications when ldap_auth_method is bind.
+ (Igor Brezac <igor@ypass.net>)
+ * doc/sysadmin.html, doc/options.html, saslauthd/saslauthd.mdoc:
+ documentation updates re: saslauthd mux path
+
+2002-10-23 Ken Murchison <ken@oceana.com>
+ * lib/external.c: added SASL_SEC_NOANONYMOUS to client side
+ (Howard Chu, <hyc@highlandsun.com>)
+
+2002-10-21 Ken Murchison <ken@oceana.com>
+ * plugins/ntlm.c: NTLM probably doesn't offer perfect forward secrecy
+ * doc/mechanisms: added table of properties/features
+
+2002-10-20 Ken Murchison <ken@oceana.com>
+ * saslauthd/lak.ch: consolidated hashed password checking code
+
+2002-10-18 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * saslauthd/lak.[ch], saslauthd/auth_ldap.c:
+ Code cleanup, now support {SHA}, {SSHA}, {MD5}, and {SMD5} hashes,
+ misc other cleanup. (Igor Brezac <igor@ypass.net> and
+ Thomas Lussnig <thomas.lussnig@bewegungsmelder.de>)
+
+2002-10-17 Ken Murchison <ken@oceana.com>
+ * doc/draft-melnikov-rfc2831bis-02.txt: added
+ * doc/draft-melnikov-rfc2831bis-01.txt: deleted
+ * doc/index.html: updated to latest RFC 2831bis draft
+
+2002-10-11 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * lib/Makefile.am: add missing staticopen.h to EXTRA_DIST,
+ fix some dependencies
+ * Ready for 2.1.9
+
+2002-10-10 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * Ready for 2.1.8
+
+2002-10-09 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * lib/client.c: Allow plaintext mechanisms under an external security
+ layer.
+
+2002-10-07 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * sample/server.c: Fix some IPV6 defines
+ (Marshall Rose <mrose@dbc.mtview.ca.us>)
+
+2002-10-02 Ken Murchison <ken@oceana.com>
+ * lib/checkpw.c: return SASL_NOUSER when we can't find APOP secret
+ * lib/server.c: plug APOP memory leak and consolidate canonification
+ * configure.in: force the use of a cache file
+ (Carlos Velasco <carlosev@newipnet.com>)
+
+2002-10-02 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * lib/checkpw.c: Fix some misuses of sasl_seterror
+ (Martin Exler <m.exler@gmx.at>)
+
+2002-09-24 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * config/sasl2.m4, saslauthd/Makefile.am: GSSAPI doesn't need
+ to link ndbm. Also cleanup some sasldb linking in saslauthd.
+
+2002-09-23 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * config/kerberos_v4.m4: Don't compile with kerberos unless we
+ have both the libs and the headers (Carlos Velasco
+ <carlosv@newipnet.com>)
+
+2002-09-19 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * plugins/gssapi.c: endinaness corrections
+ * sasldb/db_berkeley.c, utils/dbconverter-2.c: Berkley DB 4.1
+ support (Mika Iisakkila <mika.iisakkila@pingrid.fi>)
+
+2002-09-19 Ken Murchison <ken@oceana.com>
+ * plugins/plugin_common.[ch]: make SASL_CB_USER and result optional
+ * plugins/anonymous.c: use SASL_CB_USER for fetching trace info,
+ don't require SASL_CB_AUTHNAME
+ * plugins/gssapi.c, plugins/kerberos.c: don't require SASL_CB_USER
+ * lib/external.c: define SASL_FEAT_ALLOWS_PROXY for this mechanism,
+ don't require SASL_CB_USER
+
+2002-09-18 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * plugins/srp.c, plugins/kerberos4.c: correct maxoutbuf handling
+ * plugins/digestmd5.c: correct maxoutbuf handling, actually
+ send maxbuf to the remote.
+ * lib/common.c: sanity check security properties
+
+2002-09-17 Ken Murchison <ken@oceana.com>
+ * plugins/ntlm.c: home-grown client/server NTLM implementation
+ * configure.in: NTLM depends on OpenSSL libcrypto
+ * doc/sysadmin.html: added NTLM blurb
+
+2002-09-16 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * lib/canonusr.c: don't index begin_u with -1
+ (Randy Kunkee <randy@randallkunkee.com>)
+ * doc/sysadmin.html: cleanup
+ * utils/saslpasswd.c: don't exit with -SASL_FAIL
+ * saslauthd/saslauthd-unix.c: use a char* instead of a void* in
+ retry_read
+
+2002-09-12 Ken Murchison <ken@oceana.com>
+ * lib/common.c: NULL outbuf if we get no output from sasl_decode()
+
+2002-09-11 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * plugins/mysql.c: Actually loop through the potential servers
+ properly (Seow Kok Heng <kokheng@jhs.com.sg>)
+ * acinclude.m4: Added copy of the correct libtool macros as
+ acinclude.m4
+ * configure.in: fix for gcc 3.x
+ (Carlos Velasco <carlosev@newipnet.com>)
+
+2002-09-10 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * lib/server.c: Better handling of add_plugin failures
+
+2002-09-10 Ken Murchison <ken@oceana.com>
+ * acconfig.h, configure.in: enable/disable NTLM
+ * lib/staticopen.h, plugins/Makefile.am, makeinit.sh, ntlm.c:
+ added NTLM support (client-side only)
+
+2002-09-07 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * saslauthd/configure.in, saslauthd/Makefile.am: don't
+ do configure substitutions for the saslauthd_SOURCES variable
+ (Carlos Velasco <carlosev@newipnet.com>)
+
+2002-09-05 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * doc/os390.html: added
+ * doc/index.html: referenced os390.html and macosx.html
+ * lib/Makefile.am: better handling of plugin_common
+
+2002-09-04 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * (throughout) Extensive cleanup of how we build static and
+ shared versions of libsasl. Also some more portability
+ fixes (Howard Chu <hyc@highlandsun.com>)
+
+2002-09-04 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * acconfig.h, configure.in: Actually check for sysexits.h,
+ varargs.h, and stdarg.h
+ * lib/checkpw.c: compatibility patch for retry_read
+ (Howard Chu <hyc@highlandsun.com>)
+
+2002-09-03 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * (throughout) fix handling of sys/param.h
+ * (throughout) fix handling of time.h and sys/time.h
+ * include/exits.h: include a replacement for sysexits.h
+ * acconfig.h: define MAXHOSTNAMELEN if it isn't
+ * lib/getaddrinfo.c, config/ipv6.m4: minor fixes for partial
+ getaddrinfo/getnameinfo implementations
+ * (Above changes are all from or based on ideas from
+ Howard Chu <hyc@highlandsun.com>)
+
+2002-08-28 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * lib/client.c, lib/saslint.h: Properly handle client-side
+ serverFQDN and clientFQDN
+
+2002-08-19 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * lib/dlopen.c: use correct paths when a .la file is not present
+ (Justin Gibbs <gibbs@scsiguy.com>)
+
+2002-08-13 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * doc/sysadmin.html: fix some /usr/lib/sasl references to
+ /usr/lib/sasl2 (Andrew Jones <arjones@simultan.dyndns.org>)
+
+2002-08-09 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * saslauthd/Makefile.am: fix small parts of the saslauthd.8 build
+ process.
+ * Ready for 2.1.7
+
+2002-08-06 Ken Murchison <ken@oceana.com>
+ * plugins/digestmd5.c: disable/remove server-side fast reauth
+
+2002-08-02 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * include/sasl.h, lib/common.c: Add SASL_AUTHUSER as a parameter
+ to sasl_getprop
+
+2002-08-01 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * saslauthd/lak.c: allow use of more than one %u or %r in the filter
+ (Laurent Larquère <llarquere@aacom.fr>)
+
+2002-07-30 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * lib/client.c, lib/server.c: Add checks for SASL_NEED_PROXY and
+ SASL_FEAT_ALLOWS_PROXY
+ * include/sasl.h, include/saslplug.h: Add SASL_NEED_PROXY and
+ SASL_FEAT_ALLOWS_PROXY
+ * plugins/digestmd5.c, plugins/gssapi.c, plugins/kerberos4.c,
+ plugins/otp.c, plugins/plain.c, plugins/srp.c: define
+ SASL_FEAT_ALLOWS_PROXY for these mechanisms
+
+2002-07-27 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * saslauthd/auth_sasldb.c: Include mechanisms.h in a reasonable place.
+
+2002-07-24 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * saslauthd/Makefile.am: Fix DEFS to still supply -I. and -I..
+ * configure.in: Make --with-ldap show up in top level configure script,
+ make saslauthd compile by default
+ * lib/saslutil.c: use read() and not fread() on /dev/random to preserve
+ entropy
+ * doc/sysadmin.html: Add note about using /dev/urandom
+
+2002-07-19 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * doc/sysadmin.html, doc/readme.html, doc/upgrading.html:
+ Misc. documentation cleanup (Joe Rhett <jrhett@isite.net>)
+
+2002-07-17 Ken Murchison <ken@oceana.com>
+ * lib/canonusr.c: update length of user string to length of output
+ from callback
+
+2002-07-16 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * plugins/cram.c: Fix a security problem in the verification of
+ the digest string. (Andrew Jones <arjones@simultan.dyndns.org>)
+ * Ready for 2.1.6
+
+2002-07-06 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * plugins/mysql.c: Further memory management cleanup. (never
+ strdup the options, and therefore don't free staticly allocated
+ strings)
+ * man/sasl_getopt_t.3: Clarify semantics of memory management
+
+2002-07-05 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * saslauthd/lak.c: Better handling of downed ldap servers
+ (Igor Brezac <igor@ipass.net>)
+ * sasldb/db_berkeley.c, utils/dbconverter-2.c: Use db_strerror()
+ rather than strerror() for Berkeley DB error values.
+ (J.H.M. Dassen (Ray) <jdassen@debian.org>)
+ * saslauthd/Makefile.am, saslauthd/auth_ldap.c: don't
+ hardwire the saslauthd conf file
+ (J.H.M. Dassen (Ray) <jdassen@debian.org>)
+
+2002-07-03 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * man/sasl_user_exists.3: fix sasl_idle reference
+
+2002-07-02 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * lib/auxprop.c: Can now select multiple auxprop plugins
+ * doc/options.html: updated for above
+ * lib/client.c: improve mechanism selection to include
+ number of security flags
+
+2002-06-27 Ken Murchison <ken@oceana.com>
+ * doc/draft-zeilenga-sasl-plain-00.txt: added
+ * doc/index.html: added PLAIN draft
+
+2002-06-26 Ken Murchison <ken@oceana.com>
+ * doc/draft-zeilenga-sasl-anon-00.txt: added
+ * doc/index.html: added ANONYMOUS draft
+
+2002-06-20 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * lib/auxprop.c: Make "cound not find auxprop plugin" warning
+ log at LOG_DEBUG
+
+2002-06-19 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * plugins/digestmd5.c: create layer keys for integrity as
+ well as privacy
+ * saslauthd/auth_ldap.[ch], saslauthd/lak.[ch]:
+ Large rewrite (Igor Brezac <igor@ipass.net>)
+ * lib/client.c, lib/server.c, lib/common.c:
+ Actually set most of the sparams and cparams structures
+
+2002-06-19 Ken Murchison <ken@oceana.com>
+ * doc/draft-melnikov-rfc2831bis-01.txt: added
+ * doc/draft-melnikov-rfc2831bis-00.txt: deleted
+ * doc/index.html: updated to latest RFC 2831bis draft
+
+2002-06-18 Ken Murchison <ken@oceana.com>
+ * doc/draft-nerenberg-sasl-crammd5-02.txt: added
+ * doc/draft-nerenberg-sasl-crammd5-01.txt: deleted
+ * doc/index.html: updated to latest CRAM-MD5 draft
+
+2002-06-17 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * plugins/login.c, plugins/plain.c: Canonicalize username before
+ doing checkpass
+
+2002-06-14 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * lib/client.c, lib/server.c, lib/saslint.h, lib/common.c.
+ lib/seterror.c: continued size_t vs unsigned cleanups
+
+2002-06-13 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * saslauthd/ : remove LDAP support
+ * Ready for 2.1.5
+
+2002-06-12 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * plugins/digestmd5.c: rename get_realm to get_server_realm, and
+ pay attention to its return value
+ * lib/external.c, lib/seterror.c: cleanup size_t/unsigned confusion
+
+2002-06-10 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * sasldb/Makefile.am: fix handling of allockey (only include it once)
+ * plugins/kerberos4.c: fix a reference count leak
+ * Ready for 2.1.4
+
+2002-05-28 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * saslauthd/LDAP_SASLAUTHD, saslauthd/saslauthd.mdoc:
+ Update documentation for LDAP and Saslauthd as per
+ Igor Brezac <igor@ipass.net>
+
+2002-05-22 Lawrence Greenfield <leg+@andrew.cmu.edu>
+ * lib/checkpw.c: close door file descriptor in
+ saslauthd_verify_password
+
+2002-05-21 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * saslauthd/auth_krb5.c: fix a leak due to not
+ calling krb5_cc_destroy on failure
+
+2002-05-17 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * saslauthd/saslauthd-*.c: support a generic mechanism option -O
+ instead of -H
+ * saslauthd/auth_ldap.c, lak.c, et. al: auth_ldap overhaul
+ (Igor Brezac <igor@ipass.net>)
+ * lib/common.c, include/sasl.h: add sasl_version
+
+2002-05-13 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * lib/checkpw.c: use "*cmusaslsecretPLAIN" in auxprop_verify_password
+ (Howard Chu, <hyc@highlandsun.com>), also only make a single
+ canon_user call.
+
+2002-05-13 Ken Murchison <ken@oceana.com>
+ * plugins/plugin_common.c: set the return code to SASL_FAIL, and
+ NULL the results of the _plug_get_*() functions before we get
+ started
+ * plugins/digestmd5.c, otp.c, plain.c, srp.c: check for NULL or
+ empty authzid from callback
+
+2002-05-09 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * saslauthd/configure.in: --with-ldap now takes a path
+
+2002-05-08 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * saslauthd/acconfig.h, auth_ldap.c, configure.in, lak.c, lak.h:
+ Misc compile/portability fixes (mostly header-related)
+ * utils/testsuite.c: minor getopt() parameter fix
+ (Claus Assmann <ca+sasl@sendmail.org>)
+ * lib/checkpw.c: fix some warnings
+
+2002-05-07 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * Ready for 2.1.3-BETA
+
+2002-05-06 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * include/saslplug.h: add name member for canon_user plugins
+ * lib/canonusr.c: use name member
+
+2002-05-06 Ken Murchison <ken@oceana.com>
+ * plugins/digestmd5.c: added client-side reauth
+
+2002-05-05 Ken Murchison <ken@oceana.com>
+ * lib/client.c: pass global_context to mech_new()
+ * lib/server.c: don't free global_context (the plugin should free it)
+ * utils/testsuite: swapped serverlast tests so that the
+ descriptions are correct
+
+2002-05-03 Ken Murchison <ken@oceana.com>
+ * plugins/digestmd5.c: added server-side reauth
+ * doc/index.html: added Marshall Rose's SASL papers
+ * doc/options.html: added 'reauth_timeout'
+
+2002-05-03 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * plugins/kerberos4.c: fix compile errors
+ * config/kerberos_v4.m4, plugins/digestmd5.c: fix des_cbc_encrypt
+ interoperability problem (OpenSSL)
+ * saslauthd/Makefile.am, acconfig.h, auth_ldap.c, auth_ldap.h,
+ configure.in, lak.c, lak.h, mechanisms.c, mechanisms.h,
+ saslauthd.conf: added experimental LDAP saslauthd module
+ (by Igor Brezac <igor@ipass.net>)
+ * include/saslplug.h: give auxprop plugins a name
+ * plugins/sasldb.c: give sasldb plugin a name
+ * lib/auxprop.c: allow auxprop selection
+ * doc/options.html: document auxprop_plugin option
+
+2002-05-01 Ken Murchison <ken@oceana.com>
+ * plugins/digestmd5.c, gssapi.c, kerberos4.c, srp.c:
+ general plugin cleanup - standardizing structure
+
+2002-04-30 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * plugins/gssapi.c: Minor cleanup of struct hack in context structure
+
+2002-04-30 Ken Murchison <ken@oceana.com>
+ * plugins/plugin_common.[ch], anonymous.c, cram.c, login.c, otp.c,
+ plain.c, sasldb.c, srp.c,
+ lib/client.c, external.c, saslint.h, server.c: general plugin
+ cleanup - reusing more common code, standardizing structure
+
+2002-04-28 Ken Murchison <ken@oceana.com>
+ * plugins/plugin_common.[ch], anonymous.c, cram.c, digestmd5.c,
+ gssapi.c, kerberosv4.c, login.c, otp.c, plain.c, srp.c,
+ lib/external.c:finalize movement of callback/interaction stuff
+ into plugin_common
+
+2002-04-27 Ken Murchison <ken@oceana.com>
+ * plugins/plugin_common.[ch], anonymous.c, cram.c, digestmd5.c,
+ gssapi.c, kerberosv4.c, login.c, otp.c, plain.c, srp.c,
+ lib/external.c: move make_prompts stuff into plugin_common
+ * utils/testsuite.c: allow for testing of EXTERNAL
+
+2002-04-26 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * sasldb/allockey.c: be sure to set userPassword and not *userPassword
+
+2002-04-26 Ken Murchison <ken@oceana.com>
+ * lib/client.c, server.c: check 'doneflag' just before mech_step()
+ * plugins/plugin_common.[ch], anonymous.c, cram.c, digestmd5.c,
+ gssapi.c, kerberosv4.c, login.c, otp.c, plain.c, srp.c,
+ lib/external.c, Makefile.am: move callback/interaction stuff
+ into plugin_common
+ * plugins/plugin_common.[ch], digestmd5.c, gssapi.c,
+ kerberosv4.c, srp.c: move decode/concatenation of multiple
+ packets into plugin_common
+ * utils/testsuite.c: set SASL_AUTH_EXTERNAL so we can test EXTERNAL
+
+2002-04-25 Ken Murchison <ken@oceana.com>
+ * plugins/otp.c: don't free the secret when we get data from a
+ callback (and don't copy it)
+ * plugins/gssapi.c, plain.c: make sure to set 'doneflag' when done
+ * lib/client.c, server.c: don't call mech_step() if 'doneflag' is set
+
+2002-04-24 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * plugins/cram.c, digestmd5.c, login.c, plain.c, srp.c: don't
+ free the secret when we get data from a callback (and don't copy it)
+
+2002-04-22 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * include/gai.h: Fix for compatibility with older glibc versions
+ (Howard Chu, <hyc@highlandsun.com>)
+ * plugins/gssapi.c: Don't always send authzid on client side
+ (Howard Chu, <hyc@highlandsun.com>)
+
+2002-04-18 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * saslauthd/auth_sasldb.c: Use "use_realm" instead of "realm"
+ for lookup of secret. (Jonas Oberg <jonas@gnu.org>)
+ * plugins/gssapi.c: Correct handling of client-side authid and
+ authzid (Howard Chu, <hyc@highlandsun.com>)
+ * lib/external.c: Better handling of user canonicalization
+ (Howard Chu, <hyc@highlandsun.com>)
+ * plugins/cram.c, digestmd5.c, gssapi.c, kerberos4.c,
+ login.c, otp.c, plain.c, srp.c: zero out prompt_need structures
+ before use
+
+2002-04-17 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * plugins/cram.c, digestmd5.c, srp.c: Adjust cmusaslsecretFOO to
+ *cmusaslsecretFOO
+ * plugins/sasldb.c: correctly handle *(property)
+ * lib/canonusr.c, server.c: Lookup authzid and authid auxprops
+ correctly (and in the same place).
+ * include/sasl.h, saslplug.h: Fix auxprop lookups
+ (e.g. SASL_AUXPROP_AUTHZID)
+
+2002-04-15 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * plugins/gssapi.c: Handle null authzid's correctly
+ * lib/server.c: fix a strcmp() that should be a memcmp()
+
+2002-04-15 Rob Siemborski <rjs3@andrew.cmu.edu>
+ * plugins/gssapi.c: fix how name_token and name_without_realm are
+ freed.
+
+2002-04-12 Ken Murchison <ken@oceana.com>
+ * doc/draft-melnikov-rfc2831bis-00.txt: added
+ * doc/draft-myers-saslrev-02.txt: moved TOC
+ * doc/draft-myers-saslrev-02.txt: added
+ * doc/draft-myers-saslrev-01.txt: deleted
+ * doc/index.html: changed link to updated saslrev draft,
+ added KERBEROS_V4 notation,
+ added link to rfc2831bis draft
+
+2002-04-08 Ken Murchison <ken@oceana.com>
+ * lib/server.c, doc/options.html: allow multiple pwcheck_methods
+
+2002-04-03 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * saslauthd/configure.in: properly define AUTH_KRB5
+ * saslauthd/auth_krb5.c: changes for MIT KRB5
+
+2002-03-27 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * Removed check for db3/db.h (people can just use --with-bdb-incdir)
+
+2002-03-26 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * Ready for 2.1.2
+
+2002-03-11 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * plugins/kerberos4.c: Fix a race condition during mutex allocation
+
+2002-03-04 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * lib/checkpw.c: Stop logging "authentication failed" message
+ * plugins/gssapi.c: Reduce log level of "gss_accept_context" message
+
+2002-02-27 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * saslauthd/saslauthd.mdoc: Clarify that sasldb with saslauthd
+ is not what you want to be doing.
+ * doc/sysadmin.html: Update "sasldb" verifier to "auxprop"
+
+2002-02-22 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * lib/checkpw.c: made retry_read static
+
+2002-02-21 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * lib/checkpw.c (auxprop_verify_password) report SASL_NOUSER instead
+ of SASL_FAIL.
+ * lib/client.c, lib/server.c: More Complete returning of SASL_NOTINIT
+ * utils/testsuite.c: Better checking for SASL_NOTINIT
+
+2002-02-11 Ken Murchison <ken@oceana.com>
+ * plugins/srp.c: removed OpenSSL 0.9.6 dependencies, small bugfix
+ * configure.in: cleaned up OpenSSL (libcrypto) check
+
+2002-02-05 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * contrib/tclsasl: Add Marshall Rose's <mrose@dbc.mtview.ca.us>
+ tclsasl patch.
+ * plugins/anonymous.c: No longer append extra NUL to client response
+
+2002-02-04 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * utils/saslpasswd.c: Added -n option (Ken Murchison)
+ * lib/dlopen.c: Removed confusing entry point message.
+ * Ready for 2.1.1
+
+2002-02-01 Ken Murchison <ken@oceana.com>
+ * plugins/srp.c: fixed srp_setpass()
+
+2002-01-31 Ken Murchison <ken@oceana.com>
+ * include/sasl.h, lib/server.c,
+ plugins/digestmd5.c, gssapi.c, kerberos4.c, srp.c:
+ added SASL_SEC_MUTUAL_AUTH
+ * plugins/srp.c: cleanup error messages and return codes
+
+2002-01-30 Ken Murchison <ken@oceana.com>
+ * plugins/otp.c, plugins/otp.h: added non-OPIE client/server
+ implementation (requires OpenSSL)
+ * configure.in: OTP now requires OpenSSL, OPIE is optional
+ * doc/options.html, doc/readme.html, doc/sysadmin.html, doc/TODO:
+ updated for new OTP implementation
+
+2002-01-25 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * saslauthd/Makefile.am: Correct multiple EXTRA_DIST bug
+ * saslauthd/Makefile.am: small typo fixed (Leena Heino <liinu@uta.fi>)
+
+2002-01-23 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * utils/dbconverter-2.c (main): More intelligent default paths
+ * acconfig.h: #ifndef's for _GNU_SOURCE (Assar <assar@permabit.com>)
+
+2002-01-22 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * lib/common.c: Complete definition of sasl_global_listmech
+ (from Love <lha@stacken.kth.se>)
+ * lib/client.c: added checks for _sasl_client_active to
+ sasl_client_new and sasl_client_start
+
+2002-01-21 Ken Murchison <ken@oceana.com>
+ * doc/draft-myers-saslrev-01.txt: moved TOC
+ * doc/draft-ietf-cat-sasl-gssapi-05.txt: moved TOC
+ * doc/draft-nerenberg-sasl-crammd5-01.txt: added
+ * doc/draft-nerenberg-sasl-crammd5-00.txt: deleted
+ * doc/index.html: changed link to updated draft
+ * plugins/login.c (login_client_mech_step): fix client-first
+ handling
+
+2002-01-21 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * lib/server.c (sasl_server_start): null out *serverout and
+ *serveroutlen, just in case.
+ * lib/external.c: Added correct required_prompts
+ * saslauthd/testsaslauthd.c: Added simple saslauthd client
+ * saslauthd/Makefile.am: rules for testsaslauthd
+ * doc/sysadmin.html: updated to reference testsaslauthd
+ * saslauthd/saslauthd.c: allow -n 0 (for fork-per-connection)
+ * saslauthd/saslauthd.mdoc: documentation of -n 0
+ * plugins/cram.c (crammd5_client_mech_step): fix client-first
+ handling
+ * sasldb/db_gdbm.c: improved error reporting
+ (Courtesy Marshall T. Rose <mrose@dbc.mtview.ca.us>
+ * config/sasldb.m4: improved gdbm configure handling
+ (Courtesy Marshall T. Rose <mrose@dbc.mtview.ca.us>
+ * config/kerberos_v4.m4: Detect OpenSSL libdes first.
+ (Courtesy Marshall T. Rose <mrose@dbc.mtview.ca.us>
+ * plugins/cram.c, digestmd5.c, kervberos4.c, login.c,
+ lib/client.c, server.c, include/saslplug.h:
+ Cleaner client-first ABI.
+
+2002-01-19 Ken Murchison <ken@oceana.com>
+ * plugins/otp.c: set serverout to NULL where we have nothing to
+ send instead of the empty string
+ * plugins/srp.c: let glue code handle client-last/server-last
+ situation by setting serverout appropriately
+
+2002-01-19 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * plugins/plain.c, plugins/login.c, plugins/digestmd5.c:
+ set serverout to NULL where we have nothing to send instead of
+ the empty string
+ * include/saslplug.h, lib/client.c, lib/server.c: eliminated
+ SASL_FEAT_WANT_SERVER_LAST in favor of clever setting of serverout
+ * plugins/digestmd5.c: removed SASL_FEAT_WANT_SERVER_LAST
+
+2002-01-18 Ken Murchison <ken@oceana.com>
+ * plugins/srp.c: updated to draft-burdis-cat-srp-sasl-06
+ * plugins/srp.c: server uses external SSF
+ * plugins/srp.c: server sends mandatory options based on min SSF
+ * doc/draft-burdis-cat-srp-sasl-06.txt: added
+ * doc/draft-burdis-cat-srp-sasl-05.txt: deleted
+ * doc/index.html: changed link to updated draft
+
+2002-01-17 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * plugins/kerberos4.c: Actually allocate a mutex on the client side
+
+2002-01-16 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * lib/server.c (mech_permitted): fixed incorrect return value of
+ SASL_NOMECH that should have been 0.
+ * lib/common.c (sasl_errdetail): fixed core if passed in conn is NULL
+ * plugins/digestmd5.c (encode_tmp_buf): removed unneeded buffer
+
+2002-01-16 Ken Murchison <ken@oceana.com>
+ * plugins/srp.c: fixed layer decoding to handle multiple packets
+ * plugins/srp.c: plugged memory leaks (now passes testsuite)
+ * plugins/srp.c: more logging
+ * plugins/srp.c: lots of other nits, bug fixes
+ * utils/testsuite.c: added SSF=0/56 test
+
+2002-01-14 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * saslauthd/auth_krb4.c (auth_krb4): fix tf_name memory leak,
+ and other efficency fixes
+
+2002-01-11 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * include/saslplug.h: Add flags member to params structures
+ * lib/client.c, lib/server.c: flags parameter to sasl_*_new
+ now gets to the plugins
+
+2002-01-10 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * include/sasl.h: Update for sasl_global_listmech API
+ * lib/common.c, lib/client.c, lib/server.c: sasl_global_listmech()
+ * lib/dlopen.c (_parse_la): fix parseing of dlname= line
+ * Ready for 2.1.0
+
+2002-01-09 Ken Murchison <ken@oceana.com>
+ * plugins/otp.c: fixed security_flags
+ * plugins/srp.c: corrected integrity layer encoding
+ * plugins/srp.c: finished maxbuffersize handling
+ * plugins/srp.c: fixed security_flags
+ * doc/index.html: added reference to SRP paper
+
+2002-01-09 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * lib/common.c (sasl_decode): Removed maxoutbuf check
+ * man/sasl_setprop.3: Minor clarifications
+ * plugins/digestmd5.c, plugins/gssapi.c, plugins/kerberos4.c:
+ Assorted security layer fixes (maxoutbuf setting, mech_ssf setting)
+ * lib/common.c, lib/client.c, lib/server.c, lib/saslint.h:
+ Allowed client-side sasl_listmech calls.
+ * include/sasl.h: Minor cosmetic fix to comments
+ * doc/programming.html: Interaction memory management clarifications
+ * lib/common.c: Fix several crash problems in getprop
+ (Courtesy Marshall T. Rose <mrose@dbc.mtview.ca.us>)
+
+2002-01-05 Lawrence Greenfield <leg+@andrew.cmu.edu>
+ * saslauthd/saslauthd.c: F_SETLK doesn't block; F_SETLKW does
+ * saslauthd/saslauthd.c: detect errors somewhat better
+
+2002-01-04 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * lib/common.c: Allow sasl_setprop for SASL_DEFUSERREALM
+
+2002-01-04 Ken Murchison <ken@oceana.com>
+ * plugins/srp.c: don't send M2 if using a confidentiality layer
+ * plugins/srp.c: more constraint checks
+ * plugins/otp.c: improve standard hex/word response detection
+ * doc/install.html, doc/sysadmin.html, contrib/opie-2.4-fixes:
+ add patch for OPIE 2.4 to enable extended responses
+
+2002-01-03 Ken Murchison <ken@oceana.com>
+ * configure.in: removed check fpr gmp
+ * plugins/srp.c: migrated to OpenSSL's BN (removed GNU MP dependency)
+
+2001-12-20 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * sasldb/db_ndbm.c: Fixed small memory leak
+ (Courtesy Howard Chu <hyc@highlandsun.com>)
+
+2001-12-18 Ken Murchison <ken@oceana.com>
+ * plugins/srp.c: more constraint checks
+
+2001-12-17 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * saslauthd/saslauthd.c: Prefork a number of processes to handle
+ connections.
+ * saslauthd/auth_krb4.c: Handle concurrent accesses better.
+
+2001-12-15 Ken Murchison <ken@oceana.com>
+ * plugins/srp.c: added confidentiality layers
+
+2001-12-14 Ken Murchison <ken@oceana.com>
+ * plugins/srp.c: improved client/server layer option handling
+ * plugins/srp.c: added client-side support for mandatory options
+ * plugins/srp.c: added framework for confidentiality layers
+ * plugins/srp.c: added some data sanity checking (thanks to
+ Tom Holroyd <tomh@po.crl.go.jp> for feedback)
+
+2001-12-13 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * lib/server.c, lib/common.c: Fix handling of
+ global callbacks so that plugin_list works again
+
+2001-12-12 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * pwcheck/Makefile.am: Added include of ../lib
+ (from Hajimu UMEMOTO <ume@mahoroba.org>)
+
+2001-12-11 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * sasldb/db_ndbm.c: fix call to dbm_nextkey, from
+ Scot W. Hetzel <scot@genroco.com>
+
+2001-12-10 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * doc/plugprog.html: Update for new user canonicalization usage.
+ * man/sasl_canon_user.3: Update for new user canonicalization usage.
+ * configure.in: Actually set STATIC_GSSAPIV2 when necessary
+
+2001-12-08 Ken Murchison <ken@oceana.com>
+ * plugins/srp.c: make sure we have the HMAC before trying to use it
+ * plugins/srp.c: don't advertise server integrity w/o HMAC-SHA-1
+ * plugins/srp.c: move EVP_cleanup() to mech_free so mech can be reused
+
+2001-12-07 Ken Murchison <ken@oceana.com>
+ * configure.in: SRP now requires OpenSSL
+ * plugins/srp.c: migrated to OpenSSL's MDA/cipher abstraction API
+ * plugins/srp.c: added RIPEMD-160 support
+ * plugins/srp.c: using "standard ACSII names" for MDA-names as
+ documented by [SCAN] (until determined otherwise)
+ * plugins/srp.c: using updated canon_user API to allow separate
+ canonicalization of authid and authzid.
+
+2001-12-06 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * lib/canonusr.c: Better logging when desired plugin is not found.
+ * lib/checkpw.c: spelling error fixed.
+ * lib/canonusr.c, lib/checkpw.c, lib/client.c, lib/external.c,
+ lib/saslint.h, lib/server.c, include/sasl.h, include/saslplug.h,
+ plugins/*.c: Updated canon_user API to allow separate
+ canonicalization of authid and authzid.
+
+2001-12-05 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * saslauthd/Makefile.am, saslauthd/acconfig.h, saslauthd/configure.in:
+ Solaris 7 and FreeBSD (FreeBSD is courtesy of Claus Assmann
+ <ca+sasl@sendmail.org>)
+ * sasldb/Makefile.am: link order fix (Courtesy Claus Assmann
+ <ca+sasl@sendmail.org>)
+
+2001-12-05 Ken Murchison <ken@oceana.com>
+ * configure.in:
+ * plugins/Makefile.am: only build SRP with sasldb libs when
+ srp_setpass() is enabled
+ * plugins/srp.c: added HMAC-SHA-160 integrity layer
+ * plugins/srp.c: don't offer integrity layers unless HMAC-SHA-160
+ is available (mandatory)
+ * plugins/srp.c: fixed multiple integrity/confidentiality layer
+ client-side bug
+ * plugins/srp.c: fixed delete SRP secret bug
+ * plugins/srp.c: removed VL() stuff
+
+2001-12-04 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * utils/Makefile.am, config/sasldb.m4: Build sasldblistusers2
+ and saslpasswd2. Default database now /etc/sasldb2
+ * INSTALL, README, doc/index.html, doc/upgrading.html: Update
+ with upgrading instructions in preparation for release.
+ * doc/, /: Documentation reorganization, convert README and INSTALL to
+ HTML format.
+ * Bumped appropriate version numbers, Ready for 2.0.5-BETA
+
+2001-12-04 Ken Murchison <ken@oceana.com>
+ * acconfig.h, configure.in: dependency checking for SRP
+ * acconfig.h, configure.in:
+ * plugins/srp.c: made srp_setpass() a compile-time option (default=off)
+ * plugins/srp.c: use auxprop to fetch cmusaslsecretSRP/userPassword
+ * plugins/srp.c: code cleanup
+ * acconfig.h, configure.in:
+ * doc/sysadmin.html:
+ * plugins/otp.c: made otp_setpass() a compile-time option (default=off)
+
+2001-12-02 Ken Murchison <ken@oceana.com>
+ * plugins/srp.c: fixed SHA1 support
+ * plugins/srp.c: changed calculation of 'x' to coincide with draft -05
+ * plugins/srp.c: code cleanup
+
+2001-12-01 Ken Murchison <ken@oceana.com>
+ * plugins/srp.c: abstracted MDA interface
+ * plugins/srp.c: added SHA1 support (not working)
+
+2001-11-30 Ken Murchison <ken@oceana.com>
+ * plugins/srp.c: renumbered steps to start at 1
+ * plugins/srp.c: check plugin API version instead of SRP_VERSION
+ * plugins/srp.c: changed data exchanges to conform to draft -05
+
+2001-11-29 Ken Murchison <ken@oceana.com>
+ * plugins/srp.c: code now compiles and runs
+ * plugins/Makefile.am: added sasldb libs to SRP build
+
+2001-11-24 Ken Murchison <ken@oceana.com>
+ * lib/external.c: made EXTERNAL a client-send-first mechanism
+ * doc/index.html: added CRAM-MD5 draft
+
+2001-11-22 Ken Murchison <ken@oceana.com>
+ * plugins/otp.c: fixed otp_setpass() bug
+ * doc/sysadmin.html: OTP additions/changes
+
+2001-11-19 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * utils/saslpasswd.c: Corrected disable handling
+
+2001-11-17 Ken Murchison <ken@oceana.com>
+ * doc/index.html, rfc2945.txt, rfc3174.txt: specification additions
+ * doc/Makefile.am: Updated included RFCs and IDs
+
+2001-11-14 Ken Murchison <ken@oceana.com>
+ * lib/server.c, doc/options.html: added 'mech_list' option
+
+2001-11-14 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * sasldb/allockey.c: removed an assert() call
+ * sasldb/db_ndmb.c, sasldb/db_gdbm.c: Fixed cntxt's to be conn's
+
+2001-11-13 Ken Murchison <ken@oceana.com>
+ * acconfig.h, configure.in:
+ * plugins/otp.c: support client-side OTP without OPIE
+
+2001-11-08 Ken Murchison <ken@oceana.com>
+ * plugins/otp.c: allow entry of one-time password via
+ SASL_CB_ECHOPROMPT callback
+ * plugins/otp.c: code cleanup
+ * doc/index.html, draft*.txt: specification updates/additions
+
+2001-11-08 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * plugins/cram.c, digestmd5.c, sasldb.c: Removed all assert()
+ calls from supported plugins.
+
+2001-11-07 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * utils/testsuite.c: added proxy policy checks
+ * lib/checkpw.c (_sasl_auxprop_verify_apop): correct handling
+ of seterror calls
+
+2001-11-06 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * lib/canonusr.c (_canonuser_internal): added necessary seterror calls
+ * doc/Makefile.am: Updated included RFCs and IDs
+ * lib/canonusr.c, lib/server.c: Corrected authzid/authid handling
+ * plugins/digestmd5.c: Unconfused authzid/authid in server call to
+ canon_user
+
+2001-11-01 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * plugins/gssapi.c, plugins/kerberos4.c: Get rid of unnecessary
+ buffer copy in security layer encodes.
+
+2001-10-24 Ken Murchison <ken@oceana.com>
+ * plugins/otp.c: added otp_setpass() so that saslpasswd can
+ be used instead of opiepasswd on closed systems
+ * doc/sysadmin.html: OTP additions/changes
+
+2001-10-22 Ken Murchison <ken@oceana.com>
+ * acconfig.h, configure.in: detect OPIE, enable/disable OTP
+ * plugins/Makefile.am, makeinit.sh, otp.c: added OTP support
+ (still need work on RFC2444 compliance - depends on OPIE changes)
+ * doc/index.html, options.html, sysadmin.html, rfc*.txt:
+ OTP additions/changes
+
+2001-10-18 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * utils/testsuite.c: Test DES harder for DIGEST-MD5
+ * plugins/digestmd5.c (enc_des): Get rid of one buffer copy.
+ * plugins/digestmd5.c (dec_des, dec_3des): correct handling of
+ padding length check.
+
+2001-10-17 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * config/sasldb.m4: detect berkeley db 4
+ * plugins/gssapi.c, cram.c, kerberos4.c, digestmd5.c: have dispose
+ calls deal with the possibility of a null context
+
+2001-10-16 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * saslauthd/Makefile.am: Link LIB_PAM as well, if needed
+ * plugins/digestmd5.c: Don't send a trailing nul on challenge and
+ responses.
+ * lib/server.c (sasl_server_start, sasl_server_step): Deal with
+ authentication failures better. (Reported by Larry Rosenbaum
+ <lmr@ornl.gov>)
+
+2001-10-02 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * saslauthd/Makefile.am, saslauthd/auth_sasldb.c,
+ saslauthd/configure.in: Changes to allow extraction of saslauthd
+ as needed.
+
+2001-09-19 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * lib/getaddrinfo.c (getaddrinfo): Correct fix for
+ AI_PASSIVE bug from Hajimu UMEMOTO <ume@mahoroba.org>
+ * plugins/plugin_common.c, lib/common.c (_*_ipfromstring):
+ revert to previous versions.
+
+ * plugins/Makefile.am: Include necessry compatibility objects
+ as needed.
+ * lib/Makefile.am: compatibility code for static libsasl
+ * configure.in: small changes to make compatibility objects easy
+ to use.
+
+2001-09-18 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * plugins/plugin_common.c, lib/common.c (_*_ipfromstring):
+ no longer use AI_PASSIVE hint for getaddrinfo
+
+2001-09-13 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * saslauthd/auth_sasldb.c, saslauthd/auth_sasldb.h:
+ Added experimental sasldb saslauthd module
+ * saslauthd/configure.in: sasldb related config changes,
+ do not config if disabled
+
+2001-09-12 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * saslauthd/*, lib/checkpw.c (saslauthd_verify_password):
+ merged new saslauthd protocol from Ken Murchison <ken@oceana.com>
+
+2001-08-30 Rob Siemborski <rjs3+@andrew.cmu.edu>
+
+ * configure.in, saslauthd/configure.in: check for inet_aton
+ in libresolv.so, so as to link it if necessary
+
+ * config/sasldb.m4 (BERKELEY_DB_CHK_LIB): set runpath of library
+ if necessary
+
+2001-08-29 Rob Siemborski <rjs3+@andrew.cmu.edu>
+
+ * utils/testsuite.c: Minor testsuite fix (include paths)
+
+ * Ready for 2.0.4-BETA
+
+2001-08-24 Rolf Braun <rbraun+@andrew.cmu.edu>
+
+ * Mac OS 9 and X support, including Carbon
+ Mac OS 9 Classic support based on the SASL v1 code
+ by Aaron Wohl <n3liw+@andrew.cmu.edu>
+
+ * updated ltconfig and ltmain.sh
+ * acconfig.h:
+ * configure.in:
+ * lib/saslutil.c: use random() when jrand48() isn't available
+
+ * dlcompat-20010505:
+ dlcompat included for OS X support, compiles separately
+ * lib/dlopen.c: prefix symbols with underscore on OS X, as on OpenBSD
+ note that this is also detected automatically by configure,
+ this only helps when cross-compiling (for OS X?)
+
+ * acconfig.h:
+ * configure.in:
+ * config/kerberos_v4.m4
+ look for libdes524 when libdes doesn't exist.
+ look for libkrb4 when libkrb doesn't exist.
+
+ * lib/saslint.h:
+ * lib/common.c:
+ * lib/seterror.c:
+ * lib/Makefile.am:
+ split sasl_seterror() into a new file.
+ add_string -> _sasl_add_string and made this non-static
+ so seterror can use it.
+ added _sasl_get_errorbuf to go into the conn_t struct
+ so we don't have to know the format of that struct when
+ seterror.c is linked from glue code (i.e., the Mac OS X CFM glue)
+
+ * acconfig.h:
+ fix the order of the fake iovec struct for systems that
+ don't have it (like Mac OS 9) so it's the same order as
+ most Unixes that do (like Mac OS X) -- the CFM glue needs this
+
+ * acconfig.h:
+ include <sys/types.h> before we include <sys/uio.h>
+
+ * plugins/kerberos4.c:
+ * lib/checkpw.c:
+ * acconfig.h:
+ * configure.in:
+ check for krb_get_err_txt in the kerberos 4 library,
+ and use it instead of the krb_err_txt[] array if available
+
+ * plugins/kerberos4.c:
+ define KEYFILE to "/etc/srvtab" if not already defined
+ by the kerberos 4 headers (needed for MIT KfM 4.0)
+
+ * doc/macosx.html: added this
+ * README: point Mac OS X users to doc/macosx.html
+ * doc/Makefile.am: add doc/macosx.html to distfiles
+
+ * Makefile.am:
+ * lib/Makefile.am:
+ * include/Makefile.am:
+ * config/Info.plist:
+ * configure.in:
+ when building on Mac OS X, install a framework
+ in /Library/Frameworks
+
+ * mac/*:
+ projects and support files for Mac OS 9, classic and Carbon
+ * mac/osx_cfm_glue:
+ the glue to allow CFM Carbon applications under Mac OS X
+ call the Unix-layer SASL library
+
+ * lib/common.c:
+ * lib/canonusr.c:
+ don't do the auxprop stuff on Mac OS 9
+
+ * lib/getaddrinfo.c:
+ don't look up hostnames on Mac OS 9 (we only officially
+ support passing IP address strings anyway)
+
+ * lib/getaddrinfo.c:
+ * plugins/plugin_common.c:
+ * plugins/plugin_common.h:
+ don't include headers on Mac OS 9 that we don't have.
+
+ * sample/sample-client.c:
+ add a cast for Mac OS 9 (different type handling of char)
+
+ * plugins/makeinit.sh:
+ include the stub header to export the right symbols on Mac OS 9
+
+2001-08-20 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * plugins/gssapi.c (gssapi_server_mech_step): fixed accidental
+ back link into glue code
+
+ * config/kerberos4.m4: Actually link in -lkrb
+
+2001-08-15 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * lib/common.c (_sasl_iptostring): #if 0'd out.
+
+ * lib/server.c (sasl_user_exists): only check the verifier we
+ are using
+
+ * config/kerberos_v4.m4 (SASL_DES_CHK): added
+ * config/kerberos_v4.m4 (SASL_KERBEROS_V4_CHK): included
+ entire check from configure.in
+ * configure.in: moved kerberos 4 code completely out.
+ * saslauthd/acconfig.h (WITH_DES, WITH_SSL_DES): Added
+ DES-related symbols
+
+2001-08-14 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * configure.in: Check for sys/uio.h
+ * saslauthd/configure.in: Check for sys/uio.h
+ * config.h: Do the Right Thing for struct iovec (and
+ no longer include sys/uio.h elsewhere)
+ * saslauthd/config.h: Do the Right Thing for struct iovec (and
+ no longer include sys/uio.h elsewhere)
+
+2001-08-13 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * plugins/digestmd5.c (init_des, init_3des, enc_des, dec_des,
+ enc_3des, dec_3des): fixed interoperability problems,
+ 3des was not decrypting with correct key and des was not
+ setting up the initial vector.
+
+ * lib/checkpw.c (always_true): log users who log in via this verifier
+
+2001-08-13 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * utils/testsuite.c (giveokpath): fix memory leak
+
+ * lib/common.c (sasl_ipfromstring): add call to freeaddrinfo()
+ * plugins/plugin_common.c (_plug_ipfromstring): add call to
+ freeaddrinfo()
+
+ * lib/saslutil.c (sasl_randseed): actually initialize the randpool
+
+ * saslauthd/auth_getpwent.c (auth_getpwent): clear a warning
+ * saslauthd/auth_shadow.c (auth_shadow): clear a similar warning
+
+ * utils/Makefile.am (EXTRA_DIST): Actually include the needed files
+
+ * saslauthd/configure.in: Handle shadow passwords correctly
+ * saslauthd/acconfig.h: Handle shadow passwords correctly
+
+ * lib/checkpw.c (always_true): added
+ * configure.in: added check for alwaystrue verifier
+ * acconfig.h: added HAVE_ALWAYSTRUE
+ * doc/options.html: alwaystrue verifier documented
+
+2001-08-11 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * saslauthd/: Now configures separately from SASL, so as
+ to localize tests for that package within that package
+
+ * utils/dbconverter-2.c (listusers_cb): fix handling of APOP
+
+2001-08-10 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * saslauthd/Makefile.am (install-data-local):
+ correct handling of $(DESTDIR) (and create the directory if it
+ isn't there) [Amos Gouaux <amos@utdallas.edu>]
+
+ * lib/server.c (sasl_server_init): Added plugname to add_plugin
+ call for EXTERNAL
+
+ * doc/index.html: updated
+ * doc/appconvert.html: cleaned up
+
+2001-08-09 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * plugins/digestmd5.c (digestmd5_client_mech_step): handle
+ missing authorization name
+ * plugins/plain.c (plain_client_mech_step): handle
+ missing authorization name
+
+ * include/sasl.h: better documentation of SASL_CB_CANON_USER
+
+2001-08-08 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * saslauthd/saslauthd.mdoc: updated re: pam
+ * saslauthd/saslauthd.8: regenerated
+ * saslauthd/Makefile.am: Link against PLAIN_LIBS also
+ (from Ken Murchison <ken@oceana.com>)
+
+2001-08-07 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * lib/client.c (sasl_server_step): corrected maxoutbuf handleing
+ * lib/server.c (sasl_server_step): corrected maxoutbuf handleing
+ * lib/saslint.h (DEFAULT_MAXOUTBUF): removed
+
+ * lib/common.c (sasl_encodev, sasl_decode): maxbufsize checking
+
+ * utils/testsuite.c (testseclayer,doauth): more security layer
+ checking. Added parameter to doauth to disable fatal() calls,
+ updated all callers.
+
+ * utils/smtptest.c (main): added ability to support LMTP
+
+ * plugins/gssapi.c: conform with draft-ietf-cat-sasl-gssapi-05.txt
+
+ * doc/draft-ietf-cat-sasl-gssapi-05.txt: added
+ * doc/Makefile.am (EXTRA_DIST): added above to EXTRA_DIST
+
+2001-08-06 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * utils/dbconverter-2.c (listusers_cb): handle PLAIN-APOP
+
+ * lib/client.c (sasl_client_add_plugin, client_done):
+ save plugin name
+ * lib/server.c (sasl_server_add_plugin, server_done):
+ save plugin name
+ * lib/dlopen.c (_sasl_plugin_load): correctly pass pluginname
+ * lib/common.c (sasl_getprop): implement SASL_AUTHSOURCE properly
+ * lib/saslint.h (cmechanism_t, mechanism_t): added plugname field
+ * lib/canonusr.c (internal_canonuser_init): no longer limit
+ based on plugname
+ * plugins/sasldb.c (sasldb_auxprop_plug_init): no longer limit
+ based on plugname
+
+2001-08-01 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * utils/smtptest.c (iptostring): better behaved w.r.t endianness
+
+ * plugins/cram.c (crammd5_server_mech_step): support for old-style
+ secrets
+ * plugins/digestmd5.c (digestmd5_server_mech_step): support for
+ old-style secrets
+ * lib/checkpw.c (auxprop_verify_password,_sasl_make_plain_secret):
+ support for old-style secrets
+ * utils/dbconverter-2.c: added
+ * utils/sasldblistusers.c (listusers): Print out property names
+ as well as username@realm format.
+ * utils/saslpasswd.c (_sasl_sasldb_set_pass): Correctly handle updates
+ that concern old-style secrets
+
+ * sasldb/allockey.c: Added a missing null to propName in key parser
+
+2001-07-31 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * plugins/kerberos4.c (mech_avail): made static
+
+ * plugins/kerberos4.c (mech_avail): fixed ipv4 check
+ (patch from Hajimu UMEMOTO <ume@mahoroba.org>)
+
+ * doc/appconvert.html: vague guide documenting our experience
+ porting Cyrus IMAPd to use SASLv2
+ * doc/Makefile.am: added appconvert.html
+
+ * lib/client.c (sasl_client_new): fixed ip address setting to hit
+ relevant params structures as well
+ * lib/server.c (sasl_server_new): fixed ip address setting to hit
+ relevant params structures as well
+ * lib/common.c (sasl_setprop): fixed ip address setting to hit
+ relevant params structures as well
+
+ * lib/common.c (sasl_seterror): fixed spelling error
+
+2001-07-30 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * sasldb/db_berkeley.c: utils->seterror() calls
+ * sasldb/db_gdbm.c: utils->seterror() calls
+ * sasldb/db_ndbm.c: utils->seterror() calls
+ * sasldb/allockey.c: utils->seterror() calls
+
+ * lib/common.c (sasl_seterror): still call logging callback with a
+ null sasl_conn_t
+
+ * plugins/sasldb.c (sasldb_auxprop_lookup): support for multiple
+ properties
+
+ * plugins/Makefile.am: added -module to LDFLAGS
+
+ * config/sasldb.m4: Allow specification of exact berkeley db
+ lib and include paths
+ * sasldb/Makefile.am: Add proper include directory
+
+ * sasldb/sasldb.m4 (SASL_DB_BACKEND_STATIC): include allockey.o
+
+ * Ready for 2.0.3-BETA
+
+ * plugins/kerberos4.c (kerberos4_server_plug_init): reset
+ srvtab when we do not load correctly.
+
+ * lib/staticopen.c (_sasl_load_plugins): do not fail
+ if a single plugin load fails
+
+ * include/sasl.h (SASL_CLIENT_FALLBACK): removed
+
+2001-07-27 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * configure.in: extracted SASLDB-related checking
+ * config/sasldb.m4: added
+
+ * configure.in: now cache the JNI include directory path
+
+ * utils/testsuite.c: switch some sasl_errstrings to sasl_errdetail
+ * plugins/gssapi.c: Fix error reporting
+
+ * plugins/gssapi.c: Required SASL_CB_USER instead of SASL_CB_AUTHNAME
+
+ * plugins/anonymous.c: Function name standardization
+ * plugins/cram.c: Function name standardization
+ * plugins/digestmd5.c: Function name standardization
+ * plugins/gssapi.c: Function name standardization
+ * plugins/kerberos.c: Function name standardization
+ * plugins/login.c: Function name standardization
+ * plugins/plain.c: Function name standardization
+
+ * sasldb/allockey.c: Generalized SASLdb API
+ * sasldb/db_berkeley.c: Generalized SASLdb API
+ * sasldb/db_gdbm.c: Generalized SASLdb API
+ * sasldb/db_ndbm.c: Generalized SASLdb API
+ * sasldb/db_none.c: Generalized SASLdb API
+ * sasldb/db_testw32.c: Added #error to block compile so the API will
+ be fixed when we do the Win 32 port
+ * plugins/sasldb.c: Use new SASLdb API
+ * utils/saslpasswd.c: Use new SASLdb API
+
+2001-07-26 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * lib/common.c (_sasl_getcallback): fixed reference to
+ possibly NULL conn
+
+ * configure.in: only build saslpasswd and sasldblistusers
+ if we have a meaningfull libsasldb (e.g. not db_none),
+ * utils/Makefile.am: only build saslpasswd and sasldblistusers
+ if we have a meaningfull libsasldb (e.g. not db_none),
+
+ * configure.in: conditionally build smtptest
+ * utils/Makefile.am: conditionally build smtptest
+
+ * sasldb/allockey.c (_sasldb_parse_key): added
+
+ * sasldb/sasldb.h: New key list access API, added parameter to
+ sasl_check_db (all callers updated, all callees updated)
+ * sasldb/db_berkeley.c: Implement key list access API
+ * sasldb/db_gdbm.c: Implement key list access API
+ * sasldb/db_ndbm.c: Implement key list access API
+ * sasldb/db_none.c: Implement key list access API
+
+ * utils/sasldblistuser.c: Use libsasldb instead of internal
+ functions.
+
+ * utils/saslpasswd.c: No longer have separate global_utils,
+ call sasl_dispose and sasl_done
+
+ * acconfig.h: check for inttypes.h
+ * configure.in: check for inttypes.h
+ * plugins/plugin_common.c: include, if necessary, inttypes.h,
+ reference uint32_t instead of u_int32_t
+
+2001-07-25 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * lib/saslint.h: changed "sasldb" verifier to "auxprop"
+ * lib/server.c: changed "sasldb" verifier to "auxprop"
+ * lib/checkpw.c: changed "sasldb" verifier to "auxprop"
+ * utils/testsuite.c: changed "sasldb" verifier to "auxprop"
+ * doc/options.html: changed "sasldb" verifier to "auxprop"
+
+ * README: updated upgrade information
+
+ * utils/Makefile.am (CLEANFILES): added
+
+ * sasldb/allockey.c (alloc_key): single place for alloc_key()
+ Removed alloc_key from other source files.
+ * sasldb/sasldb.h: added declaration of alloc_key()
+
+ * configure.in: added checks for db-3.3 and db3.3
+
+ * plugins/digestmd5.c (get_realm): now error on empty user_realm
+
+ * plugins/cram.c (client_required_prompts): removed redundant
+ required_prompts
+
+ * plugins/plain.c (client_continue_step): server-send-last error
+
+ * utils/testsuite.c (main): detailed client-send-first,
+ server-send-last checking
+
+2001-07-24 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * plugins/sasldb.c: Cleaned up calls into the glue code
+
+ * java/Test/*: Cleaned up java test utilities
+
+ * configure.in: Minor GSSAPI configure changes
+
+ * utils/saslpasswd.c: Clarfied -d option for saslpasswd
+ * utils/saslpasswd.8: Clarfied -d option for saslpasswd
+
+ * doc/plugprog.html: Added plugin programmer's guide
+ * doc/index.html: linked to plugin programmer's guide
+
+ * configure.in: corrected configure checking of Berkeley DB
+ (from Scot W. Hetzel <scot@genroco.com>)
+
+ * configure.in: corrected checking for libcom_err
+ (from Scot W. Hetzel <scot@genroco.com>)
+
+2001-07-23 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * configure.in: Added check for db3/db.h
+
+ * plugins/kerberos4.c Added mech_avail (checks for IP info)
+
+ * lib/common.c: Fixed setting of serverFQDN in _sasl_conn_init
+
+ * lib/server.c: Fully Implemented mech_avail calls in glue code
+
+ * lib/server.c: Fixed allocation/destruction of sasl_conn_t's
+ * lib/client.c: Fixed allocation/destruction of sasl_conn_t's
+ * lib/common.c: Rely on earlier initialization in server.c and client.c
+
+ * doc/options.html: added
+
+ * ChangeLog: back to standard format
+
+2001-07-20 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * Can now deal with variable client-first mechs such as
+ DIGEST-MD5, though this interface is subject to change
+ * Modified parseuser to deal better with default realms
+ * Simplified realm handling in DIGEST-MD5 (getrealm callback
+ is no longer required).
+ * Cleaned up some memory management issues in DIGEST-MD5
+
+2001-07-19 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * Fixed prototype of sasl_getpath_t to be in conformance with
+ memory allocation rules
+ * Fixed up samples directory
+ * Try to dlopen using information in .la file if available
+ (based on patch from
+ Stoned Elipot <Stoned.Elipot@script.jussieu.fr>)
+ * Resolution of most of the server-send-first and client-send-last
+ issues (using mechanism feature flags)
+
+2001-07-18 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * Updated config.guess and config.sub
+ * Better underscore checking for dlsym
+ * Resolved possible global_utils namespace collision
+ * Updated sasldb library to be expandable to multiple properties
+ if the need arises in the future.
+ * IPv6 support from Hajimu UMEMOTO <ume@mahoroba.org>
+
+2001-07-17 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * Extricated sasldb support to an auxprop plugin only.
+ sasldb modifications can now only be done through the saslpasswd
+ interface.
+
+2001-07-13 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * Fixed buffer overrun problem in sasldb auxprop plugin
+ * Removed severe memory leak from testsuite
+ * Version 2.0.2-ALPHA Released
+
+2001-07-11 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * error reporting in KERBEROS_V4 plugin
+ * vague handling of SASL_AUTHSOURCE for getprop
+ * random misc error reporting bugs
+ * basic error messages for GSSAPI plugin
+
+2001-07-10 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * added client-send-first logic in glue code
+ * removed some client-send-first logic in mechanisms
+ * removed IPv4 specifics from sasl_conn_t
+ * Much gluecode error revamping (store the error code
+ in sasl_conn_t)
+
+2001-07-09 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * Removed dependency on "name" in canonuser plugin structure
+ * Update configure.in from a new configure.scan
+ * Update copyright info in man pages, finished all API man pages
+ * Added auxprop tests to testsuite
+ * Added userdb callback support
+
+2001-07-09 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * First attempt at making the java code work again
+ * Minor memory and byte order bugfixes
+ * Added testing support for dmalloc (--with-dmalloc)
+
+2001-07-06 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * Loading of auxprop and canonuser plugins from DSOs
+ (This still sucks performance wise, and will be fixed soon)
+ * Fixed some lack of indirection in the plugins
+ * Reverted to the v1 entry points for the plugins
+ * Cleaned up a good deal of the library loading code so it
+ now only gets called from the sasl_*_init functions, and
+ all the cleanup happens in the common sasl_done function
+ * Added SASL_IPREMOTEPORT and SASL_IPLOCALPORT to setprop,
+ and now _sasl_conn_init calls it to do the same work.
+
+2001-07-05 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * Working libsfsasl and smtptest program (--with-sfio)
+ * Fixed sasldblistusers (atleast for Berkeley DB)
+ * seterror() calls in ANONYMOUS, CRAM, PLAIN and LOGIN
+ * Some new manpages
+
+2001-07-03 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * Static library compilation now optional (--with-staticsasl)
+ Note that this is different from --enable-static, which causes
+ libtool to build static versions of everything is is almost
+ certainly NOT what you want.
+ * Removed all references to the ancient NANA code.
+ * Updated some documentation.
+
+2001-07-02 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * Improved allocation efficiency of KERBEROS_V4, DIGEST-MD5,
+ and GSSAPI security layers.
+ * Fixed a decode bug in DIGEST-MD5 (and testsuite improvements to
+ help find similar ones)
+ * Fixed a number of solaris compiler warnings
+ * Static Library Build Support
+
+2001-06-30 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * Cleanup of some man pages (added sasl_errors.3)
+
+2001-06-29 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * Cleanup of APOP Code + new man page (Ken Murchison <ken@oceana.com>)
+ * Cleanup of comments in some files (Ken Murchison <ken@oceana.com>)
+ * Fixed some compiler errors on Solaris using /opt/SUNWspro/bin/cc
+ (Reported by Mei-Hui Su <mei@ISI.EDU>
+
+2001-06-28 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * Improved memory allocation in default sasl_decode handler
+ * Added ability to disable sasl_checkapop (--disable-checkapop)
+ * Re-initialized kerberos mutex to NULL after it was freed
+
+2001-06-28 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * Fixed a severe bug in DIGEST-MD5 Plugin
+ * KERBEROS_V4 plugin now thread safe
+ * Version 2.0.1-ALPHA Released (due to DIGEST-MD5 problem)
+
+2001-06-27 Rob Siemborski <rjs3+@andrew.cmu.edu>
+ * Version 2.0.0-ALPHA Released
diff --git a/contrib/libs/sasl/INSTALL.TXT b/contrib/libs/sasl/INSTALL.TXT
new file mode 100644
index 0000000000..703ff08e4c
--- /dev/null
+++ b/contrib/libs/sasl/INSTALL.TXT
@@ -0,0 +1 @@
+For installation instructions, see doc/legacy/install.html.
diff --git a/contrib/libs/sasl/README b/contrib/libs/sasl/README
new file mode 100644
index 0000000000..b2e1dcc13b
--- /dev/null
+++ b/contrib/libs/sasl/README
@@ -0,0 +1 @@
+Look at README.md
diff --git a/contrib/libs/sasl/README.GS2 b/contrib/libs/sasl/README.GS2
new file mode 100644
index 0000000000..973cee883e
--- /dev/null
+++ b/contrib/libs/sasl/README.GS2
@@ -0,0 +1,3 @@
+To build the GS2 SASL mechanism, you need MIT Kerberos 1.9.
+
+Please e-mail lukeh@padl.com with any bug reports.
diff --git a/contrib/libs/sasl/README.ldapdb b/contrib/libs/sasl/README.ldapdb
new file mode 100644
index 0000000000..d632af3152
--- /dev/null
+++ b/contrib/libs/sasl/README.ldapdb
@@ -0,0 +1,53 @@
+ldapdb auxprop plugin is contributed to cyrus-sasl by the OpenLDAP Project
+(http://www.openldap.org) under the license below. The code is written by
+Howard Chu (hyc@openldap.org) and it is integrated to the cyrus-sasl
+distribution by Igor Brezac (igor@ypass.net). See doc/options.html for the
+plugin documentation.
+
+The OpenLDAP Public License
+ Version 2.8, 17 August 2003
+
+Redistribution and use of this software and associated documentation
+("Software"), with or without modification, are permitted provided
+that the following conditions are met:
+
+1. Redistributions in source form must retain copyright statements
+ and notices,
+
+2. Redistributions in binary form must reproduce applicable copyright
+ statements and notices, this list of conditions, and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution, and
+
+3. Redistributions must contain a verbatim copy of this document.
+
+The OpenLDAP Foundation may revise this license from time to time.
+Each revision is distinguished by a version number. You may use
+this Software under terms of this license revision or under the
+terms of any subsequent revision of the license.
+
+THIS SOFTWARE IS PROVIDED BY THE OPENLDAP FOUNDATION AND ITS
+CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+SHALL THE OPENLDAP FOUNDATION, ITS CONTRIBUTORS, OR THE AUTHOR(S)
+OR OWNER(S) OF THE SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+The names of the authors and copyright holders must not be used in
+advertising or otherwise to promote the sale, use or other dealing
+in this Software without specific, written prior permission. Title
+to copyright in this Software shall at all times remain with copyright
+holders.
+
+OpenLDAP is a registered trademark of the OpenLDAP Foundation.
+
+Copyright 1999-2003 The OpenLDAP Foundation, Redwood City,
+California, USA. All Rights Reserved. Permission to copy and
+distribute verbatim copies of this document is granted.
diff --git a/contrib/libs/sasl/README.md b/contrib/libs/sasl/README.md
new file mode 100644
index 0000000000..9953921943
--- /dev/null
+++ b/contrib/libs/sasl/README.md
@@ -0,0 +1,27 @@
+[![Build Status:master](https://api.travis-ci.org/cyrusimap/cyrus-sasl.svg?branch=master)](https://travis-ci.org/cyrusimap/cyrus-sasl)
+
+
+## Cyrus SASL
+This is the Cyrus SASL API implementation. It can be used on the client
+or server side to provide authentication and authorization services.
+See RFC 4422 for more information.
+
+The latest version is available at:
+https://github.com/cyrusimap/cyrus-sasl/releases
+
+There's a mailing list for Cyrus SASL. Subscribe by sending a message
+to majordomo@lists.andrew.cmu.edu with the body "subscribe
+cyrus-sasl". The mailing list is available via anonymous IMAP at
+imap://cyrus.andrew.cmu.edu/archive.cyrus-sasl or via the web at
+https://lists.andrew.cmu.edu/pipermail/cyrus-sasl/.
+
+If you are looking to port SASLv1 applications to SASLv2, please see
+doc/appconvert.html
+
+Bugs can be searched/reported [on GitHub](https://github.com/cyrusimap/cyrus-sasl/issues),
+but please also notify the mailing list.
+
+## DOCUMENTATION
+
+Please see doc/legacy/index.html for detailed documentation.
+
diff --git a/contrib/libs/sasl/README.release b/contrib/libs/sasl/README.release
new file mode 100644
index 0000000000..55720b7277
--- /dev/null
+++ b/contrib/libs/sasl/README.release
@@ -0,0 +1,89 @@
+* Ensure version is incremented in:
+ configure.ac
+ docsrc/conf.py
+ include/sasl.h
+ win32/common.mak
+ win32/include/config.h
+
+* Add release notes to
+ docsrc/sasl/release-notes/2.1/index.rst
+
+* NOCONFIGURE=yes ./autogen.sh
+ to generate configure etc
+
+* MUST build with one of the supported database backends:
+ bdb gdbm lmdb ndbm
+ It is recommended to use lmdb
+
+Generally using Debian or Ubuntu distributions for the compile steps is useful
+as they provide both MIT and Heimdal development packages:
+
+ NOTE: Sphinx version 4.4.0 or later is required. It may be mandatory to install
+ it manually via python3-pip:
+ pip install -U Sphinx
+ OR
+ apt install sphinx-common (Documentation)
+
+ Other dependencies:
+ apt install libpod-pom-view-restructured-perl (Documentation)
+ apt install liblmdb-dev (LMDB backend)
+ apt install libkrb5-dev (MIT Kerberos)
+ apt install heimdal-dev (Heimdal Kerberos)
+
+* Confirm build compiles with no kerberos support
+ ./configure --with-dblib=lmdb
+ make
+
+* Confirm build compiles with MIT kerberos support
+ LDFLAGS="-L/usr/lib/x86_64-linux-gnu/mit-krb5/" CPPFLAGS="-I/usr/include/mit-krb5" ./configure --with-dblib=lmdb
+ make
+
+* Confirm build compiles with Heimdal kerberos support
+ LDFLAGS="-L/usr/lib/x86_64-linux-gnu/heimdal/" CPPFLAGS="-I/usr/include/heimdal" ./configure --with-dblib=lmdb
+ make
+
+* If possible, build on a non-Linux OS such as FreeBSD
+ NOTE: Currently FreeBSD has ndbm installed as an alternative
+ to test with rather than LMDB
+ pkg install openssl
+ pkg install heimdal
+
+* git tag the repository:
+ git tag -a -s cyrus-sasl-MAJOR.MINOR.PATCH
+
+ We are pleased to announce the release of Cyrus SASL version MAJOR.MINOR.PATCH.
+
+ This release contains features and fixes you can find on the following pages:
+
+ https://www.cyrusimap.org/sasl/sasl/release-notes/2.1/index.html#new-in-MAJOR-MINOR-PATCH
+
+* check out the tag:
+ git checkout cyrus-sasl-MAJOR.MINOR.PATCH
+
+* make distcheck
+ Generates the tarball etc
+
+* Post release announcement to announce@cyrus.topicbox.com
+
+ Example:
+
+ The Cyrus team is proud to announce the immediate availability of a new version of Cyrus SASL: MAJOR.MINOR.PATCH
+
+ <INSERT HIGHLIGHTS OF THE RELEASE>
+
+ Of course, please check the release notes for the full list of changes.
+
+ Release notes:
+
+ https://www.cyrusimap.org/sasl/sasl/release-notes/2.1/index.html#new-in-MAJOR-MINOR-PATCH
+
+ Download URLs:
+
+ https://github.com/cyrusimap/cyrus-sasl/releases/download/cyrus-sasl-MAJOR.MINOR.PATCH/cyrus-sasl-MAJOR.MINOR.PATCH.tar.gz
+ https://github.com/cyrusimap/cyrus-sasl/releases/download/cyrus-sasl-MAJOR.MINOR.PATCH/cyrus-sasl-MAJOR.MINOR.PATCH.tar.gz.sig
+
+ On behalf of the Cyrus team,
+
+ Kind regards,
+
+ YOUR NAME HERE
diff --git a/contrib/libs/sasl/common/plugin_common.c b/contrib/libs/sasl/common/plugin_common.c
new file mode 100644
index 0000000000..94d4479245
--- /dev/null
+++ b/contrib/libs/sasl/common/plugin_common.c
@@ -0,0 +1,920 @@
+/* Generic SASL plugin utility functions
+ * Rob Siemborski
+ */
+/*
+ * Copyright (c) 1998-2016 Carnegie Mellon University. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For permission or any other legal
+ * details, please contact
+ * Carnegie Mellon University
+ * Center for Technology Transfer and Enterprise Creation
+ * 4615 Forbes Avenue
+ * Suite 302
+ * Pittsburgh, PA 15213
+ * (412) 268-7393, fax: (412) 268-7395
+ * innovation@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Computing Services
+ * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+#ifndef macintosh
+#ifdef WIN32
+# include <winsock2.h>
+# include <versionhelpers.h>
+#else
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
+# include <netdb.h>
+# include <sys/utsname.h>
+#endif /* WIN32 */
+#endif /* macintosh */
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <sasl.h>
+#include <saslutil.h>
+#include <saslplug.h>
+
+#include <errno.h>
+#include <ctype.h>
+#include <stdio.h>
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+#include "plugin_common.h"
+
+/* translate IPv4 mapped IPv6 address to IPv4 address */
+static void sockaddr_unmapped(
+#ifdef IN6_IS_ADDR_V4MAPPED
+ struct sockaddr *sa, socklen_t *len
+#else
+ struct sockaddr *sa __attribute__((unused)),
+ socklen_t *len __attribute__((unused))
+#endif
+)
+{
+#ifdef IN6_IS_ADDR_V4MAPPED
+ struct sockaddr_in6 *sin6;
+ struct sockaddr_in *sin4;
+ uint32_t addr;
+ int port;
+
+ if (sa->sa_family != AF_INET6)
+ return;
+ sin6 = (struct sockaddr_in6 *)sa;
+ if (!IN6_IS_ADDR_V4MAPPED((&sin6->sin6_addr)))
+ return;
+ sin4 = (struct sockaddr_in *)sa;
+#ifdef s6_addr32
+ addr = *(uint32_t *)&sin6->sin6_addr.s6_addr32[3];
+#else
+ memcpy(&addr, &sin6->sin6_addr.s6_addr[12], 4);
+#endif
+ port = sin6->sin6_port;
+ memset(sin4, 0, sizeof(struct sockaddr_in));
+ sin4->sin_addr.s_addr = addr;
+ sin4->sin_port = port;
+ sin4->sin_family = AF_INET;
+#ifdef HAVE_SOCKADDR_SA_LEN
+ sin4->sin_len = sizeof(struct sockaddr_in);
+#endif
+ *len = sizeof(struct sockaddr_in);
+#else
+ return;
+#endif
+}
+
+int _plug_ipfromstring(const sasl_utils_t *utils, const char *addr,
+ struct sockaddr *out, socklen_t outlen)
+{
+ int i, j;
+ socklen_t len;
+ struct sockaddr_storage ss;
+ struct addrinfo hints, *ai = NULL;
+ char hbuf[NI_MAXHOST];
+
+ if(!utils || !addr || !out) {
+ if(utils) PARAMERROR( utils );
+ return SASL_BADPARAM;
+ }
+
+ /* Parse the address */
+ for (i = 0; addr[i] != '\0' && addr[i] != ';'; i++) {
+ if (i + 1 >= NI_MAXHOST) {
+ if(utils) PARAMERROR( utils );
+ return SASL_BADPARAM;
+ }
+ hbuf[i] = addr[i];
+ }
+ hbuf[i] = '\0';
+
+ if (addr[i] == ';')
+ i++;
+ /* XXX/FIXME: Do we need this check? */
+ for (j = i; addr[j] != '\0'; j++)
+ if (!isdigit((int)(addr[j]))) {
+ PARAMERROR( utils );
+ return SASL_BADPARAM;
+ }
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
+
+ if (getaddrinfo(hbuf, &addr[i], &hints, &ai) != 0) {
+ PARAMERROR( utils );
+ return SASL_BADPARAM;
+ }
+
+ len = (socklen_t) ai->ai_addrlen;
+ memcpy(&ss, ai->ai_addr, len);
+ freeaddrinfo(ai);
+ sockaddr_unmapped((struct sockaddr *)&ss, &len);
+ if (outlen < len) {
+ PARAMERROR( utils );
+ return SASL_BUFOVER;
+ }
+
+ memcpy(out, &ss, len);
+
+ return SASL_OK;
+}
+
+int _plug_iovec_to_buf(const sasl_utils_t *utils, const struct iovec *vec,
+ unsigned numiov, buffer_info_t **output)
+{
+ unsigned i;
+ int ret;
+ buffer_info_t *out;
+ char *pos;
+
+ if(!utils || !vec || !output) {
+ if(utils) PARAMERROR( utils );
+ return SASL_BADPARAM;
+ }
+
+ if(!(*output)) {
+ *output = utils->malloc(sizeof(buffer_info_t));
+ if(!*output) {
+ MEMERROR(utils);
+ return SASL_NOMEM;
+ }
+ memset(*output,0,sizeof(buffer_info_t));
+ }
+
+ out = *output;
+
+ out->curlen = 0;
+ for(i=0; i<numiov; i++)
+ out->curlen += vec[i].iov_len;
+
+ ret = _plug_buf_alloc(utils, &out->data, &out->reallen, out->curlen);
+
+ if(ret != SASL_OK) {
+ MEMERROR(utils);
+ return SASL_NOMEM;
+ }
+
+ memset(out->data, 0, out->reallen);
+ pos = out->data;
+
+ for(i=0; i<numiov; i++) {
+ memcpy(pos, vec[i].iov_base, vec[i].iov_len);
+ pos += vec[i].iov_len;
+ }
+
+ return SASL_OK;
+}
+
+/* Basically a conditional call to realloc(), if we need more */
+int _plug_buf_alloc(const sasl_utils_t *utils, char **rwbuf,
+ unsigned *curlen, unsigned newlen)
+{
+ if(!utils || !rwbuf || !curlen) {
+ if (utils) PARAMERROR(utils);
+ return SASL_BADPARAM;
+ }
+
+ if(!(*rwbuf)) {
+ *rwbuf = utils->malloc(newlen);
+ if (*rwbuf == NULL) {
+ *curlen = 0;
+ MEMERROR(utils);
+ return SASL_NOMEM;
+ }
+ *curlen = newlen;
+ } else if(*rwbuf && *curlen < newlen) {
+ unsigned needed = 2*(*curlen);
+
+ while(needed < newlen)
+ needed *= 2;
+
+ *rwbuf = utils->realloc(*rwbuf, needed);
+ if (*rwbuf == NULL) {
+ *curlen = 0;
+ MEMERROR(utils);
+ return SASL_NOMEM;
+ }
+ *curlen = needed;
+ }
+
+ return SASL_OK;
+}
+
+/* copy a string */
+int _plug_strdup(const sasl_utils_t * utils, const char *in,
+ char **out, int *outlen)
+{
+ size_t len = 0;
+
+ if(!utils || !in || !out) {
+ if(utils) PARAMERROR(utils);
+ return SASL_BADPARAM;
+ }
+
+ len = strlen(in);
+
+ *out = utils->malloc(len + 1);
+ if (!*out) {
+ MEMERROR(utils);
+ return SASL_NOMEM;
+ }
+
+ strcpy((char *) *out, in);
+
+ if (outlen)
+ *outlen = (int) len;
+
+ return SASL_OK;
+}
+
+void _plug_free_string(const sasl_utils_t *utils, char **str)
+{
+ size_t len;
+
+ if (!utils || !str || !(*str)) return;
+
+ len = strlen(*str);
+
+ utils->erasebuffer(*str, (unsigned int) len);
+ utils->free(*str);
+
+ *str=NULL;
+}
+
+void _plug_free_secret(const sasl_utils_t *utils, sasl_secret_t **secret)
+{
+ if(!utils || !secret || !(*secret)) return;
+
+ utils->erasebuffer((char *)(*secret)->data, (*secret)->len);
+ utils->free(*secret);
+ *secret = NULL;
+}
+
+/*
+ * Trys to find the prompt with the lookingfor id in the prompt list
+ * Returns it if found. NULL otherwise
+ */
+sasl_interact_t *_plug_find_prompt(sasl_interact_t **promptlist,
+ unsigned int lookingfor)
+{
+ sasl_interact_t *prompt;
+
+ if (promptlist && *promptlist) {
+ for (prompt = *promptlist; prompt->id != SASL_CB_LIST_END; ++prompt) {
+ if (prompt->id==lookingfor)
+ return prompt;
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * Retrieve the simple string given by the callback id.
+ */
+int _plug_get_simple(const sasl_utils_t *utils, unsigned int id, int required,
+ const char **result, sasl_interact_t **prompt_need)
+{
+
+ int ret = SASL_FAIL;
+ sasl_getsimple_t *simple_cb;
+ void *simple_context;
+ sasl_interact_t *prompt;
+
+ *result = NULL;
+
+ /* see if we were given the result in the prompt */
+ prompt = _plug_find_prompt(prompt_need, id);
+ if (prompt != NULL) {
+ /* We prompted, and got.*/
+
+ if (required && !prompt->result) {
+ SETERROR(utils, "Unexpectedly missing a prompt result in _plug_get_simple");
+ return SASL_BADPARAM;
+ }
+
+ *result = prompt->result;
+ return SASL_OK;
+ }
+
+ /* Try to get the callback... */
+ ret = utils->getcallback(utils->conn, id, (sasl_callback_ft *)&simple_cb, &simple_context);
+
+ if (ret == SASL_FAIL && !required)
+ return SASL_OK;
+
+ if (ret == SASL_OK && simple_cb) {
+ ret = simple_cb(simple_context, id, result, NULL);
+ if (ret != SASL_OK)
+ return ret;
+
+ if (required && !*result) {
+ PARAMERROR(utils);
+ return SASL_BADPARAM;
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * Retrieve the user password.
+ */
+int _plug_get_password(const sasl_utils_t *utils, sasl_secret_t **password,
+ unsigned int *iscopy, sasl_interact_t **prompt_need)
+{
+ int ret = SASL_FAIL;
+ sasl_getsecret_t *pass_cb;
+ void *pass_context;
+ sasl_interact_t *prompt;
+
+ *password = NULL;
+ *iscopy = 0;
+
+ /* see if we were given the password in the prompt */
+ prompt = _plug_find_prompt(prompt_need, SASL_CB_PASS);
+ if (prompt != NULL) {
+ /* We prompted, and got.*/
+
+ if (!prompt->result) {
+ SETERROR(utils, "Unexpectedly missing a prompt result in _plug_get_password");
+ return SASL_BADPARAM;
+ }
+
+ /* copy what we got into a secret_t */
+ *password = (sasl_secret_t *) utils->malloc(sizeof(sasl_secret_t) +
+ prompt->len + 1);
+ if (!*password) {
+ MEMERROR(utils);
+ return SASL_NOMEM;
+ }
+
+ (*password)->len=prompt->len;
+ memcpy((*password)->data, prompt->result, prompt->len);
+ (*password)->data[(*password)->len]=0;
+
+ *iscopy = 1;
+
+ return SASL_OK;
+ }
+
+ /* Try to get the callback... */
+ ret = utils->getcallback(utils->conn, SASL_CB_PASS,
+ (sasl_callback_ft *)&pass_cb, &pass_context);
+
+ if (ret == SASL_OK && pass_cb) {
+ ret = pass_cb(utils->conn, pass_context, SASL_CB_PASS, password);
+ if (ret != SASL_OK)
+ return ret;
+
+ if (!*password) {
+ PARAMERROR(utils);
+ return SASL_BADPARAM;
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * Retrieve the string given by the challenge prompt id.
+ */
+int _plug_challenge_prompt(const sasl_utils_t *utils, unsigned int id,
+ const char *challenge, const char *promptstr,
+ const char **result, sasl_interact_t **prompt_need)
+{
+ int ret = SASL_FAIL;
+ sasl_chalprompt_t *chalprompt_cb;
+ void *chalprompt_context;
+ sasl_interact_t *prompt;
+
+ *result = NULL;
+
+ /* see if we were given the password in the prompt */
+ prompt = _plug_find_prompt(prompt_need, id);
+ if (prompt != NULL) {
+ /* We prompted, and got.*/
+
+ if (!prompt->result) {
+ SETERROR(utils, "Unexpectedly missing a prompt result in _plug_challenge_prompt");
+ return SASL_BADPARAM;
+ }
+
+ *result = prompt->result;
+ return SASL_OK;
+ }
+
+ /* Try to get the callback... */
+ ret = utils->getcallback(utils->conn, id,
+ (sasl_callback_ft *)&chalprompt_cb, &chalprompt_context);
+
+ if (ret == SASL_OK && chalprompt_cb) {
+ ret = chalprompt_cb(chalprompt_context, id,
+ challenge, promptstr, NULL, result, NULL);
+ if (ret != SASL_OK)
+ return ret;
+
+ if (!*result) {
+ PARAMERROR(utils);
+ return SASL_BADPARAM;
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * Retrieve the client realm.
+ */
+int _plug_get_realm(const sasl_utils_t *utils, const char **availrealms,
+ const char **realm, sasl_interact_t **prompt_need)
+{
+ int ret = SASL_FAIL;
+ sasl_getrealm_t *realm_cb;
+ void *realm_context;
+ sasl_interact_t *prompt;
+
+ *realm = NULL;
+
+ /* see if we were given the result in the prompt */
+ prompt = _plug_find_prompt(prompt_need, SASL_CB_GETREALM);
+ if (prompt != NULL) {
+ /* We prompted, and got.*/
+
+ if (!prompt->result) {
+ SETERROR(utils, "Unexpectedly missing a prompt result in _plug_get_realm");
+ return SASL_BADPARAM;
+ }
+
+ *realm = prompt->result;
+ return SASL_OK;
+ }
+
+ /* Try to get the callback... */
+ ret = utils->getcallback(utils->conn, SASL_CB_GETREALM,
+ (sasl_callback_ft *)&realm_cb, &realm_context);
+
+ if (ret == SASL_OK && realm_cb) {
+ ret = realm_cb(realm_context, SASL_CB_GETREALM, availrealms, realm);
+ if (ret != SASL_OK)
+ return ret;
+
+ if (!*realm) {
+ PARAMERROR(utils);
+ return SASL_BADPARAM;
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * Make the requested prompts. (prompt==NULL means we don't want it)
+ */
+int _plug_make_prompts(const sasl_utils_t *utils,
+ sasl_interact_t **prompts_res,
+ const char *user_prompt, const char *user_def,
+ const char *auth_prompt, const char *auth_def,
+ const char *pass_prompt, const char *pass_def,
+ const char *echo_chal,
+ const char *echo_prompt, const char *echo_def,
+ const char *realm_chal,
+ const char *realm_prompt, const char *realm_def)
+{
+ int num = 1;
+ int alloc_size;
+ sasl_interact_t *prompts;
+
+ if (user_prompt) num++;
+ if (auth_prompt) num++;
+ if (pass_prompt) num++;
+ if (echo_prompt) num++;
+ if (realm_prompt) num++;
+
+ if (num == 1) {
+ SETERROR( utils, "make_prompts() called with no actual prompts" );
+ return SASL_FAIL;
+ }
+
+ alloc_size = sizeof(sasl_interact_t)*num;
+ prompts = utils->malloc(alloc_size);
+ if (!prompts) {
+ MEMERROR( utils );
+ return SASL_NOMEM;
+ }
+ memset(prompts, 0, alloc_size);
+
+ *prompts_res = prompts;
+
+ if (user_prompt) {
+ (prompts)->id = SASL_CB_USER;
+ (prompts)->challenge = "Authorization Name";
+ (prompts)->prompt = user_prompt;
+ (prompts)->defresult = user_def;
+
+ prompts++;
+ }
+
+ if (auth_prompt) {
+ (prompts)->id = SASL_CB_AUTHNAME;
+ (prompts)->challenge = "Authentication Name";
+ (prompts)->prompt = auth_prompt;
+ (prompts)->defresult = auth_def;
+
+ prompts++;
+ }
+
+ if (pass_prompt) {
+ (prompts)->id = SASL_CB_PASS;
+ (prompts)->challenge = "Password";
+ (prompts)->prompt = pass_prompt;
+ (prompts)->defresult = pass_def;
+
+ prompts++;
+ }
+
+ if (echo_prompt) {
+ (prompts)->id = SASL_CB_ECHOPROMPT;
+ (prompts)->challenge = echo_chal;
+ (prompts)->prompt = echo_prompt;
+ (prompts)->defresult = echo_def;
+
+ prompts++;
+ }
+
+ if (realm_prompt) {
+ (prompts)->id = SASL_CB_GETREALM;
+ (prompts)->challenge = realm_chal;
+ (prompts)->prompt = realm_prompt;
+ (prompts)->defresult = realm_def;
+
+ prompts++;
+ }
+
+ /* add the ending one */
+ (prompts)->id = SASL_CB_LIST_END;
+ (prompts)->challenge = NULL;
+ (prompts)->prompt = NULL;
+ (prompts)->defresult = NULL;
+
+ return SASL_OK;
+}
+
+void _plug_decode_init(decode_context_t *text,
+ const sasl_utils_t *utils, unsigned int in_maxbuf)
+{
+ memset(text, 0, sizeof(decode_context_t));
+
+ text->utils = utils;
+ text->needsize = 4;
+ text->in_maxbuf = in_maxbuf;
+}
+
+/*
+ * Decode as much of the input as possible (possibly none),
+ * using decode_pkt() to decode individual packets.
+ */
+int _plug_decode(decode_context_t *text,
+ const char *input, unsigned inputlen,
+ char **output, /* output buffer */
+ unsigned *outputsize, /* current size of output buffer */
+ unsigned *outputlen, /* length of data in output buffer */
+ int (*decode_pkt)(void *rock,
+ const char *input, unsigned inputlen,
+ char **output, unsigned *outputlen),
+ void *rock)
+{
+ unsigned int tocopy;
+ unsigned diff;
+ char *tmp;
+ unsigned tmplen;
+ int ret;
+
+ *outputlen = 0;
+
+ while (inputlen) { /* more input */
+ if (text->needsize) { /* need to get the rest of the 4-byte size */
+
+ /* copy as many bytes (up to 4) as we have into size buffer */
+ tocopy = (inputlen > text->needsize) ? text->needsize : inputlen;
+ memcpy(text->sizebuf + 4 - text->needsize, input, tocopy);
+ text->needsize -= tocopy;
+
+ input += tocopy;
+ inputlen -= tocopy;
+
+ if (!text->needsize) { /* we have the entire 4-byte size */
+ memcpy(&(text->size), text->sizebuf, 4);
+ text->size = ntohl(text->size);
+ text->cursize = 0;
+ } else {
+ /* We do NOT have the entire 4-byte size...
+ * wait for more data */
+ return SASL_OK;
+ }
+ }
+
+ if (!text->size) /* should never happen */
+ return SASL_FAIL;
+
+ if (text->size > text->in_maxbuf) {
+ text->utils->log(NULL, SASL_LOG_ERR,
+ "encoded packet size too big (%d > %d)",
+ text->size, text->in_maxbuf);
+ return SASL_FAIL;
+ }
+
+ if (!text->buffer) {
+ text->buffer = text->utils->malloc(text->in_maxbuf);
+ if (text->buffer == NULL) return SASL_NOMEM;
+ }
+
+ diff = text->size - text->cursize; /* bytes needed for full packet */
+
+ if (inputlen < diff) { /* not a complete packet, need more input */
+ memcpy(text->buffer + text->cursize, input, inputlen);
+ text->cursize += inputlen;
+ return SASL_OK;
+ }
+
+ /* copy the rest of the packet */
+ memcpy(text->buffer + text->cursize, input, diff);
+ input += diff;
+ inputlen -= diff;
+
+ /* decode the packet (no need to free tmp) */
+ ret = decode_pkt(rock, text->buffer, text->size, &tmp, &tmplen);
+ if (ret != SASL_OK) return ret;
+
+ /* append the decoded packet to the output */
+ ret = _plug_buf_alloc(text->utils, output, outputsize,
+ *outputlen + tmplen + 1); /* +1 for NUL */
+ if (ret != SASL_OK) return ret;
+
+ memcpy(*output + *outputlen, tmp, tmplen);
+ *outputlen += tmplen;
+
+ /* protect stupid clients */
+ *(*output + *outputlen) = '\0';
+
+ /* reset for the next packet */
+ text->needsize = 4;
+ }
+
+ return SASL_OK;
+}
+
+void _plug_decode_free(decode_context_t *text)
+{
+ if (text->buffer) text->utils->free(text->buffer);
+}
+
+/* returns the realm we should pretend to be in */
+int _plug_parseuser(const sasl_utils_t *utils,
+ char **user, char **realm, const char *user_realm,
+ const char *serverFQDN, const char *input)
+{
+ int ret;
+ char *r;
+
+ if(!user || !serverFQDN) {
+ PARAMERROR( utils );
+ return SASL_BADPARAM;
+ }
+
+ r = strchr(input, '@');
+ if (!r) {
+ /* hmmm, the user didn't specify a realm */
+ if(user_realm && user_realm[0]) {
+ ret = _plug_strdup(utils, user_realm, realm, NULL);
+ } else {
+ /* Default to serverFQDN */
+ ret = _plug_strdup(utils, serverFQDN, realm, NULL);
+ }
+
+ if (ret == SASL_OK) {
+ ret = _plug_strdup(utils, input, user, NULL);
+ }
+ } else {
+ r++;
+ ret = _plug_strdup(utils, r, realm, NULL);
+ *--r = '\0';
+ *user = utils->malloc(r - input + 1);
+ if (*user) {
+ strncpy(*user, input, r - input +1);
+ } else {
+ MEMERROR( utils );
+ ret = SASL_NOMEM;
+ }
+ *r = '@';
+ }
+
+ return ret;
+}
+
+int _plug_make_fulluser(const sasl_utils_t *utils,
+ char **fulluser,
+ const char * useronly,
+ const char *realm)
+{
+ if(!fulluser || !useronly || !realm) {
+ PARAMERROR( utils );
+ return (SASL_BADPARAM);
+ }
+
+ *fulluser = utils->malloc (strlen(useronly) + strlen(realm) + 2);
+ if (*fulluser == NULL) {
+ MEMERROR( utils );
+ return (SASL_NOMEM);
+ }
+
+ strcpy (*fulluser, useronly);
+ strcat (*fulluser, "@");
+ strcat (*fulluser, realm);
+
+ return (SASL_OK);
+}
+
+char * _plug_get_error_message (const sasl_utils_t *utils,
+#ifdef WIN32
+ DWORD error
+#else
+ int error
+#endif
+ )
+{
+ char * return_value;
+#ifdef WIN32
+ LPVOID lpMsgBuf;
+
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ error,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
+ (LPTSTR) &lpMsgBuf,
+ 0,
+ NULL
+ );
+
+ if (_plug_strdup (utils, lpMsgBuf, &return_value, NULL) != SASL_OK) {
+ return_value = NULL;
+ }
+
+ LocalFree( lpMsgBuf );
+#else /* !WIN32 */
+ if (_plug_strdup (utils, strerror(error), &return_value, NULL) != SASL_OK) {
+ return_value = NULL;
+ }
+#endif /* WIN32 */
+ return (return_value);
+}
+
+void _plug_snprintf_os_info (char * osbuf, int osbuf_len)
+{
+#ifdef WIN32
+ char *sysname;
+ sysname = "Unknown Windows";
+
+/* Let's suppose it's still compilable with win2k sdk. So define everythig missing */
+#ifndef _WIN32_WINNT_WINXP
+# define _WIN32_WINNT_WINXP 0x0501
+#endif
+#ifndef _WIN32_WINNT_WS03
+# define _WIN32_WINNT_WS03 0x0502
+#endif
+#ifndef _WIN32_WINNT_WIN6
+# define _WIN32_WINNT_WIN6 0x0600
+#endif
+#ifndef _WIN32_WINNT_VISTA
+# define _WIN32_WINNT_VISTA 0x0600
+#endif
+#ifndef _WIN32_WINNT_WS08
+# define _WIN32_WINNT_WS08 0x0600
+#endif
+#ifndef _WIN32_WINNT_LONGHORN
+# define _WIN32_WINNT_LONGHORN 0x0600
+#endif
+#ifndef _WIN32_WINNT_WIN7
+# define _WIN32_WINNT_WIN7 0x0601
+#endif
+#ifndef _WIN32_WINNT_WIN8
+# define _WIN32_WINNT_WIN8 0x0602
+#endif
+#ifndef _WIN32_WINNT_WINBLUE
+# define _WIN32_WINNT_WINBLUE 0x0603
+#endif
+#ifndef _WIN32_WINNT_WIN10
+# define _WIN32_WINNT_WIN10 0x0A00
+#endif
+
+ /* and use IsWindowsVersionOrGreater instead of convenient wrappers by the same reason */
+ if (IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN10), LOBYTE(_WIN32_WINNT_WIN10), 0)) {
+ sysname = "Windows 10 or greater";
+ } else
+ if (IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINBLUE), LOBYTE(_WIN32_WINNT_WINBLUE), 0)) {
+ sysname = "Windows 8.1";
+ } else
+ if (IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN8), LOBYTE(_WIN32_WINNT_WIN8), 0)) {
+ sysname = "Windows 8";
+ } else
+ if (IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN7), LOBYTE(_WIN32_WINNT_WIN7), 1)) {
+ sysname = "Windows 7 SP1";
+ } else
+ if (IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WIN7), LOBYTE(_WIN32_WINNT_WIN7), 0)) {
+ sysname = "Windows 7";
+ } else
+ if (IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 2)) {
+ sysname = "Windows Vista SP2";
+ } else
+ if (IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 1)) {
+ sysname = "Windows Vista SP1";
+ } else
+ if (IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_VISTA), LOBYTE(_WIN32_WINNT_VISTA), 0)) {
+ sysname = "Windows Vista";
+ } else
+ if (IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 3)) {
+ sysname = "Windows XP SP3";
+ } else
+ if (IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 2)) {
+ sysname = "Windows XP SP2";
+ } else
+ if (IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 1)) {
+ sysname = "Windows XP SP1";
+ } else
+ if (IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINXP), LOBYTE(_WIN32_WINNT_WINXP), 0)) {
+ sysname = "Windows XP";
+ }
+
+ snprintf(osbuf, osbuf_len, "%s", sysname);
+
+#else /* !WIN32 */
+ struct utsname os;
+
+ uname(&os);
+ snprintf(osbuf, osbuf_len, "%s %s", os.sysname, os.release);
+#endif /* WIN32 */
+}
+
+#if defined(WIN32)
+unsigned int plug_sleep (unsigned int seconds)
+{
+ long dwSec = seconds*1000;
+ Sleep (dwSec);
+ return 0;
+}
+#endif
diff --git a/contrib/libs/sasl/common/plugin_common.h b/contrib/libs/sasl/common/plugin_common.h
new file mode 100644
index 0000000000..60f1dcd3a2
--- /dev/null
+++ b/contrib/libs/sasl/common/plugin_common.h
@@ -0,0 +1,230 @@
+
+/* Generic SASL plugin utility functions
+ * Rob Siemborski
+ */
+/*
+ * Copyright (c) 1998-2016 Carnegie Mellon University. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For permission or any other legal
+ * details, please contact
+ * Carnegie Mellon University
+ * Center for Technology Transfer and Enterprise Creation
+ * 4615 Forbes Avenue
+ * Suite 302
+ * Pittsburgh, PA 15213
+ * (412) 268-7393, fax: (412) 268-7395
+ * innovation@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Computing Services
+ * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _PLUGIN_COMMON_H_
+#define _PLUGIN_COMMON_H_
+
+#include <config.h>
+
+#ifndef macintosh
+#ifdef WIN32
+# include <winsock2.h>
+#else
+# include <sys/socket.h>
+# include <netinet/in.h>
+# include <arpa/inet.h>
+# include <netdb.h>
+#endif /* WIN32 */
+#endif /* macintosh */
+
+#include <sasl.h>
+#include <saslutil.h>
+#include <saslplug.h>
+
+#ifdef WIN32
+#define PLUG_API __declspec(dllexport)
+#else
+#define PLUG_API extern
+#endif
+
+#define SASL_CLIENT_PLUG_INIT( x ) \
+extern sasl_client_plug_init_t x##_client_plug_init; \
+PLUG_API int sasl_client_plug_init(const sasl_utils_t *utils, \
+ int maxversion, int *out_version, \
+ sasl_client_plug_t **pluglist, \
+ int *plugcount) { \
+ return x##_client_plug_init(utils, maxversion, out_version, \
+ pluglist, plugcount); \
+}
+
+#define SASL_SERVER_PLUG_INIT( x ) \
+extern sasl_server_plug_init_t x##_server_plug_init; \
+PLUG_API int sasl_server_plug_init(const sasl_utils_t *utils, \
+ int maxversion, int *out_version, \
+ sasl_server_plug_t **pluglist, \
+ int *plugcount) { \
+ return x##_server_plug_init(utils, maxversion, out_version, \
+ pluglist, plugcount); \
+}
+
+#define SASL_AUXPROP_PLUG_INIT( x ) \
+extern sasl_auxprop_init_t x##_auxprop_plug_init; \
+PLUG_API int sasl_auxprop_plug_init(const sasl_utils_t *utils, \
+ int maxversion, int *out_version, \
+ sasl_auxprop_plug_t **plug, \
+ const char *plugname) {\
+ return x##_auxprop_plug_init(utils, maxversion, out_version, \
+ plug, plugname); \
+}
+
+#define SASL_CANONUSER_PLUG_INIT( x ) \
+extern sasl_canonuser_init_t x##_canonuser_plug_init; \
+PLUG_API int sasl_canonuser_init(const sasl_utils_t *utils, \
+ int maxversion, int *out_version, \
+ sasl_canonuser_plug_t **plug, \
+ const char *plugname) {\
+ return x##_canonuser_plug_init(utils, maxversion, out_version, \
+ plug, plugname); \
+}
+
+/* note: msg cannot include additional variables, so if you want to
+ * do a printf-format string, then you need to call seterror yourself */
+#define SETERROR( utils, msg ) (utils)->seterror( (utils)->conn, 0, (msg) )
+
+#ifndef MEMERROR
+#define MEMERROR( utils ) \
+ (utils)->seterror( (utils)->conn, 0, \
+ "Out of Memory in " __FILE__ " near line %d", __LINE__ )
+#endif
+
+#ifndef PARAMERROR
+#define PARAMERROR( utils ) \
+ (utils)->seterror( (utils)->conn, 0, \
+ "Parameter Error in " __FILE__ " near line %d", __LINE__ )
+#endif
+
+#ifndef SASLINT_H
+typedef struct buffer_info
+{
+ char *data;
+ unsigned curlen; /* Current length of data in buffer */
+ unsigned reallen; /* total length of buffer (>= curlen) */
+} buffer_info_t;
+
+#ifndef HAVE_GETHOSTNAME
+#ifdef sun
+/* gotta define gethostname ourselves on suns */
+extern int gethostname(char *, int);
+#endif
+#endif /* HAVE_GETHOSTNAME */
+
+#endif /* SASLINT_H */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int _plug_ipfromstring(const sasl_utils_t *utils, const char *addr,
+ struct sockaddr *out, socklen_t outlen);
+int _plug_iovec_to_buf(const sasl_utils_t *utils, const struct iovec *vec,
+ unsigned numiov, buffer_info_t **output);
+int _plug_buf_alloc(const sasl_utils_t *utils, char **rwbuf,
+ unsigned *curlen, unsigned newlen);
+int _plug_strdup(const sasl_utils_t * utils, const char *in,
+ char **out, int *outlen);
+void _plug_free_string(const sasl_utils_t *utils, char **str);
+void _plug_free_secret(const sasl_utils_t *utils, sasl_secret_t **secret);
+
+#define _plug_get_userid(utils, result, prompt_need) \
+ _plug_get_simple(utils, SASL_CB_USER, 0, result, prompt_need)
+#define _plug_get_authid(utils, result, prompt_need) \
+ _plug_get_simple(utils, SASL_CB_AUTHNAME, 1, result, prompt_need)
+int _plug_get_simple(const sasl_utils_t *utils, unsigned int id, int required,
+ const char **result, sasl_interact_t **prompt_need);
+
+int _plug_get_password(const sasl_utils_t *utils, sasl_secret_t **secret,
+ unsigned int *iscopy, sasl_interact_t **prompt_need);
+
+int _plug_challenge_prompt(const sasl_utils_t *utils, unsigned int id,
+ const char *challenge, const char *promptstr,
+ const char **result, sasl_interact_t **prompt_need);
+
+int _plug_get_realm(const sasl_utils_t *utils, const char **availrealms,
+ const char **realm, sasl_interact_t **prompt_need);
+
+int _plug_make_prompts(const sasl_utils_t *utils,
+ sasl_interact_t **prompts_res,
+ const char *user_prompt, const char *user_def,
+ const char *auth_prompt, const char *auth_def,
+ const char *pass_prompt, const char *pass_def,
+ const char *echo_chal,
+ const char *echo_prompt, const char *echo_def,
+ const char *realm_chal,
+ const char *realm_prompt, const char *realm_def);
+
+typedef struct decode_context {
+ const sasl_utils_t *utils;
+ unsigned int needsize; /* How much of the 4-byte size do we need? */
+ char sizebuf[4]; /* Buffer to accumulate the 4-byte size */
+ unsigned int size; /* Absolute size of the encoded packet */
+ char *buffer; /* Buffer to accumulate an encoded packet */
+ unsigned int cursize; /* Amount of packet data in the buffer */
+ unsigned int in_maxbuf; /* Maximum allowed size of an incoming encoded packet */
+} decode_context_t;
+
+void _plug_decode_init(decode_context_t *text,
+ const sasl_utils_t *utils, unsigned int in_maxbuf);
+
+int _plug_decode(decode_context_t *text,
+ const char *input, unsigned inputlen,
+ char **output, unsigned *outputsize, unsigned *outputlen,
+ int (*decode_pkt)(void *rock,
+ const char *input, unsigned inputlen,
+ char **output, unsigned *outputlen),
+ void *rock);
+
+void _plug_decode_free(decode_context_t *text);
+
+int _plug_parseuser(const sasl_utils_t *utils,
+ char **user, char **realm, const char *user_realm,
+ const char *serverFQDN, const char *input);
+
+int _plug_make_fulluser(const sasl_utils_t *utils,
+ char **fulluser, const char * useronly, const char *realm);
+
+char * _plug_get_error_message (const sasl_utils_t *utils,
+#ifdef WIN32
+ DWORD error
+#else
+ int error
+#endif
+ );
+void _plug_snprintf_os_info (char * osbuf, int osbuf_len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PLUGIN_COMMON_H_ */
diff --git a/contrib/libs/sasl/config-linux.h b/contrib/libs/sasl/config-linux.h
new file mode 100644
index 0000000000..6528cc867f
--- /dev/null
+++ b/contrib/libs/sasl/config-linux.h
@@ -0,0 +1,782 @@
+/* config.h. Generated from config.h.in by configure. */
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+
+/* acconfig.h - autoheader configuration input */
+/*
+ * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For permission or any other legal
+ * details, please contact
+ * Office of Technology Transfer
+ * Carnegie Mellon University
+ * 5000 Forbes Avenue
+ * Pittsburgh, PA 15213-3890
+ * (412) 268-4387, fax: (412) 268-7395
+ * tech-transfer@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Computing Services
+ * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef CONFIG_H
+#define CONFIG_H
+
+
+/* Include SASLdb Support */
+/* #undef AUTH_SASLDB */
+
+/* Do we need a leading _ for dlsym? */
+/* #undef DLSYM_NEEDS_UNDERSCORE */
+
+/* Should we build a shared plugin (via dlopen) library? */
+/* #undef DO_DLOPEN */
+
+/* should we support sasl_checkapop? */
+#define DO_SASL_CHECKAPOP /**/
+
+/* should we support setpass() for SRP? */
+/* #undef DO_SRP_SETPASS */
+
+/* Define if your getpwnam_r()/getspnam_r() functions take 5 arguments */
+#define GETXXNAM_R_5ARG 1
+
+/* should we mutex-wrap calls into the GSS library? */
+/* #undef GSS_USE_MUTEXES */
+
+/* Enable 'alwaystrue' password verifier? */
+/* #undef HAVE_ALWAYSTRUE */
+
+/* Define to 1 if you have the `asprintf' function. */
+#define HAVE_ASPRINTF 1
+
+/* Include support for Courier's authdaemond? */
+#define HAVE_AUTHDAEMON /**/
+
+/* Define to 1 if you have the <crypt.h> header file. */
+#define HAVE_CRYPT_H 1
+
+/* Define to 1 if you have the <des.h> header file. */
+/* #undef HAVE_DES_H */
+
+/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
+ */
+#define HAVE_DIRENT_H 1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the `dns_lookup' function. */
+/* #undef HAVE_DNS_LOOKUP */
+
+/* Define to 1 if you have the `dn_expand' function. */
+#define HAVE_DN_EXPAND 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Do we have a getaddrinfo? */
+#define HAVE_GETADDRINFO /**/
+
+/* Define to 1 if you have the `getdomainname' function. */
+#define HAVE_GETDOMAINNAME 1
+
+/* Define to 1 if you have the `gethostname' function. */
+#define HAVE_GETHOSTNAME 1
+
+/* Do we have a getnameinfo() function? */
+#define HAVE_GETNAMEINFO /**/
+
+/* Define to 1 if you have the `getpassphrase' function. */
+/* #undef HAVE_GETPASSPHRASE */
+
+/* Define to 1 if you have the `getpwnam' function. */
+#define HAVE_GETPWNAM 1
+
+/* Define to 1 if you have the `getspnam' function. */
+#define HAVE_GETSPNAM 1
+
+/* do we have getsubopt()? */
+#define HAVE_GETSUBOPT /**/
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Include GSSAPI/Kerberos 5 Support */
+/* #undef HAVE_GSSAPI */
+
+/* Define to 1 if you have the <gssapi/gssapi_ext.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_EXT_H */
+
+/* Define if you have the gssapi/gssapi.h header file */
+/* #undef HAVE_GSSAPI_GSSAPI_H */
+
+/* Define to 1 if you have the <gssapi/gssapi_krb5.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_KRB5_H */
+
+/* Define if you have the gssapi.h header file */
+/* #undef HAVE_GSSAPI_H */
+
+/* Define if your GSSAPI implementation defines
+ gsskrb5_register_acceptor_identity */
+/* #undef HAVE_GSSKRB5_REGISTER_ACCEPTOR_IDENTITY */
+
+/* Define if your GSSAPI implementation defines GSS_C_NT_HOSTBASED_SERVICE */
+/* #undef HAVE_GSS_C_NT_HOSTBASED_SERVICE */
+
+/* Define if your GSSAPI implementation defines GSS_C_NT_USER_NAME */
+/* #undef HAVE_GSS_C_NT_USER_NAME */
+
+/* Define if your GSSAPI implementation defines GSS_C_SEC_CONTEXT_SASL_SSF */
+/* #undef HAVE_GSS_C_SEC_CONTEXT_SASL_SSF */
+
+/* Define to 1 if you have the `gss_decapsulate_token' function. */
+/* #undef HAVE_GSS_DECAPSULATE_TOKEN */
+
+/* Define to 1 if you have the `gss_encapsulate_token' function. */
+/* #undef HAVE_GSS_ENCAPSULATE_TOKEN */
+
+/* Define to 1 if you have the `gss_get_name_attribute' function. */
+/* #undef HAVE_GSS_GET_NAME_ATTRIBUTE */
+
+/* Define if your GSSAPI implementation defines gss_inquire_sec_context_by_oid
+ */
+/* #undef HAVE_GSS_INQUIRE_SEC_CONTEXT_BY_OID */
+
+/* Define to 1 if you have the `gss_oid_equal' function. */
+/* #undef HAVE_GSS_OID_EQUAL */
+
+/* Define if your GSSAPI implementation supports SPNEGO */
+/* #undef HAVE_GSS_SPNEGO */
+
+/* Include HTTP form Support */
+/* #undef HAVE_HTTPFORM */
+
+/* Define to 1 if you have the `inet_aton' function. */
+#define HAVE_INET_ATON 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `jrand48' function. */
+#define HAVE_JRAND48 1
+
+/* Do we have Kerberos 4 Support? */
+/* #undef HAVE_KRB */
+
+/* Define to 1 if you have the <krb5.h> header file. */
+/* #undef HAVE_KRB5_H */
+
+/* Define to 1 if you have the `krb_get_err_text' function. */
+/* #undef HAVE_KRB_GET_ERR_TEXT */
+
+/* Define to 1 if you have the <lber.h> header file. */
+/* #undef HAVE_LBER_H */
+
+/* Support for LDAP? */
+/* #undef HAVE_LDAP */
+
+/* Define to 1 if you have the <ldap.h> header file. */
+/* #undef HAVE_LDAP_H */
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+#define HAVE_LIBRESOLV 1
+
+/* Define to 1 if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* Define to 1 if you have the <malloc.h> header file. */
+#define HAVE_MALLOC_H 1
+
+/* Define to 1 if you have the `memcpy' function. */
+#define HAVE_MEMCPY 1
+
+/* Define to 1 if you have the `memmem' function. */
+#define HAVE_MEMMEM 1
+
+/* Define to 1 if you have the <minix/config.h> header file. */
+/* #undef HAVE_MINIX_CONFIG_H */
+
+/* Define to 1 if you have the `mkdir' function. */
+#define HAVE_MKDIR 1
+
+/* Do we have mysql support? */
+/* #undef HAVE_MYSQL */
+
+/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
+/* #undef HAVE_NDIR_H */
+
+/* Do we have OpenSSL? */
+#define HAVE_OPENSSL /**/
+
+/* Use OPIE for server-side OTP? */
+/* #undef HAVE_OPIE */
+
+/* Support for PAM? */
+#define HAVE_PAM /**/
+
+/* Define to 1 if you have the <paths.h> header file. */
+#define HAVE_PATHS_H 1
+
+/* Do we have Postgres support? */
+/* #undef HAVE_PGSQL */
+
+/* Include Support for pwcheck daemon? */
+/* #undef HAVE_PWCHECK */
+
+/* Include support for saslauthd? */
+#define HAVE_SASLAUTHD /**/
+
+/* Define to 1 if you have the `select' function. */
+#define HAVE_SELECT 1
+
+/* Do we have SHA512? */
+#define HAVE_SHA512 /**/
+
+/* Include SIA Support */
+/* #undef HAVE_SIA */
+
+/* Does the system have snprintf()? */
+#define HAVE_SNPRINTF /**/
+
+/* Does sockaddr have an sa_len? */
+/* #undef HAVE_SOCKADDR_SA_LEN */
+
+/* Define to 1 if you have the `socket' function. */
+#define HAVE_SOCKET 1
+
+/* Do we have a socklen_t? */
+#define HAVE_SOCKLEN_T /**/
+
+/* Do we have SQLite support? */
+/* #undef HAVE_SQLITE */
+
+/* Do we have SQLite3 support? */
+/* #undef HAVE_SQLITE3 */
+
+/* Is there an ss_family in sockaddr_storage? */
+#define HAVE_SS_FAMILY /**/
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#define HAVE_STDARG_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdio.h> header file. */
+#define HAVE_STDIO_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the `strchr' function. */
+#define HAVE_STRCHR 1
+
+/* Define to 1 if you have the `strdup' function. */
+#define HAVE_STRDUP 1
+
+/* Define to 1 if you have the `strerror' function. */
+#define HAVE_STRERROR 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcat' function. */
+/* #undef HAVE_STRLCAT */
+
+/* Define to 1 if you have the `strlcpy' function. */
+/* #undef HAVE_STRLCPY */
+
+/* Define to 1 if you have the `strspn' function. */
+#define HAVE_STRSPN 1
+
+/* Define to 1 if you have the `strstr' function. */
+#define HAVE_STRSTR 1
+
+/* Define to 1 if you have the `strtol' function. */
+#define HAVE_STRTOL 1
+
+/* Do we have struct sockaddr_stroage? */
+#define HAVE_STRUCT_SOCKADDR_STORAGE /**/
+
+/* Define to 1 if you have the <sysexits.h> header file. */
+#define HAVE_SYSEXITS_H 1
+
+/* Define to 1 if you have the `syslog' function. */
+#define HAVE_SYSLOG 1
+
+/* Define to 1 if you have the <syslog.h> header file. */
+#define HAVE_SYSLOG_H 1
+
+/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
+ */
+/* #undef HAVE_SYS_DIR_H */
+
+/* Define to 1 if you have the <sys/file.h> header file. */
+#define HAVE_SYS_FILE_H 1
+
+/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
+ */
+/* #undef HAVE_SYS_NDIR_H */
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/uio.h> header file. */
+#define HAVE_SYS_UIO_H 1
+
+/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
+#define HAVE_SYS_WAIT_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the <varargs.h> header file. */
+/* #undef HAVE_VARARGS_H */
+
+/* Does the system have vsnprintf()? */
+#define HAVE_VSNPRINTF /**/
+
+/* Define to 1 if you have the <wchar.h> header file. */
+#define HAVE_WCHAR_H 1
+
+/* Define to 1 if you have the <ws2tcpip.h> header file. */
+/* #undef HAVE_WS2TCPIP_H */
+
+/* Should we keep handle to DB open in SASLDB plugin? */
+/* #undef KEEP_DB_OPEN */
+
+/* Ignore IP Address in Kerberos 4 tickets? */
+/* #undef KRB4_IGNORE_IP_ADDRESS */
+
+/* Using Heimdal */
+/* #undef KRB5_HEIMDAL */
+
+/* Define to the sub-directory where libtool stores uninstalled libraries. */
+#define LT_OBJDIR ".libs/"
+
+/* Name of package */
+#define PACKAGE "cyrus-sasl"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "https://github.com/cyrusimap/cyrus-sasl/issues"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "cyrus-sasl"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "cyrus-sasl 2.1.28"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "cyrus-sasl"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL "https://www.cyrusimap.org"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "2.1.28"
+
+/* Where do we look for Courier authdaemond's socket? */
+#define PATH_AUTHDAEMON_SOCKET "/dev/null"
+
+/* Where do we look for saslauthd's socket? */
+#define PATH_SASLAUTHD_RUNDIR "/run/saslauthd"
+
+/* Force a preferred mechanism */
+/* #undef PREFER_MECH */
+
+/* Location of pwcheck socket */
+/* #undef PWCHECKDIR */
+
+/* Use BerkeleyDB for SASLdb */
+/* #undef SASL_BERKELEYDB */
+
+/* Path to default SASLdb database */
+#define SASL_DB_PATH "/etc/sasldb2"
+
+/* File to use for source of randomness */
+#define SASL_DEV_RANDOM "/dev/urandom"
+
+/* Use GDBM for SASLdb */
+/* #undef SASL_GDBM */
+
+/* Use LMDB for SASLdb */
+/* #undef SASL_LMDB */
+
+/* Use NDBM for SASLdb */
+/* #undef SASL_NDBM */
+
+/* The size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 8
+
+/* Link ANONYMOUS Statically */
+#define STATIC_ANONYMOUS /**/
+
+/* Link CRAM-MD5 Statically */
+#define STATIC_CRAMMD5 /**/
+
+/* Link DIGEST-MD5 Statically */
+#define STATIC_DIGESTMD5 /**/
+
+/* Link GSSAPI Statically */
+/* #undef STATIC_GSSAPIV2 */
+
+/* User KERBEROS_V4 Staticly */
+/* #undef STATIC_KERBEROS4 */
+
+/* Link ldapdb plugin Statically */
+/* #undef STATIC_LDAPDB */
+
+/* Link LOGIN Statically */
+/* #undef STATIC_LOGIN */
+
+/* Link NTLM Statically */
+/* #undef STATIC_NTLM */
+
+/* Link OTP Statically */
+#define STATIC_OTP /**/
+
+/* Link PASSDSS Statically */
+/* #undef STATIC_PASSDSS */
+
+/* Link PLAIN Staticly */
+#define STATIC_PLAIN /**/
+
+/* Link SASLdb Staticly */
+#define STATIC_SASLDB /**/
+
+/* Link SCRAM Statically */
+#define STATIC_SCRAM /**/
+
+/* Link SQL plugin statically */
+/* #undef STATIC_SQL */
+
+/* Link SRP Statically */
+/* #undef STATIC_SRP */
+
+/* Define to 1 if all of the C90 standard headers exist (not just the ones
+ required in a freestanding environment). This macro is provided for
+ backward compatibility; new code need not use it. */
+#define STDC_HEADERS 1
+
+/* Should we try to dlopen() plugins while statically compiled? */
+/* #undef TRY_DLOPEN_WHEN_STATIC */
+
+/* use the doors IPC API for saslauthd? */
+/* #undef USE_DOORS */
+
+/* Enable extensions on AIX 3, Interix. */
+#ifndef _ALL_SOURCE
+# define _ALL_SOURCE 1
+#endif
+/* Enable general extensions on macOS. */
+#ifndef _DARWIN_C_SOURCE
+# define _DARWIN_C_SOURCE 1
+#endif
+/* Enable general extensions on Solaris. */
+#ifndef __EXTENSIONS__
+# define __EXTENSIONS__ 1
+#endif
+/* Enable GNU extensions on systems that have them. */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
+/* Enable X/Open compliant socket functions that do not require linking
+ with -lxnet on HP-UX 11.11. */
+#ifndef _HPUX_ALT_XOPEN_SOCKET_API
+# define _HPUX_ALT_XOPEN_SOCKET_API 1
+#endif
+/* Identify the host operating system as Minix.
+ This macro does not affect the system headers' behavior.
+ A future release of Autoconf may stop defining this macro. */
+#ifndef _MINIX
+/* # undef _MINIX */
+#endif
+/* Enable general extensions on NetBSD.
+ Enable NetBSD compatibility extensions on Minix. */
+#ifndef _NETBSD_SOURCE
+# define _NETBSD_SOURCE 1
+#endif
+/* Enable OpenBSD compatibility extensions on NetBSD.
+ Oddly enough, this does nothing on OpenBSD. */
+#ifndef _OPENBSD_SOURCE
+# define _OPENBSD_SOURCE 1
+#endif
+/* Define to 1 if needed for POSIX-compatible behavior. */
+#ifndef _POSIX_SOURCE
+/* # undef _POSIX_SOURCE */
+#endif
+/* Define to 2 if needed for POSIX-compatible behavior. */
+#ifndef _POSIX_1_SOURCE
+/* # undef _POSIX_1_SOURCE */
+#endif
+/* Enable POSIX-compatible threading on Solaris. */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# define _POSIX_PTHREAD_SEMANTICS 1
+#endif
+/* Enable extensions specified by ISO/IEC TS 18661-5:2014. */
+#ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__
+# define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1
+#endif
+/* Enable extensions specified by ISO/IEC TS 18661-1:2014. */
+#ifndef __STDC_WANT_IEC_60559_BFP_EXT__
+# define __STDC_WANT_IEC_60559_BFP_EXT__ 1
+#endif
+/* Enable extensions specified by ISO/IEC TS 18661-2:2015. */
+#ifndef __STDC_WANT_IEC_60559_DFP_EXT__
+# define __STDC_WANT_IEC_60559_DFP_EXT__ 1
+#endif
+/* Enable extensions specified by ISO/IEC TS 18661-4:2015. */
+#ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__
+# define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1
+#endif
+/* Enable extensions specified by ISO/IEC TS 18661-3:2015. */
+#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__
+# define __STDC_WANT_IEC_60559_TYPES_EXT__ 1
+#endif
+/* Enable extensions specified by ISO/IEC TR 24731-2:2010. */
+#ifndef __STDC_WANT_LIB_EXT2__
+# define __STDC_WANT_LIB_EXT2__ 1
+#endif
+/* Enable extensions specified by ISO/IEC 24747:2009. */
+#ifndef __STDC_WANT_MATH_SPEC_FUNCS__
+# define __STDC_WANT_MATH_SPEC_FUNCS__ 1
+#endif
+/* Enable extensions on HP NonStop. */
+#ifndef _TANDEM_SOURCE
+# define _TANDEM_SOURCE 1
+#endif
+/* Enable X/Open extensions. Define to 500 only if necessary
+ to make mbstate_t available. */
+#ifndef _XOPEN_SOURCE
+/* # undef _XOPEN_SOURCE */
+#endif
+
+
+/* Version number of package */
+#define VERSION "2.1.28"
+
+/* Use DES */
+#define WITH_DES /**/
+
+/* Linking against dmalloc? */
+/* #undef WITH_DMALLOC */
+
+/* Use RC4 */
+#define WITH_RC4 /**/
+
+/* Use OpenSSL DES Implementation */
+#define WITH_SSL_DES /**/
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef mode_t */
+
+/* Define as a signed integer type capable of holding a process identifier. */
+/* #undef pid_t */
+
+
+
+#define RETSIGTYPE void
+
+/* Create a struct iovec if we need one */
+#if !defined(_WIN32)
+#if !defined(HAVE_SYS_UIO_H)
+/* (win32 is handled in sasl.h) */
+struct iovec {
+ char *iov_base;
+ long iov_len;
+};
+#else
+#include <sys/types.h>
+#include <sys/uio.h>
+#endif
+#endif
+
+/* location of the random number generator */
+#ifdef DEV_RANDOM
+/* #undef DEV_RANDOM */
+#endif
+#define DEV_RANDOM SASL_DEV_RANDOM
+
+/* if we've got krb_get_err_txt, we might as well use it;
+ especially since krb_err_txt isn't in some newer distributions
+ (MIT Kerb for Mac 4 being a notable example). If we don't have
+ it, we fall back to the krb_err_txt array */
+#ifdef HAVE_KRB_GET_ERR_TEXT
+#define get_krb_err_txt krb_get_err_text
+#else
+#define get_krb_err_txt(X) (krb_err_txt[(X)])
+#endif
+
+/* Make Solaris happy... */
+#ifndef __EXTENSIONS__
+#define __EXTENSIONS__ 1
+#endif
+
+/* Make Linux happy... */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#define SASL_PATH_ENV_VAR "SASL_PATH"
+#define SASL_CONF_PATH_ENV_VAR "SASL_CONF_PATH"
+
+#include <stdlib.h>
+#include <sys/types.h>
+#ifndef WIN32
+# include <sys/socket.h>
+# include <netdb.h>
+# include <netinet/in.h>
+# ifdef HAVE_SYS_PARAM_H
+# include <sys/param.h>
+# endif
+#else /* WIN32 */
+# include <winsock2.h>
+#endif /* WIN32 */
+#include <string.h>
+
+#ifndef HAVE_SOCKLEN_T
+typedef unsigned int socklen_t;
+#endif /* HAVE_SOCKLEN_T */
+
+#if !defined(HAVE_STRUCT_SOCKADDR_STORAGE) && !defined(WIN32)
+#define _SS_MAXSIZE 128 /* Implementation specific max size */
+#define _SS_PADSIZE (_SS_MAXSIZE - sizeof (struct sockaddr))
+
+struct sockaddr_storage {
+ struct sockaddr ss_sa;
+ char __ss_pad2[_SS_PADSIZE];
+};
+# define ss_family ss_sa.sa_family
+#endif /* !HAVE_STRUCT_SOCKADDR_STORAGE */
+
+#ifndef AF_INET6
+/* Define it to something that should never appear */
+#define AF_INET6 AF_MAX
+#endif
+
+#ifndef HAVE_GETADDRINFO
+#define getaddrinfo sasl_getaddrinfo
+#define freeaddrinfo sasl_freeaddrinfo
+#define gai_strerror sasl_gai_strerror
+#endif
+
+#ifndef HAVE_GETNAMEINFO
+#define getnameinfo sasl_getnameinfo
+#endif
+
+#if !defined(HAVE_GETNAMEINFO) || !defined(HAVE_GETADDRINFO)
+#include "gai.h"
+#endif
+
+#ifndef AI_NUMERICHOST /* support glibc 2.0.x */
+#define AI_NUMERICHOST 4
+#define NI_NUMERICHOST 2
+#define NI_NAMEREQD 4
+#define NI_NUMERICSERV 8
+#endif
+
+#ifndef HAVE_SYSEXITS_H
+#include "exits.h"
+#else
+#include "sysexits.h"
+#endif
+
+/* Get the correct time.h */
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+
+#ifndef HIER_DELIMITER
+#define HIER_DELIMITER '/'
+#endif
+
+#ifdef WIN32
+#define SASL_ROOT_KEY "SOFTWARE\\Carnegie Mellon\\Project Cyrus\\SASL Library"
+#define SASL_PLUGIN_PATH_ATTR "SearchPath"
+#define SASL_CONF_PATH_ATTR "ConfFile"
+
+#include <windows.h>
+inline static unsigned int sleep(unsigned int seconds) {
+ Sleep(seconds * 1000);
+ return 0;
+}
+#endif
+
+/* handy string manipulation functions */
+#ifndef HAVE_STRLCPY
+extern size_t saslauthd_strlcpy(char *dst, const char *src, size_t len);
+#define strlcpy(x,y,z) saslauthd_strlcpy((x),(y),(z))
+#endif
+#ifndef HAVE_STRLCAT
+extern size_t saslauthd_strlcat(char *dst, const char *src, size_t len);
+#define strlcat(x,y,z) saslauthd_strlcat((x),(y),(z))
+#endif
+#ifndef HAVE_ASPRINTF
+extern int asprintf(char **str, const char *fmt, ...);
+#endif
+
+#endif /* CONFIG_H */
+
+
+#if defined __GNUC__ && __GNUC__ > 6
+ #define GCC_FALLTHROUGH __attribute__((fallthrough));
+#else
+ #define GCC_FALLTHROUGH /* fall through */
+#endif
+
diff --git a/contrib/libs/sasl/config-osx.h b/contrib/libs/sasl/config-osx.h
new file mode 100644
index 0000000000..3d16804aee
--- /dev/null
+++ b/contrib/libs/sasl/config-osx.h
@@ -0,0 +1,3 @@
+#pragma once
+
+#include "config-linux.h"
diff --git a/contrib/libs/sasl/config-win.h b/contrib/libs/sasl/config-win.h
new file mode 100644
index 0000000000..42fc50ada5
--- /dev/null
+++ b/contrib/libs/sasl/config-win.h
@@ -0,0 +1,221 @@
+/* config.h--SASL configuration for win32
+ * Ryan Troll
+ */
+/*
+ * Copyright (c) 1998-2004 Carnegie Mellon University. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For permission or any other legal
+ * details, please contact
+ * Office of Technology Transfer
+ * Carnegie Mellon University
+ * 5000 Forbes Avenue
+ * Pittsburgh, PA 15213-3890
+ * (412) 268-4387, fax: (412) 268-7395
+ * tech-transfer@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Computing Services
+ * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef CONFIG_H
+#define CONFIG_H
+
+#define _CRT_RAND_S
+
+#include <stddef.h>
+
+/* winsock2 includes windows.h.
+ Note that we can't include both winsock.h and winsock2.h as
+ they conflict */
+#include <winsock2.h>
+
+/* Our package */
+#define PACKAGE "cyrus-sasl"
+
+/* Our version */
+#define VERSION "2.1.28"
+
+/* Visual Studio supports prototypes */
+#define PROTOTYPES 1
+
+#ifndef HAVE_CADDR_T
+#ifndef caddr_t
+typedef unsigned char *caddr_t;
+#define HAVE_CADDR_T 1
+#endif
+#endif
+
+#ifndef _INTPTR_T_DEFINED
+
+#ifdef _WIN64
+typedef __int64 intptr_t;
+#else
+typedef int intptr_t;
+#endif
+
+#endif
+
+/* Registry key that contains the locations of the plugins */
+#define SASL_ROOT_KEY "SOFTWARE\\Carnegie Mellon\\Project Cyrus\\SASL Library"
+#define SASL_PLUGIN_PATH_ATTR "SearchPath"
+#define SASL_CONF_PATH_ATTR "ConfFile"
+
+/* : This should probably be replaced with a call to a function
+ : that gets the proper value from Registry */
+#define SASL_DB_PATH "c:\\CMU\\sasldb2"
+
+/* what db package are we using? */
+/* #undef SASL_GDBM */
+/* #undef SASL_NDBM */
+/* #undef SASL_BERKELEYDB */
+
+/* which mechs can we link staticly? */
+#define STATIC_ANONYMOUS 1
+#define STATIC_CRAMMD5 1
+#define STATIC_DIGESTMD5 1
+#define STATIC_SCRAM 1
+#define STATIC_GSSAPIV2 1
+/* #undef STATIC_KERBEROS4 */
+#define STATIC_LOGIN 1
+/* #undef STATIC_MYSQL */
+#define STATIC_OTP 1
+#define STATIC_PLAIN 1
+#define STATIC_SASLDB 1
+#define STATIC_SRP 1
+
+/* ------------------------------------------------------------ */
+
+/* Things that are fetched via autoconf under Unix
+ */
+#define HAVE_MEMCPY 1
+
+#define PLUGINDIR "C:\\CMU\\bin\\sasl2"
+#define CONFIGDIR "C:\\CMU\\bin\\sasl2"
+
+/* Windows calls these functions something else
+ */
+#define strcasecmp stricmp
+#define strncasecmp strnicmp
+
+#define MAXHOSTNAMELEN 1024
+
+/* ------------------------------------------------------------ */
+
+#define WITHOUT_NANA
+#define L_DEFAULT_GUARD (0)
+#define I_DEFAULT_GUARD (0)
+#define I(foo)
+#define VL(foo) printf foo;
+#define VLP(foo,bar)
+
+#if !defined(__clang__)
+/* we're not gcc */
+#define __attribute__(foo)
+#endif
+
+/* : Same as in tpipv6.h */
+#ifndef HAVE_SOCKLEN_T
+typedef int socklen_t;
+#endif /* HAVE_SOCKLEN_T */
+
+/* If we expect to run on XP and later, we have IPv6 support natively */
+#if TARGET_WIN_SYSTEM >= 51
+#if !defined(_WIN32_WINNT)
+/* This forces the inclusion of OS supported functions, with no fallback */
+#define _WIN32_WINNT 0x0510
+#endif
+#endif
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1300)
+/* The following two defines will prevent our own definitions below */
+#define HAVE_GETADDRINFO
+#define HAVE_GETNAMEINFO
+#define HAVE_STRUCT_SOCKADDR_STORAGE
+/* Unless _WIN32_WINNT > 0x0500, Ws2tcpip.h will try to find OS provided
+ getaddrinfo at runtime. It will fallback to Microsoft emulation,
+ if not found */
+#include <Ws2tcpip.h>
+#endif
+
+#if !defined(HAVE_STRUCT_SOCKADDR_STORAGE) && !defined(_SS_MAXSIZE)
+#define _SS_MAXSIZE 128 /* Implementation specific max size */
+#define _SS_PADSIZE (_SS_MAXSIZE - sizeof (struct sockaddr))
+
+struct sockaddr_storage {
+ struct sockaddr ss_sa;
+ char __ss_pad2[_SS_PADSIZE];
+};
+# define ss_family ss_sa.sa_family
+#endif /* !HAVE_STRUCT_SOCKADDR_STORAGE */
+
+#ifndef AF_INET6
+/* Define it to something that should never appear */
+#define AF_INET6 AF_MAX
+#endif
+
+#ifndef HAVE_GETADDRINFO
+#define getaddrinfo sasl_getaddrinfo
+#define freeaddrinfo sasl_freeaddrinfo
+#define gai_strerror sasl_gai_strerror
+#endif
+
+#ifndef HAVE_GETNAMEINFO
+#define getnameinfo sasl_getnameinfo
+#endif
+
+#if !defined(HAVE_GETNAMEINFO) || !defined(HAVE_GETADDRINFO)
+#include "gai.h"
+#endif
+
+#ifndef AI_NUMERICHOST /* support glibc 2.0.x */
+#define AI_NUMERICHOST 4
+#define NI_NUMERICHOST 2
+#define NI_NAMEREQD 4
+#define NI_NUMERICSERV 8
+#endif
+
+#include <time.h>
+
+/* Keep in sync with SleepyCat definitions */
+typedef int int32_t;
+typedef __int64 int64_t;
+#ifdef _WIN64
+typedef int64_t ssize_t;
+#else
+typedef int32_t ssize_t;
+#endif
+
+#define HIER_DELIMITER '\\'
+
+#ifndef sleep
+#define sleep(seconds) plug_sleep(seconds)
+unsigned int plug_sleep(unsigned int seconds);
+#endif
+
+#define GCC_FALLTHROUGH
+
+#endif /* CONFIG_H */
diff --git a/contrib/libs/sasl/config.h b/contrib/libs/sasl/config.h
new file mode 100644
index 0000000000..1614a4f2b6
--- /dev/null
+++ b/contrib/libs/sasl/config.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#if defined(__APPLE__)
+# include "config-osx.h"
+#elif defined(_MSC_VER)
+# include "config-win.h"
+#else
+# include "config-linux.h"
+#endif
diff --git a/contrib/libs/sasl/include/exits.h b/contrib/libs/sasl/include/exits.h
new file mode 100644
index 0000000000..464cb11bab
--- /dev/null
+++ b/contrib/libs/sasl/include/exits.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 1987, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)sysexits.h 8.1 (Berkeley) 6/2/93
+ */
+
+#ifndef _SYSEXITS_H_
+#define _SYSEXITS_H_
+
+/*
+ * SYSEXITS.H -- Exit status codes for system programs.
+ *
+ * This include file attempts to categorize possible error
+ * exit statuses for system programs, notably delivermail
+ * and the Berkeley network.
+ *
+ * Error numbers begin at EX__BASE to reduce the possibility of
+ * clashing with other exit statuses that random programs may
+ * already return. The meaning of the codes is approximately
+ * as follows:
+ *
+ * EX_USAGE -- The command was used incorrectly, e.g., with
+ * the wrong number of arguments, a bad flag, a bad
+ * syntax in a parameter, or whatever.
+ * EX_DATAERR -- The input data was incorrect in some way.
+ * This should only be used for user's data & not
+ * system files.
+ * EX_NOINPUT -- An input file (not a system file) did not
+ * exist or was not readable. This could also include
+ * errors like "No message" to a mailer (if it cared
+ * to catch it).
+ * EX_NOUSER -- The user specified did not exist. This might
+ * be used for mail addresses or remote logins.
+ * EX_NOHOST -- The host specified did not exist. This is used
+ * in mail addresses or network requests.
+ * EX_UNAVAILABLE -- A service is unavailable. This can occur
+ * if a support program or file does not exist. This
+ * can also be used as a catchall message when something
+ * you wanted to do doesn't work, but you don't know
+ * why.
+ * EX_SOFTWARE -- An internal software error has been detected.
+ * This should be limited to non-operating system related
+ * errors as possible.
+ * EX_OSERR -- An operating system error has been detected.
+ * This is intended to be used for such things as "cannot
+ * fork", "cannot create pipe", or the like. It includes
+ * things like getuid returning a user that does not
+ * exist in the passwd file.
+ * EX_OSFILE -- Some system file (e.g., /etc/passwd, /etc/utmp,
+ * etc.) does not exist, cannot be opened, or has some
+ * sort of error (e.g., syntax error).
+ * EX_CANTCREAT -- A (user specified) output file cannot be
+ * created.
+ * EX_IOERR -- An error occurred while doing I/O on some file.
+ * EX_TEMPFAIL -- temporary failure, indicating something that
+ * is not really an error. In sendmail, this means
+ * that a mailer (e.g.) could not create a connection,
+ * and the request should be reattempted later.
+ * EX_PROTOCOL -- the remote system returned something that
+ * was "not possible" during a protocol exchange.
+ * EX_NOPERM -- You did not have sufficient permission to
+ * perform the operation. This is not intended for
+ * file system problems, which should use NOINPUT or
+ * CANTCREAT, but rather for higher level permissions.
+ */
+
+#define EX_OK 0 /* successful termination */
+
+#define EX__BASE 64 /* base value for error messages */
+
+#define EX_USAGE 64 /* command line usage error */
+#define EX_DATAERR 65 /* data format error */
+#define EX_NOINPUT 66 /* cannot open input */
+#define EX_NOUSER 67 /* addressee unknown */
+#define EX_NOHOST 68 /* host name unknown */
+#define EX_UNAVAILABLE 69 /* service unavailable */
+#define EX_SOFTWARE 70 /* internal software error */
+#define EX_OSERR 71 /* system error (e.g., can't fork) */
+#define EX_OSFILE 72 /* critical OS file missing */
+#define EX_CANTCREAT 73 /* can't create (user) output file */
+#define EX_IOERR 74 /* input/output error */
+#define EX_TEMPFAIL 75 /* temp failure; user is invited to retry */
+#define EX_PROTOCOL 76 /* remote error in protocol */
+#define EX_NOPERM 77 /* permission denied */
+#define EX_CONFIG 78 /* configuration error */
+
+#define EX__MAX 78 /* maximum listed value */
+
+#endif /* !_SYSEXITS_H_ */
diff --git a/contrib/libs/sasl/include/gai.h b/contrib/libs/sasl/include/gai.h
new file mode 100644
index 0000000000..59a38988ea
--- /dev/null
+++ b/contrib/libs/sasl/include/gai.h
@@ -0,0 +1,108 @@
+/*
+ * Mar 8, 2000 by Hajimu UMEMOTO <ume@mahoroba.org>
+ *
+ * This module is besed on ssh-1.2.27-IPv6-1.5 written by
+ * KIKUCHI Takahiro <kick@kyoto.wide.ad.jp>
+ */
+/*
+ * Copyright (c) 1998-2016 Carnegie Mellon University. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For permission or any other legal
+ * details, please contact
+ * Carnegie Mellon University
+ * Center for Technology Transfer and Enterprise Creation
+ * 4615 Forbes Avenue
+ * Suite 302
+ * Pittsburgh, PA 15213
+ * (412) 268-7393, fax: (412) 268-7395
+ * innovation@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Computing Services
+ * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * fake library for ssh
+ *
+ * This file is included in getaddrinfo.c and getnameinfo.c.
+ * See getaddrinfo.c and getnameinfo.c.
+ */
+
+#ifndef _GAI_H_
+#define _GAI_H_
+
+#ifndef NI_MAXHOST
+#define NI_MAXHOST 1025
+#endif
+#ifndef NI_MAXSERV
+#define NI_MAXSERV 32
+#endif
+
+/* for old netdb.h */
+#ifndef EAI_NODATA
+#define EAI_NODATA 1
+#define EAI_MEMORY 2
+#define EAI_FAMILY 5 /* ai_family not supported */
+#define EAI_SERVICE 9 /* servname not supported for ai_socktype */
+#endif
+
+/* dummy value for old netdb.h */
+#ifndef AI_PASSIVE
+#define AI_PASSIVE 1
+#define AI_CANONNAME 2
+struct addrinfo {
+ int ai_flags; /* AI_PASSIVE, AI_CANONNAME */
+ int ai_family; /* PF_xxx */
+ int ai_socktype; /* SOCK_xxx */
+ int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
+ size_t ai_addrlen; /* length of ai_addr */
+ char *ai_canonname; /* canonical name for hostname */
+ struct sockaddr *ai_addr; /* binary address */
+ struct addrinfo *ai_next; /* next structure in linked list */
+};
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef HAVE_GETNAMEINFO
+int getnameinfo(const struct sockaddr *, socklen_t, char *,
+ size_t, char *, size_t, int);
+#endif
+
+#ifndef HAVE_GETADDRINFO
+int getaddrinfo(const char *, const char *,
+ const struct addrinfo *, struct addrinfo **);
+void freeaddrinfo(struct addrinfo *);
+char *gai_strerror(int);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/contrib/libs/sasl/include/hmac-md5.h b/contrib/libs/sasl/include/hmac-md5.h
new file mode 100644
index 0000000000..ff81a9d871
--- /dev/null
+++ b/contrib/libs/sasl/include/hmac-md5.h
@@ -0,0 +1,59 @@
+/* hmac-md5.h -- HMAC_MD5 functions
+ */
+
+#ifndef HMAC_MD5_H
+#define HMAC_MD5_H 1
+
+#define HMAC_MD5_SIZE 16
+
+/* intermediate MD5 context */
+typedef struct HMAC_MD5_CTX_s {
+ MD5_CTX ictx, octx;
+} HMAC_MD5_CTX;
+
+/* intermediate HMAC state
+ * values stored in network byte order (Big Endian)
+ */
+typedef struct HMAC_MD5_STATE_s {
+ SASL_UINT4 istate[4];
+ SASL_UINT4 ostate[4];
+} HMAC_MD5_STATE;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* One step hmac computation
+ *
+ * digest may be same as text or key
+ */
+void _sasl_hmac_md5(const unsigned char *text, int text_len,
+ const unsigned char *key, int key_len,
+ unsigned char digest[HMAC_MD5_SIZE]);
+
+/* create context from key
+ */
+void _sasl_hmac_md5_init(HMAC_MD5_CTX *hmac,
+ const unsigned char *key, int key_len);
+
+/* precalculate intermediate state from key
+ */
+void _sasl_hmac_md5_precalc(HMAC_MD5_STATE *hmac,
+ const unsigned char *key, int key_len);
+
+/* initialize context from intermediate state
+ */
+void _sasl_hmac_md5_import(HMAC_MD5_CTX *hmac, HMAC_MD5_STATE *state);
+
+#define _sasl_hmac_md5_update(hmac, text, text_len) _sasl_MD5Update(&(hmac)->ictx, (text), (text_len))
+
+/* finish hmac from intermediate result. Intermediate result is zeroed.
+ */
+void _sasl_hmac_md5_final(unsigned char digest[HMAC_MD5_SIZE],
+ HMAC_MD5_CTX *hmac);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HMAC_MD5_H */
diff --git a/contrib/libs/sasl/include/md5.h b/contrib/libs/sasl/include/md5.h
new file mode 100644
index 0000000000..3571930158
--- /dev/null
+++ b/contrib/libs/sasl/include/md5.h
@@ -0,0 +1,42 @@
+/* MD5.H - header file for MD5C.C
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+/* MD5 context. */
+typedef struct {
+ SASL_UINT4 state[4]; /* state (ABCD) */
+ SASL_UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
+ unsigned char buffer[64]; /* input buffer */
+} MD5_CTX;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void _sasl_MD5Init (MD5_CTX *);
+void _sasl_MD5Update (MD5_CTX *, const unsigned char *, unsigned int);
+void _sasl_MD5Final (unsigned char [16], MD5_CTX *);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/contrib/libs/sasl/include/md5global.h b/contrib/libs/sasl/include/md5global.h
new file mode 100644
index 0000000000..034d9fa2d4
--- /dev/null
+++ b/contrib/libs/sasl/include/md5global.h
@@ -0,0 +1,38 @@
+/* GLOBAL.H - RSAREF types and constants
+ */
+#ifndef MD5GLOBAL_H
+#define MD5GLOBAL_H
+
+/* PROTOTYPES should be set to one if and only if the compiler supports
+ function argument prototyping.
+The following makes PROTOTYPES default to 0 if it has not already
+ been defined with C compiler flags.
+ */
+#ifndef PROTOTYPES
+#define PROTOTYPES 0
+#endif
+
+/* POINTER defines a generic pointer type */
+typedef unsigned char *POINTER;
+
+typedef signed char SASL_INT1; /* 8 bits */
+typedef short SASL_INT2; /* 16 bits */
+typedef int SASL_INT4; /* 32 bits */
+typedef long SASL_INT8; /* 64 bits */
+typedef unsigned char SASL_UINT1; /* 8 bits */
+typedef unsigned short SASL_UINT2; /* 16 bits */
+typedef unsigned int SASL_UINT4; /* 32 bits */
+typedef unsigned long SASL_UINT8; /* 64 bits */
+
+/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
+If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
+returns an empty list.
+*/
+#if PROTOTYPES
+#define PROTO_LIST(list) list
+#else
+#define PROTO_LIST(list) ()
+#endif
+
+#endif /* MD5GLOBAL_H */
+
diff --git a/contrib/libs/sasl/include/prop.h b/contrib/libs/sasl/include/prop.h
new file mode 100644
index 0000000000..bf091d67d8
--- /dev/null
+++ b/contrib/libs/sasl/include/prop.h
@@ -0,0 +1,170 @@
+/* prop.h -- property request/response management routines
+ *
+ * Author: Chris Newman
+ * Removal of implementation-specific details by: Rob Siemborski
+ *
+ * This is intended to be used to create a list of properties to request,
+ * and _then_ request values for all properties. Any change to the request
+ * list will discard any existing values. This assumption allows a very
+ * efficient and simple memory model. This was designed for SASL API auxiliary
+ * property support, but would be fine for other contexts where this property
+ * model is appropriate.
+ *
+ * The "struct propctx" is allocated by prop_new and is a fixed size structure.
+ * If a prop_init() call were added, it would be reasonable to embed a "struct
+ * propctx" in another structure. prop_new also allocates a pool of memory
+ * (in the vbase field) which will be used for an array of "struct propval"
+ * to list all the requested properties.
+ *
+ * Properties may be multi-valued.
+ */
+
+#ifndef PROP_H
+#define PROP_H 1
+
+/* The following ifdef block is the standard way of creating macros
+ * which make exporting from a DLL simpler. All files within this DLL
+ * are compiled with the LIBSASL_EXPORTS symbol defined on the command
+ * line. this symbol should not be defined on any project that uses
+ * this DLL. This way any other project whose source files include
+ * this file see LIBSASL_API functions as being imported from a DLL,
+ * wheras this DLL sees symbols defined with this macro as being
+ * exported. */
+/* Under Unix, life is simpler: we just need to mark library functions
+ * as extern. (Technically, we don't even have to do that.) */
+# define LIBSASL_API extern
+
+/* Same as above, but used during a variable declaration. */
+# define LIBSASL_VAR extern
+
+/* the resulting structure for property values
+ */
+struct propval {
+ const char *name; /* name of property; NULL = end of list */
+ /* same pointer used in request will be used here */
+ const char **values; /* list of strings, values == NULL if property not
+ * found, *values == NULL if property found with
+ * no values */
+ unsigned nvalues; /* total number of value strings */
+ unsigned valsize; /* total size in characters of all value strings */
+};
+
+/*
+ * private internal structure
+ */
+#define PROP_DEFAULT 4 /* default number of propvals to assume */
+struct propctx;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* create a property context
+ * estimate -- an estimate of the storage needed for requests & responses
+ * 0 will use module default
+ * returns a new property context on success and NULL on any error
+ */
+LIBSASL_API struct propctx *prop_new(unsigned estimate);
+
+/* create new propctx which duplicates the contents of an existing propctx
+ * returns SASL_OK on success
+ * possible other return values include: SASL_NOMEM, SASL_BADPARAM
+ */
+LIBSASL_API int prop_dup(struct propctx *src_ctx, struct propctx **dst_ctx);
+
+/* Add property names to request
+ * ctx -- context from prop_new()
+ * names -- list of property names; must persist until context freed
+ * or requests cleared (This extends to other contexts that
+ * are dup'ed from this one, and their children, etc)
+ *
+ * NOTE: may clear values from context as side-effect
+ * returns SASL_OK on success
+ * possible other return values include: SASL_NOMEM, SASL_BADPARAM
+ */
+LIBSASL_API int prop_request(struct propctx *ctx, const char **names);
+
+/* return array of struct propval from the context
+ * return value persists until next call to
+ * prop_request, prop_clear or prop_dispose on context
+ *
+ * returns NULL on error
+ */
+LIBSASL_API const struct propval *prop_get(struct propctx *ctx);
+
+/* Fill in an array of struct propval based on a list of property names
+ * return value persists until next call to
+ * prop_request, prop_clear or prop_dispose on context
+ * returns number of matching properties which were found (values != NULL)
+ * if a name requested here was never requested by a prop_request, then
+ * the name field of the associated vals entry will be set to NULL
+ *
+ * The vals array MUST be atleast as long as the names array.
+ *
+ * returns # of matching properties on success
+ * possible other return values include: SASL_BADPARAM
+ */
+LIBSASL_API int prop_getnames(struct propctx *ctx, const char **names,
+ struct propval *vals);
+
+/* clear values and optionally requests from property context
+ * ctx -- property context
+ * requests -- 0 = don't clear requests, 1 = clear requests
+ */
+LIBSASL_API void prop_clear(struct propctx *ctx, int requests);
+
+/* erase the value of a property
+ */
+LIBSASL_API void prop_erase(struct propctx *ctx, const char *name);
+
+/* dispose of property context
+ * ctx -- is disposed and set to NULL; noop if ctx or *ctx is NULL
+ */
+LIBSASL_API void prop_dispose(struct propctx **ctx);
+
+
+/****fetcher interfaces****/
+
+/* format the requested property names into a string
+ * ctx -- context from prop_new()/prop_request()
+ * sep -- separator between property names (unused if none requested)
+ * seplen -- length of separator, if < 0 then strlen(sep) will be used
+ * outbuf -- output buffer
+ * outmax -- maximum length of output buffer including NUL terminator
+ * outlen -- set to length of output string excluding NUL terminator
+ * returns SASL_OK on success
+ * returns SASL_BADPARAM or amount of additional space needed on failure
+ */
+LIBSASL_API int prop_format(struct propctx *ctx, const char *sep, int seplen,
+ char *outbuf, unsigned outmax, unsigned *outlen);
+
+/* add a property value to the context
+ * ctx -- context from prop_new()/prop_request()
+ * name -- name of property to which value will be added
+ * if NULL, add to the same name as previous prop_set/setvals call
+ * value -- a value for the property; will be copied into context
+ * if NULL, remove existing values
+ * vallen -- length of value, if <= 0 then strlen(value) will be used
+ * returns SASL_OK on success
+ * possible error return values include: SASL_BADPARAM, SASL_NOMEM
+ */
+LIBSASL_API int prop_set(struct propctx *ctx, const char *name,
+ const char *value, int vallen);
+
+/* set the values for a property
+ * ctx -- context from prop_new()/prop_request()
+ * name -- name of property to which value will be added
+ * if NULL, add to the same name as previous prop_set/setvals call
+ * values -- array of values, ending in NULL. Each value is a NUL terminated
+ * string
+ * returns SASL_OK on success
+ * possible error return values include: SASL_BADPARAM, SASL_NOMEM
+ */
+LIBSASL_API int prop_setvals(struct propctx *ctx, const char *name,
+ const char **values);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PROP_H */
diff --git a/contrib/libs/sasl/include/sasl.h b/contrib/libs/sasl/include/sasl.h
new file mode 100644
index 0000000000..dc04ca4714
--- /dev/null
+++ b/contrib/libs/sasl/include/sasl.h
@@ -0,0 +1,1332 @@
+/* This is a proposed C API for support of SASL
+ *
+ *********************************IMPORTANT*******************************
+ * send email to chris.newman@innosoft.com and cyrus-bugs@andrew.cmu.edu *
+ * if you need to add new error codes, callback types, property values, *
+ * etc. It is important to keep the multiple implementations of this *
+ * API from diverging. *
+ *********************************IMPORTANT*******************************
+ *
+ * Basic Type Summary:
+ * sasl_conn_t Context for a SASL connection negotiation
+ * sasl_ssf_t Security layer Strength Factor
+ * sasl_callback_t A typed client/server callback function and context
+ * sasl_interact_t A client interaction descriptor
+ * sasl_secret_t A client password
+ * sasl_rand_t Random data context structure
+ * sasl_security_properties_t An application's required security level
+ *
+ * Callbacks:
+ * sasl_getopt_t client/server: Get an option value
+ * sasl_logmsg_t client/server: Log message handler
+ * sasl_getsimple_t client: Get user/language list
+ * sasl_getsecret_t client: Get authentication secret
+ * sasl_chalprompt_t client: Display challenge and prompt for response
+ *
+ * Server only Callbacks:
+ * sasl_authorize_t user authorization policy callback
+ * sasl_getconfpath_t get path to search for config file
+ * sasl_server_userdb_checkpass check password and auxprops in userdb
+ * sasl_server_userdb_setpass set password in userdb
+ * sasl_server_canon_user canonicalize username routine
+ *
+ * Client/Server Function Summary:
+ * sasl_done Release all SASL global state
+ * sasl_dispose Connection done: Dispose of sasl_conn_t
+ * sasl_getprop Get property (e.g., user name, security layer info)
+ * sasl_setprop Set property (e.g., external ssf)
+ * sasl_errdetail Generate string from last error on connection
+ * sasl_errstring Translate sasl error code to a string
+ * sasl_encode Encode data to send using security layer
+ * sasl_decode Decode data received using security layer
+ *
+ * Utility functions:
+ * sasl_encode64 Encode data to send using MIME base64 encoding
+ * sasl_decode64 Decode data received using MIME base64 encoding
+ * sasl_erasebuffer Erase a buffer
+ *
+ * Client Function Summary:
+ * sasl_client_init Load and initialize client plug-ins (call once)
+ * sasl_client_new Initialize client connection context: sasl_conn_t
+ * sasl_client_start Select mechanism for connection
+ * sasl_client_step Perform one authentication step
+ *
+ * Server Function Summary
+ * sasl_server_init Load and initialize server plug-ins (call once)
+ * sasl_server_new Initialize server connection context: sasl_conn_t
+ * sasl_listmech Create list of available mechanisms
+ * sasl_server_start Begin an authentication exchange
+ * sasl_server_step Perform one authentication exchange step
+ * sasl_checkpass Check a plaintext passphrase
+ * sasl_checkapop Check an APOP challenge/response (uses pseudo "APOP"
+ * mechanism similar to CRAM-MD5 mechanism; optional)
+ * sasl_user_exists Check if user exists
+ * sasl_setpass Change a password or add a user entry
+ * sasl_auxprop_request Request auxiliary properties
+ * sasl_auxprop_getctx Get auxiliary property context for connection
+ * sasl_auxprop_store Store a set of auxiliary properties
+ *
+ * Basic client model:
+ * 1. client calls sasl_client_init() at startup to load plug-ins
+ * 2. when connection formed, call sasl_client_new()
+ * 3. once list of supported mechanisms received from server, client
+ * calls sasl_client_start(). goto 4a
+ * 4. client calls sasl_client_step()
+ * [4a. If SASL_INTERACT, fill in prompts and goto 4
+ * -- doesn't happen if callbacks provided]
+ * 4b. If SASL error, goto 7 or 3
+ * 4c. If SASL_OK, continue or goto 6 if last server response was success
+ * 5. send message to server, wait for response
+ * 5a. On data or success with server response, goto 4
+ * 5b. On failure goto 7 or 3
+ * 5c. On success with no server response continue
+ * 6. continue with application protocol until connection closes
+ * call sasl_getprop/sasl_encode/sasl_decode() if using security layer
+ * 7. call sasl_dispose(), may return to step 2
+ * 8. call sasl_done() when program terminates
+ *
+ * Basic Server model:
+ * 1. call sasl_server_init() at startup to load plug-ins
+ * 2. On connection, call sasl_server_new()
+ * 3. call sasl_listmech() and send list to client]
+ * 4. after client AUTH command, call sasl_server_start(), goto 5a
+ * 5. call sasl_server_step()
+ * 5a. If SASL_CONTINUE, output to client, wait response, repeat 5
+ * 5b. If SASL error, then goto 7
+ * 5c. If SASL_OK, move on
+ * 6. continue with application protocol until connection closes
+ * call sasl_getprop to get username
+ * call sasl_getprop/sasl_encode/sasl_decode() if using security layer
+ * 7. call sasl_dispose(), may return to step 2
+ * 8. call sasl_done() when program terminates
+ *
+ *************************************************
+ * IMPORTANT NOTE: server realms / username syntax
+ *
+ * If a user name contains a "@", then the rightmost "@" in the user name
+ * separates the account name from the realm in which this account is
+ * located. A single server may support multiple realms. If the
+ * server knows the realm at connection creation time (e.g., a server
+ * with multiple IP addresses tightly binds one address to a specific
+ * realm) then that realm must be passed in the user_realm field of
+ * the sasl_server_new call. If user_realm is non-empty and an
+ * unqualified user name is supplied, then the canon_user facility is
+ * expected to append "@" and user_realm to the user name. The canon_user
+ * facility may treat other characters such as "%" as equivalent to "@".
+ *
+ * If the server forbids the use of "@" in user names for other
+ * purposes, this simplifies security validation.
+ */
+
+#ifndef SASL_H
+#define SASL_H 1
+
+#include <stddef.h> /* For size_t */
+
+/* Keep in sync with win32/common.mak */
+#define SASL_VERSION_MAJOR 2
+#define SASL_VERSION_MINOR 1
+#define SASL_VERSION_STEP 28
+
+/* A convenience macro: same as was defined in the OpenLDAP LDAPDB */
+#define SASL_VERSION_FULL ((SASL_VERSION_MAJOR << 16) |\
+ (SASL_VERSION_MINOR << 8) | SASL_VERSION_STEP)
+
+#include "prop.h"
+
+/*************
+ * Basic API *
+ *************/
+
+/* SASL result codes: */
+#define SASL_CONTINUE 1 /* another step is needed in authentication */
+#define SASL_OK 0 /* successful result */
+#define SASL_FAIL -1 /* generic failure */
+#define SASL_NOMEM -2 /* memory shortage failure */
+#define SASL_BUFOVER -3 /* overflowed buffer */
+#define SASL_NOMECH -4 /* mechanism not supported */
+#define SASL_BADPROT -5 /* bad protocol / cancel */
+#define SASL_NOTDONE -6 /* can't request info until later in exchange */
+#define SASL_BADPARAM -7 /* invalid parameter supplied */
+#define SASL_TRYAGAIN -8 /* transient failure (e.g., weak key) */
+#define SASL_BADMAC -9 /* integrity check failed */
+#define SASL_NOTINIT -12 /* SASL library not initialized */
+ /* -- client only codes -- */
+#define SASL_INTERACT 2 /* needs user interaction */
+#define SASL_BADSERV -10 /* server failed mutual authentication step */
+#define SASL_WRONGMECH -11 /* mechanism doesn't support requested feature */
+ /* -- server only codes -- */
+#define SASL_BADAUTH -13 /* authentication failure */
+#define SASL_NOAUTHZ -14 /* authorization failure */
+#define SASL_TOOWEAK -15 /* mechanism too weak for this user */
+#define SASL_ENCRYPT -16 /* encryption needed to use mechanism */
+#define SASL_TRANS -17 /* One time use of a plaintext password will
+ enable requested mechanism for user */
+#define SASL_EXPIRED -18 /* passphrase expired, has to be reset */
+#define SASL_DISABLED -19 /* account disabled */
+#define SASL_NOUSER -20 /* user not found */
+#define SASL_BADVERS -23 /* version mismatch with plug-in */
+#define SASL_UNAVAIL -24 /* remote authentication server unavailable */
+#define SASL_NOVERIFY -26 /* user exists, but no verifier for user */
+ /* -- codes for password setting -- */
+#define SASL_PWLOCK -21 /* passphrase locked */
+#define SASL_NOCHANGE -22 /* requested change was not needed */
+#define SASL_WEAKPASS -27 /* passphrase is too weak for security policy */
+#define SASL_NOUSERPASS -28 /* user supplied passwords not permitted */
+#define SASL_NEED_OLD_PASSWD -29 /* sasl_setpass needs old password in order
+ to perform password change */
+#define SASL_CONSTRAINT_VIOLAT -30 /* a property can't be stored,
+ because of some constrains/policy violation */
+
+#define SASL_BADBINDING -32 /* channel binding failure */
+#define SASL_CONFIGERR -100 /* error when parsing configuration file */
+
+/* max size of a sasl mechanism name */
+#define SASL_MECHNAMEMAX 20
+
+#ifdef _WIN32
+/* Define to have the same layout as a WSABUF */
+#ifndef STRUCT_IOVEC_DEFINED
+#define STRUCT_IOVEC_DEFINED 1
+struct iovec {
+ long iov_len;
+ char *iov_base;
+};
+#endif
+#else
+struct iovec; /* Defined in OS headers */
+#endif
+
+
+/* per-connection SASL negotiation state for client or server
+ */
+typedef struct sasl_conn sasl_conn_t;
+
+/* Plain text password structure.
+ * len is the length of the password, data is the text.
+ */
+typedef struct sasl_secret {
+ unsigned long len;
+ unsigned char data[1]; /* variable sized */
+} sasl_secret_t;
+
+/* random data context structure
+ */
+typedef struct sasl_rand_s sasl_rand_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/****************************
+ * Configure Basic Services *
+ ****************************/
+
+/* the following functions are used to adjust how allocation and mutexes work
+ * they must be called before all other SASL functions:
+ */
+
+#include <sys/types.h>
+
+/* memory allocation functions which may optionally be replaced:
+ */
+typedef void *sasl_malloc_t(size_t);
+typedef void *sasl_calloc_t(size_t, size_t);
+typedef void *sasl_realloc_t(void *, size_t);
+typedef void sasl_free_t(void *);
+
+LIBSASL_API void sasl_set_alloc(sasl_malloc_t *,
+ sasl_calloc_t *,
+ sasl_realloc_t *,
+ sasl_free_t *);
+
+/* mutex functions which may optionally be replaced:
+ * sasl_mutex_alloc allocates a mutex structure
+ * sasl_mutex_lock blocks until mutex locked
+ * returns -1 on deadlock or parameter error
+ * returns 0 on success
+ * sasl_mutex_unlock unlocks mutex if it's locked
+ * returns -1 if not locked or parameter error
+ * returns 0 on success
+ * sasl_mutex_free frees a mutex structure
+ */
+typedef void *sasl_mutex_alloc_t(void);
+typedef int sasl_mutex_lock_t(void *mutex);
+typedef int sasl_mutex_unlock_t(void *mutex);
+typedef void sasl_mutex_free_t(void *mutex);
+LIBSASL_API void sasl_set_mutex(sasl_mutex_alloc_t *, sasl_mutex_lock_t *,
+ sasl_mutex_unlock_t *, sasl_mutex_free_t *);
+
+/*****************************
+ * Security preference types *
+ *****************************/
+
+/* security layer strength factor -- an unsigned integer usable by the caller
+ * to specify approximate security layer strength desired. Roughly
+ * correlated to effective key length for encryption.
+ * 0 = no protection
+ * 1 = integrity protection only
+ * 40 = 40-bit DES or 40-bit RC2/RC4
+ * 56 = DES
+ * 112 = triple-DES
+ * 128 = 128-bit RC2/RC4/BLOWFISH
+ * 256 = baseline AES
+ */
+typedef unsigned sasl_ssf_t;
+
+/* usage flags provided to sasl_server_new and sasl_client_new:
+ */
+#define SASL_SUCCESS_DATA 0x0004 /* server supports data on success */
+#define SASL_NEED_PROXY 0x0008 /* require a mech that allows proxying */
+#define SASL_NEED_HTTP 0x0010 /* require a mech that can do HTTP auth */
+
+/***************************
+ * Security Property Types *
+ ***************************/
+
+/* Structure specifying the client or server's security policy
+ * and optional additional properties.
+ */
+
+/* These are the various security flags apps can specify. */
+/* NOPLAINTEXT -- don't permit mechanisms susceptible to simple
+ * passive attack (e.g., PLAIN, LOGIN)
+ * NOACTIVE -- protection from active (non-dictionary) attacks
+ * during authentication exchange.
+ * Authenticates server.
+ * NODICTIONARY -- don't permit mechanisms susceptible to passive
+ * dictionary attack
+ * FORWARD_SECRECY -- require forward secrecy between sessions
+ * (breaking one won't help break next)
+ * NOANONYMOUS -- don't permit mechanisms that allow anonymous login
+ * PASS_CREDENTIALS -- require mechanisms which pass client
+ * credentials, and allow mechanisms which can pass
+ * credentials to do so
+ * MUTUAL_AUTH -- require mechanisms which provide mutual
+ * authentication
+ */
+#define SASL_SEC_NOPLAINTEXT 0x0001
+#define SASL_SEC_NOACTIVE 0x0002
+#define SASL_SEC_NODICTIONARY 0x0004
+#define SASL_SEC_FORWARD_SECRECY 0x0008
+#define SASL_SEC_NOANONYMOUS 0x0010
+#define SASL_SEC_PASS_CREDENTIALS 0x0020
+#define SASL_SEC_MUTUAL_AUTH 0x0040
+#define SASL_SEC_MAXIMUM 0xFFFF
+
+/* This is used when adding hash size to the security_flags field */
+/* NB: hash size is in bits */
+#define SASL_SET_HASH_STRENGTH_BITS(x) (((x) / 8) << 16)
+
+/* NB: This value is in bytes */
+#define SASL_GET_HASH_STRENGTH(x) ((x) >> 16)
+
+typedef struct sasl_security_properties
+{
+ /* security strength factor
+ * min_ssf = minimum acceptable final level
+ * max_ssf = maximum acceptable final level
+ */
+ sasl_ssf_t min_ssf;
+ sasl_ssf_t max_ssf;
+
+ /* Maximum security layer receive buffer size.
+ * 0=security layer not supported
+ */
+ unsigned maxbufsize;
+
+ /* bitfield for attacks to protect against */
+ unsigned security_flags;
+
+ /* NULL terminated array of additional property names, values */
+ const char **property_names;
+ const char **property_values;
+} sasl_security_properties_t;
+
+/******************
+ * Callback types *
+ ******************/
+
+/*
+ * Extensible type for a client/server callbacks
+ * id -- identifies callback type
+ * proc -- procedure call arguments vary based on id
+ * context -- context passed to procedure
+ */
+/* Note that any memory that is allocated by the callback needs to be
+ * freed by the application, be it via function call or interaction.
+ *
+ * It may be freed after sasl_*_step returns SASL_OK. if the mechanism
+ * requires this information to persist (for a security layer, for example)
+ * it must maintain a private copy.
+ */
+typedef struct sasl_callback {
+ /* Identifies the type of the callback function.
+ * Mechanisms must ignore callbacks with id's they don't recognize.
+ */
+ unsigned long id;
+ int (*proc)(void); /* Callback function. Types of arguments vary by 'id' */
+ void *context;
+} sasl_callback_t;
+
+/* callback ids & functions:
+ */
+#define SASL_CB_LIST_END 0 /* end of list */
+
+/* option reading callback -- this allows a SASL configuration to be
+ * encapsulated in the caller's configuration system. Some implementations
+ * may use default config file(s) if this is omitted. Configuration items
+ * may be plugin-specific and are arbitrary strings.
+ *
+ * inputs:
+ * context -- option context from callback record
+ * plugin_name -- name of plugin (NULL = general SASL option)
+ * option -- name of option
+ * output:
+ * result -- set to result which persists until next getopt in
+ * same thread, unchanged if option not found
+ * len -- length of result (may be NULL)
+ * returns:
+ * SASL_OK -- no error
+ * SASL_FAIL -- error
+ */
+typedef int sasl_getopt_t(void *context, const char *plugin_name,
+ const char *option,
+ const char **result, unsigned *len);
+#define SASL_CB_GETOPT 1
+
+/* Logging levels for use with the logging callback function. */
+#define SASL_LOG_NONE 0 /* don't log anything */
+#define SASL_LOG_ERR 1 /* log unusual errors (default) */
+#define SASL_LOG_FAIL 2 /* log all authentication failures */
+#define SASL_LOG_WARN 3 /* log non-fatal warnings */
+#define SASL_LOG_NOTE 4 /* more verbose than LOG_WARN */
+#define SASL_LOG_DEBUG 5 /* more verbose than LOG_NOTE */
+#define SASL_LOG_TRACE 6 /* traces of internal protocols */
+#define SASL_LOG_PASS 7 /* traces of internal protocols, including
+ * passwords */
+
+/* logging callback -- this allows plugins and the middleware to
+ * log operations they perform.
+ * inputs:
+ * context -- logging context from the callback record
+ * level -- logging level; see above
+ * message -- message to log
+ * returns:
+ * SASL_OK -- no error
+ * SASL_FAIL -- error
+ */
+typedef int sasl_log_t(void *context,
+ int level,
+ const char *message);
+#define SASL_CB_LOG 2
+
+/* getpath callback -- this allows applications to specify the
+ * colon-separated path to search for plugins (by default,
+ * taken from an implementation-specific location).
+ * inputs:
+ * context -- getpath context from the callback record
+ * outputs:
+ * path -- colon seperated path
+ * returns:
+ * SASL_OK -- no error
+ * SASL_FAIL -- error
+ */
+typedef int sasl_getpath_t(void *context,
+ const char **path);
+
+#define SASL_CB_GETPATH 3
+
+/* verify file callback -- this allows applications to check if they
+ * want SASL to use files, file by file. This is intended to allow
+ * applications to sanity check the environment to make sure plugins
+ * or the configuration file can't be written to, etc.
+ * inputs:
+ * context -- verifypath context from the callback record
+ * file -- full path to file to verify
+ * type -- type of file to verify (see below)
+
+ * returns:
+ * SASL_OK -- no error (file can safely be used)
+ * SASL_CONTINUE -- continue WITHOUT using this file
+ * SASL_FAIL -- error
+ */
+
+/* these are the types of files libsasl will ask about */
+typedef enum {
+ SASL_VRFY_PLUGIN=0, /* a DLL/shared library plug-in */
+ SASL_VRFY_CONF=1, /* a configuration file */
+ SASL_VRFY_PASSWD=2, /* a password storage file/db */
+ SASL_VRFY_OTHER=3 /* some other file */
+} sasl_verify_type_t;
+
+typedef int sasl_verifyfile_t(void *context,
+ const char *file, sasl_verify_type_t type);
+#define SASL_CB_VERIFYFILE 4
+
+/* getconfpath callback -- this allows applications to specify the
+ * colon-separated path to search for config files (by default,
+ * taken from the SASL_CONF_PATH environment variable).
+ * inputs:
+ * context -- getconfpath context from the callback record
+ * outputs:
+ * path -- colon seperated path (allocated on the heap; the
+ * library will free it using the sasl_free_t *
+ * passed to sasl_set_callback, or the standard free()
+ * library call).
+ * returns:
+ * SASL_OK -- no error
+ * SASL_FAIL -- error
+ */
+typedef int sasl_getconfpath_t(void *context,
+ char **path);
+
+#define SASL_CB_GETCONFPATH 5
+
+/* client/user interaction callbacks:
+ */
+/* Simple prompt -- result must persist until next call to getsimple on
+ * same connection or until connection context is disposed
+ * inputs:
+ * context -- context from callback structure
+ * id -- callback id
+ * outputs:
+ * result -- set to NUL terminated string
+ * NULL = user cancel
+ * len -- length of result
+ * returns SASL_OK
+ */
+typedef int sasl_getsimple_t(void *context, int id,
+ const char **result, unsigned *len);
+#define SASL_CB_USER 0x4001 /* client user identity to login as */
+#define SASL_CB_AUTHNAME 0x4002 /* client authentication name */
+#define SASL_CB_LANGUAGE 0x4003 /* comma separated list of RFC 1766
+ * language codes in order of preference
+ * to be used to localize client prompts
+ * or server error codes */
+#define SASL_CB_CNONCE 0x4007 /* caller supplies client-nonce
+ * primarily for testing purposes */
+
+/* get a sasl_secret_t (plaintext password with length)
+ * inputs:
+ * conn -- connection context
+ * context -- context from callback structure
+ * id -- callback id
+ * outputs:
+ * psecret -- set to NULL to cancel
+ * set to password structure which must persist until
+ * next call to getsecret in same connection, but middleware
+ * will erase password data when it's done with it.
+ * returns SASL_OK
+ */
+typedef int sasl_getsecret_t(sasl_conn_t *conn, void *context, int id,
+ sasl_secret_t **psecret);
+#define SASL_CB_PASS 0x4004 /* client passphrase-based secret */
+
+
+/* prompt for input in response to a challenge.
+ * input:
+ * context -- context from callback structure
+ * id -- callback id
+ * challenge -- server challenge
+ * output:
+ * result -- NUL terminated result, NULL = user cancel
+ * len -- length of result
+ * returns SASL_OK
+ */
+typedef int sasl_chalprompt_t(void *context, int id,
+ const char *challenge,
+ const char *prompt, const char *defresult,
+ const char **result, unsigned *len);
+#define SASL_CB_ECHOPROMPT 0x4005 /* challenge and client enterred result */
+#define SASL_CB_NOECHOPROMPT 0x4006 /* challenge and client enterred result */
+
+/* prompt (or autoselect) the realm to do authentication in.
+ * may get a list of valid realms.
+ * input:
+ * context -- context from callback structure
+ * id -- callback id
+ * availrealms -- available realms; string list; NULL terminated
+ * list may be empty.
+ * output:
+ * result -- NUL terminated realm; NULL is equivalent to ""
+ * returns SASL_OK
+ * result must persist until the next callback
+ */
+typedef int sasl_getrealm_t(void *context, int id,
+ const char **availrealms,
+ const char **result);
+#define SASL_CB_GETREALM (0x4008) /* realm to attempt authentication in */
+
+/* server callbacks:
+ */
+
+/* improved callback to verify authorization;
+ * canonicalization now handled elsewhere
+ * conn -- connection context
+ * requested_user -- the identity/username to authorize (NUL terminated)
+ * rlen -- length of requested_user
+ * auth_identity -- the identity associated with the secret (NUL terminated)
+ * alen -- length of auth_identity
+ * default_realm -- default user realm, as passed to sasl_server_new if
+ * urlen -- length of default realm
+ * propctx -- auxiliary properties
+ * returns SASL_OK on success,
+ * SASL_NOAUTHZ or other SASL response on failure
+ */
+typedef int sasl_authorize_t(sasl_conn_t *conn,
+ void *context,
+ const char *requested_user, unsigned rlen,
+ const char *auth_identity, unsigned alen,
+ const char *def_realm, unsigned urlen,
+ struct propctx *propctx);
+#define SASL_CB_PROXY_POLICY 0x8001
+
+/* functions for "userdb" based plugins to call to get/set passwords.
+ * the location for the passwords is determined by the caller or middleware.
+ * plug-ins may get passwords from other locations.
+ */
+
+/* callback to verify a plaintext password against the caller-supplied
+ * user database. This is necessary to allow additional <method>s for
+ * encoding of the userPassword property.
+ * user -- NUL terminated user name with user@realm syntax
+ * pass -- password to check (may not be NUL terminated)
+ * passlen -- length of password to check
+ * propctx -- auxiliary properties for user
+ */
+typedef int sasl_server_userdb_checkpass_t(sasl_conn_t *conn,
+ void *context,
+ const char *user,
+ const char *pass,
+ unsigned passlen,
+ struct propctx *propctx);
+#define SASL_CB_SERVER_USERDB_CHECKPASS (0x8005)
+
+/* callback to store/change a plaintext password in the user database
+ * user -- NUL terminated user name with user@realm syntax
+ * pass -- password to store (may not be NUL terminated)
+ * passlen -- length of password to store
+ * propctx -- auxiliary properties (not stored)
+ * flags -- see SASL_SET_* flags below (SASL_SET_CREATE optional)
+ */
+typedef int sasl_server_userdb_setpass_t(sasl_conn_t *conn,
+ void *context,
+ const char *user,
+ const char *pass,
+ unsigned passlen,
+ struct propctx *propctx,
+ unsigned flags);
+#define SASL_CB_SERVER_USERDB_SETPASS (0x8006)
+
+/* callback for a server-supplied user canonicalization function.
+ *
+ * This function is called directly after the mechanism has the
+ * authentication and authorization IDs. It is called before any
+ * User Canonicalization plugin is called. It has the responsibility
+ * of copying its output into the provided output buffers.
+ *
+ * in, inlen -- user name to canonicalize, may not be NUL terminated
+ * may be same buffer as out
+ * flags -- not currently used, supplied by auth mechanism
+ * user_realm -- the user realm (may be NULL in case of client)
+ * out -- buffer to copy user name
+ * out_max -- max length of user name
+ * out_len -- set to length of user name
+ *
+ * returns
+ * SASL_OK on success
+ * SASL_BADPROT username contains invalid character
+ */
+
+/* User Canonicalization Function Flags */
+
+#define SASL_CU_NONE 0x00 /* Not a valid flag to pass */
+/* One of the following two is required */
+#define SASL_CU_AUTHID 0x01
+#define SASL_CU_AUTHZID 0x02
+
+/* Combine the following with SASL_CU_AUTHID, if you don't want
+ to fail if auxprop returned SASL_NOUSER/SASL_NOMECH. */
+#define SASL_CU_EXTERNALLY_VERIFIED 0x04
+
+#define SASL_CU_OVERRIDE 0x08 /* mapped to SASL_AUXPROP_OVERRIDE */
+
+/* The following CU flags are passed "as is" down to auxprop lookup */
+#define SASL_CU_ASIS_MASK 0xFFF0
+/* NOTE: Keep in sync with SASL_AUXPROP_<XXX> flags */
+#define SASL_CU_VERIFY_AGAINST_HASH 0x10
+
+
+typedef int sasl_canon_user_t(sasl_conn_t *conn,
+ void *context,
+ const char *in, unsigned inlen,
+ unsigned flags,
+ const char *user_realm,
+ char *out,
+ unsigned out_max, unsigned *out_len);
+
+#define SASL_CB_CANON_USER (0x8007)
+
+/**********************************
+ * Common Client/server functions *
+ **********************************/
+
+/* Types of paths to set (see sasl_set_path below). */
+#define SASL_PATH_TYPE_PLUGIN 0
+#define SASL_PATH_TYPE_CONFIG 1
+
+/* a simpler way to set plugin path or configuration file path
+ * without the need to set sasl_getpath_t callback.
+ *
+ * This function can be called before sasl_server_init/sasl_client_init.
+ */
+LIBSASL_API int sasl_set_path (int path_type, char * path);
+
+/* get sasl library version information
+ * implementation is a vendor-defined string
+ * version is a vender-defined representation of the version #.
+ *
+ * This function is being deprecated in favor of sasl_version_info. */
+LIBSASL_API void sasl_version(const char **implementation,
+ int *version);
+
+/* Extended version of sasl_version().
+ *
+ * This function is to be used
+ * for library version display and logging
+ * for bug workarounds in old library versions
+ *
+ * The sasl_version_info is not to be used for API feature detection.
+ *
+ * All parameters are optional. If NULL is specified, the value is not returned.
+ */
+LIBSASL_API void sasl_version_info (const char **implementation,
+ const char **version_string,
+ int *version_major,
+ int *version_minor,
+ int *version_step,
+ int *version_patch);
+
+/* dispose of all SASL plugins. Connection
+ * states have to be disposed of before calling this.
+ *
+ * This function is DEPRECATED in favour of sasl_server_done/
+ * sasl_client_done.
+ */
+LIBSASL_API void sasl_done(void);
+
+/* dispose of all SASL plugins. Connection
+ * states have to be disposed of before calling this.
+ * This function should be called instead of sasl_done(),
+ whenever possible.
+ */
+LIBSASL_API int sasl_server_done(void);
+
+/* dispose of all SASL plugins. Connection
+ * states have to be disposed of before calling this.
+ * This function should be called instead of sasl_done(),
+ whenever possible.
+ */
+LIBSASL_API int sasl_client_done(void);
+
+/* dispose connection state, sets it to NULL
+ * checks for pointer to NULL
+ */
+LIBSASL_API void sasl_dispose(sasl_conn_t **pconn);
+
+/* translate an error number into a string
+ * input:
+ * saslerr -- the error number
+ * langlist -- comma separated list of RFC 1766 languages (may be NULL)
+ * results:
+ * outlang -- the language actually used (may be NULL if don't care)
+ * returns:
+ * the error message in UTF-8 (only the US-ASCII subset if langlist is NULL)
+ */
+LIBSASL_API const char *sasl_errstring(int saslerr,
+ const char *langlist,
+ const char **outlang);
+
+/* get detail about the last error that occurred on a connection
+ * text is sanitized so it's suitable to send over the wire
+ * (e.g., no distinction between SASL_BADAUTH and SASL_NOUSER)
+ * input:
+ * conn -- mandatory connection context
+ * returns:
+ * the error message in UTF-8 (only the US-ASCII subset permitted if no
+ * SASL_CB_LANGUAGE callback is present)
+ */
+LIBSASL_API const char *sasl_errdetail(sasl_conn_t *conn);
+
+/* set the error string which will be returned by sasl_errdetail() using
+ * syslog()-style formatting (e.g. printf-style with %m as most recent
+ * errno error)
+ *
+ * primarily for use by server callbacks such as the sasl_authorize_t
+ * callback and internally to plug-ins
+ *
+ * This will also trigger a call to the SASL logging callback (if any)
+ * with a level of SASL_LOG_FAIL unless the SASL_NOLOG flag is set.
+ *
+ * Messages should be sensitive to the current language setting. If there
+ * is no SASL_CB_LANGUAGE callback messages MUST be US-ASCII otherwise UTF-8
+ * is used and use of RFC 2482 for mixed-language text is encouraged.
+ *
+ * if conn is NULL, function does nothing
+ */
+LIBSASL_API void sasl_seterror(sasl_conn_t *conn, unsigned flags,
+ const char *fmt, ...);
+#define SASL_NOLOG 0x01
+
+/* get property from SASL connection state
+ * propnum -- property number
+ * pvalue -- pointer to value
+ * returns:
+ * SASL_OK -- no error
+ * SASL_NOTDONE -- property not available yet
+ * SASL_BADPARAM -- bad property number
+ */
+LIBSASL_API int sasl_getprop(sasl_conn_t *conn, int propnum,
+ const void **pvalue);
+#define SASL_USERNAME 0 /* pointer to NUL terminated user name */
+#define SASL_SSF 1 /* security layer security strength factor,
+ * if 0, call to sasl_encode, sasl_decode
+ * unnecessary */
+#define SASL_MAXOUTBUF 2 /* security layer max output buf unsigned */
+#define SASL_DEFUSERREALM 3 /* default realm passed to server_new */
+ /* or set with setprop */
+#define SASL_GETOPTCTX 4 /* context for getopt callback */
+#define SASL_CALLBACK 7 /* current callback function list */
+#define SASL_IPLOCALPORT 8 /* iplocalport string passed to server_new */
+#define SASL_IPREMOTEPORT 9 /* ipremoteport string passed to server_new */
+
+/* This returns a string which is either empty or has an error message
+ * from sasl_seterror (e.g., from a plug-in or callback). It differs
+ * from the result of sasl_errdetail() which also takes into account the
+ * last return status code.
+ */
+#define SASL_PLUGERR 10
+
+/* a handle to any delegated credentials or NULL if none is present
+ * is returned by the mechanism. The user will probably need to know
+ * which mechanism was used to actually known how to make use of them
+ * currently only implemented for the gssapi mechanism */
+#define SASL_DELEGATEDCREDS 11
+
+#define SASL_SERVICE 12 /* service passed to sasl_*_new */
+#define SASL_SERVERFQDN 13 /* serverFQDN passed to sasl_*_new */
+#define SASL_AUTHSOURCE 14 /* name of auth source last used, useful
+ * for failed authentication tracking */
+#define SASL_MECHNAME 15 /* active mechanism name, if any */
+#define SASL_AUTHUSER 16 /* authentication/admin user */
+#define SASL_APPNAME 17 /* application name (used for logging/
+ configuration), same as appname parameter
+ to sasl_server_init */
+
+/* GSS-API credential handle for sasl_client_step() or sasl_server_step().
+ * The application is responsible for releasing this credential handle. */
+#define SASL_GSS_CREDS 18
+
+/* GSS name (gss_name_t) of the peer, as output by gss_inquire_context()
+ * or gss_accept_sec_context().
+ * On server end this is similar to SASL_USERNAME, but the gss_name_t
+ * structure can contain additional attributes associated with the peer.
+ */
+#define SASL_GSS_PEER_NAME 19
+
+/* Local GSS name (gss_name_t) as output by gss_inquire_context(). This
+ * is particularly useful for servers that respond to multiple names. */
+#define SASL_GSS_LOCAL_NAME 20
+
+/* Channel binding information. Memory is managed by the caller. */
+typedef struct sasl_channel_binding {
+ const char *name;
+ int critical;
+ unsigned long len;
+ const unsigned char *data;
+} sasl_channel_binding_t;
+
+#define SASL_CHANNEL_BINDING 21
+
+/* HTTP Request (RFC 2616) - ONLY used for HTTP Digest Auth (RFC 2617) */
+typedef struct sasl_http_request {
+ const char *method; /* HTTP Method */
+ const char *uri; /* request-URI */
+ const unsigned char *entity; /* entity-body */
+ unsigned long elen; /* entity-body length */
+ unsigned non_persist; /* Is it a non-persistent connection? */
+} sasl_http_request_t;
+
+#define SASL_HTTP_REQUEST 22
+
+/* set property in SASL connection state
+ * returns:
+ * SASL_OK -- value set
+ * SASL_BADPARAM -- invalid property or value
+ */
+LIBSASL_API int sasl_setprop(sasl_conn_t *conn,
+ int propnum,
+ const void *value);
+#define SASL_SSF_EXTERNAL 100 /* external SSF active (sasl_ssf_t *) */
+#define SASL_SEC_PROPS 101 /* sasl_security_properties_t */
+#define SASL_AUTH_EXTERNAL 102 /* external authentication ID (const char *) */
+
+/* If the SASL_AUTH_EXTERNAL value is non-NULL, then a special version of the
+ * EXTERNAL mechanism is enabled (one for server-embedded EXTERNAL mechanisms).
+ * Otherwise, the EXTERNAL mechanism will be absent unless a plug-in
+ * including EXTERNAL is present.
+ */
+
+/* do precalculations during an idle period or network round trip
+ * may pass NULL to precompute for some mechanisms prior to connect
+ * returns 1 if action taken, 0 if no action taken
+ */
+LIBSASL_API int sasl_idle(sasl_conn_t *conn);
+
+/**************
+ * Client API *
+ **************/
+
+/* list of client interactions with user for caller to fill in
+ */
+typedef struct sasl_interact {
+ unsigned long id; /* same as client/user callback ID */
+ const char *challenge; /* presented to user (e.g. OTP challenge) */
+ const char *prompt; /* presented to user (e.g. "Username: ") */
+ const char *defresult; /* default result string */
+ const void *result; /* set to point to result */
+ unsigned len; /* set to length of result */
+} sasl_interact_t;
+
+/* initialize the SASL client drivers
+ * callbacks -- base callbacks for all client connections;
+ * must include getopt callback
+ * returns:
+ * SASL_OK -- Success
+ * SASL_NOMEM -- Not enough memory
+ * SASL_BADVERS -- Mechanism version mismatch
+ * SASL_BADPARAM -- missing getopt callback or error in config file
+ * SASL_NOMECH -- No mechanisms available
+ * ...
+ */
+LIBSASL_API int sasl_client_init(const sasl_callback_t *callbacks);
+
+/* initialize a client exchange based on the specified mechanism
+ * service -- registered name of the service using SASL (e.g. "imap")
+ * serverFQDN -- the fully qualified domain name of the server
+ * iplocalport -- client IPv4/IPv6 domain literal string with port
+ * (if NULL, then mechanisms requiring IPaddr are disabled)
+ * ipremoteport -- server IPv4/IPv6 domain literal string with port
+ * (if NULL, then mechanisms requiring IPaddr are disabled)
+ * prompt_supp -- list of client interactions supported
+ * may also include sasl_getopt_t context & call
+ * NULL prompt_supp = user/pass via SASL_INTERACT only
+ * NULL proc = interaction supported via SASL_INTERACT
+ * flags -- server usage flags (see above)
+ * in/out:
+ * pconn -- connection negotiation structure
+ * pointer to NULL => allocate new
+ *
+ * Returns:
+ * SASL_OK -- success
+ * SASL_NOMECH -- no mechanism meets requested properties
+ * SASL_NOMEM -- not enough memory
+ */
+LIBSASL_API int sasl_client_new(const char *service,
+ const char *serverFQDN,
+ const char *iplocalport,
+ const char *ipremoteport,
+ const sasl_callback_t *prompt_supp,
+ unsigned flags,
+ sasl_conn_t **pconn);
+
+/* select a mechanism for a connection
+ * mechlist -- mechanisms server has available (punctuation ignored)
+ * if NULL, then discard cached info and retry last mech
+ * output:
+ * prompt_need -- on SASL_INTERACT, list of prompts needed to continue
+ * may be NULL if callbacks provided
+ * clientout -- the initial client response to send to the server
+ * will be valid until next call to client_start/client_step
+ * NULL if mech doesn't include initial client challenge
+ * mech -- set to mechansm name of selected mechanism (may be NULL)
+ *
+ * Returns:
+ * SASL_OK -- success
+ * SASL_NOMEM -- not enough memory
+ * SASL_NOMECH -- no mechanism meets requested properties
+ * SASL_INTERACT -- user interaction needed to fill in prompt_need list
+ */
+LIBSASL_API int sasl_client_start(sasl_conn_t *conn,
+ const char *mechlist,
+ sasl_interact_t **prompt_need,
+ const char **clientout,
+ unsigned *clientoutlen,
+ const char **mech);
+
+/* do a single authentication step.
+ * serverin -- the server message received by the client, MUST have a NUL
+ * sentinel, not counted by serverinlen
+ * output:
+ * prompt_need -- on SASL_INTERACT, list of prompts needed to continue
+ * clientout -- the client response to send to the server
+ * will be valid until next call to client_start/client_step
+ *
+ * returns:
+ * SASL_OK -- success
+ * SASL_INTERACT -- user interaction needed to fill in prompt_need list
+ * SASL_BADPROT -- server protocol incorrect/cancelled
+ * SASL_BADSERV -- server failed mutual auth
+ */
+LIBSASL_API int sasl_client_step(sasl_conn_t *conn,
+ const char *serverin,
+ unsigned serverinlen,
+ sasl_interact_t **prompt_need,
+ const char **clientout,
+ unsigned *clientoutlen);
+
+/**************
+ * Server API *
+ **************/
+
+/* initialize server drivers, done once per process
+ * callbacks -- callbacks for all server connections; must include
+ * getopt callback
+ * appname -- name of calling application (for lower level logging)
+ * results:
+ * state -- server state
+ * returns:
+ * SASL_OK -- success
+ * SASL_BADPARAM -- error in config file
+ * SASL_NOMEM -- memory failure
+ * SASL_BADVERS -- Mechanism version mismatch
+ */
+LIBSASL_API int sasl_server_init(const sasl_callback_t *callbacks,
+ const char *appname);
+
+/* IP/port syntax:
+ * a.b.c.d;p where a-d are 0-255 and p is 0-65535 port number.
+ * e:f:g:h:i:j:k:l;p where e-l are 0000-ffff lower-case hexidecimal
+ * e:f:g:h:i:j:a.b.c.d;p alternate syntax for previous
+ *
+ * Note that one or more "0" fields in f-k can be replaced with "::"
+ * Thus: e:f:0000:0000:0000:j:k:l;p
+ * can be abbreviated: e:f::j:k:l;p
+ *
+ * A buffer of size 52 is adequate for the longest format with NUL terminator.
+ */
+
+/* create context for a single SASL connection
+ * service -- registered name of the service using SASL (e.g. "imap")
+ * serverFQDN -- Fully qualified domain name of server. NULL means use
+ * gethostname() or equivalent.
+ * Useful for multi-homed servers.
+ * user_realm -- permits multiple user realms on server, NULL = default
+ * iplocalport -- server IPv4/IPv6 domain literal string with port
+ * (if NULL, then mechanisms requiring IPaddr are disabled)
+ * ipremoteport -- client IPv4/IPv6 domain literal string with port
+ * (if NULL, then mechanisms requiring IPaddr are disabled)
+ * callbacks -- callbacks (e.g., authorization, lang, new getopt context)
+ * flags -- usage flags (see above)
+ * returns:
+ * pconn -- new connection context
+ *
+ * returns:
+ * SASL_OK -- success
+ * SASL_NOMEM -- not enough memory
+ */
+LIBSASL_API int sasl_server_new(const char *service,
+ const char *serverFQDN,
+ const char *user_realm,
+ const char *iplocalport,
+ const char *ipremoteport,
+ const sasl_callback_t *callbacks,
+ unsigned flags,
+ sasl_conn_t **pconn);
+
+/* Return an array of NUL-terminated strings, terminated by a NULL pointer,
+ * which lists all possible mechanisms that the library can supply
+ *
+ * Returns NULL on failure. */
+LIBSASL_API const char ** sasl_global_listmech(void);
+
+/* This returns a list of mechanisms in a NUL-terminated string
+ * conn -- the connection to list mechanisms for (either client
+ * or server)
+ * user -- restricts mechanisms to those available to that user
+ * (may be NULL, not used for client case)
+ * prefix -- appended to beginning of result
+ * sep -- appended between mechanisms
+ * suffix -- appended to end of result
+ * results:
+ * result -- NUL terminated result which persists until next
+ * call to sasl_listmech for this sasl_conn_t
+ * plen -- gets length of result (excluding NUL), may be NULL
+ * pcount -- gets number of mechanisms, may be NULL
+ *
+ * returns:
+ * SASL_OK -- success
+ * SASL_NOMEM -- not enough memory
+ * SASL_NOMECH -- no enabled mechanisms
+ */
+LIBSASL_API int sasl_listmech(sasl_conn_t *conn,
+ const char *user,
+ const char *prefix,
+ const char *sep,
+ const char *suffix,
+ const char **result,
+ unsigned *plen,
+ int *pcount);
+
+/* start a mechanism exchange within a connection context
+ * mech -- the mechanism name client requested
+ * clientin -- client initial response (NUL terminated), NULL if empty
+ * clientinlen -- length of initial response
+ * serverout -- initial server challenge, NULL if done
+ * (library handles freeing this string)
+ * serveroutlen -- length of initial server challenge
+ * output:
+ * pconn -- the connection negotiation state on success
+ *
+ * Same returns as sasl_server_step() or
+ * SASL_NOMECH if mechanism not available.
+ */
+LIBSASL_API int sasl_server_start(sasl_conn_t *conn,
+ const char *mech,
+ const char *clientin,
+ unsigned clientinlen,
+ const char **serverout,
+ unsigned *serveroutlen);
+
+/* perform one step of the SASL exchange
+ * inputlen & input -- client data
+ * NULL on first step if no optional client step
+ * outputlen & output -- set to the server data to transmit
+ * to the client in the next step
+ * (library handles freeing this)
+ *
+ * returns:
+ * SASL_OK -- exchange is complete.
+ * SASL_CONTINUE -- indicates another step is necessary.
+ * SASL_TRANS -- entry for user exists, but not for mechanism
+ * and transition is possible
+ * SASL_BADPARAM -- service name needed
+ * SASL_BADPROT -- invalid input from client
+ * ...
+ */
+LIBSASL_API int sasl_server_step(sasl_conn_t *conn,
+ const char *clientin,
+ unsigned clientinlen,
+ const char **serverout,
+ unsigned *serveroutlen);
+
+/* check if an apop exchange is valid
+ * (note this is an optional part of the SASL API)
+ * if challenge is NULL, just check if APOP is enabled
+ * inputs:
+ * challenge -- challenge which was sent to client
+ * challen -- length of challenge, 0 = strlen(challenge)
+ * response -- client response, "<user> <digest>" (RFC 1939)
+ * resplen -- length of response, 0 = strlen(response)
+ * returns
+ * SASL_OK -- success
+ * SASL_BADAUTH -- authentication failed
+ * SASL_BADPARAM -- missing challenge
+ * SASL_BADPROT -- protocol error (e.g., response in wrong format)
+ * SASL_NOVERIFY -- user found, but no verifier
+ * SASL_NOMECH -- mechanism not supported
+ * SASL_NOUSER -- user not found
+ */
+LIBSASL_API int sasl_checkapop(sasl_conn_t *conn,
+ const char *challenge, unsigned challen,
+ const char *response, unsigned resplen);
+
+/* check if a plaintext password is valid
+ * if user is NULL, check if plaintext passwords are enabled
+ * inputs:
+ * user -- user to query in current user_domain
+ * userlen -- length of username, 0 = strlen(user)
+ * pass -- plaintext password to check
+ * passlen -- length of password, 0 = strlen(pass)
+ * returns
+ * SASL_OK -- success
+ * SASL_NOMECH -- mechanism not supported
+ * SASL_NOVERIFY -- user found, but no verifier
+ * SASL_NOUSER -- user not found
+ */
+LIBSASL_API int sasl_checkpass(sasl_conn_t *conn,
+ const char *user, unsigned userlen,
+ const char *pass, unsigned passlen);
+
+/* check if a user exists on server
+ * conn -- connection context
+ * service -- registered name of the service using SASL (e.g. "imap")
+ * user_realm -- permits multiple user realms on server, NULL = default
+ * user -- NUL terminated user name
+ *
+ * returns:
+ * SASL_OK -- success
+ * SASL_DISABLED -- account disabled
+ * SASL_NOUSER -- user not found
+ * SASL_NOVERIFY -- user found, but no usable mechanism
+ * SASL_NOMECH -- no mechanisms enabled
+ * SASL_UNAVAIL -- remote authentication server unavailable, try again later
+ */
+LIBSASL_API int sasl_user_exists(sasl_conn_t *conn,
+ const char *service,
+ const char *user_realm,
+ const char *user);
+
+/* set the password for a user
+ * conn -- SASL connection
+ * user -- user name
+ * pass -- plaintext password, may be NULL to remove user
+ * passlen -- length of password, 0 = strlen(pass)
+ * oldpass -- NULL will sometimes work
+ * oldpasslen -- length of password, 0 = strlen(oldpass)
+ * flags -- see flags below
+ *
+ * returns:
+ * SASL_NOCHANGE -- proper entry already exists
+ * SASL_NOMECH -- no authdb supports password setting as configured
+ * SASL_NOVERIFY -- user exists, but no settable password present
+ * SASL_DISABLED -- account disabled
+ * SASL_PWLOCK -- password locked
+ * SASL_WEAKPASS -- password too weak for security policy
+ * SASL_NOUSERPASS -- user-supplied passwords not permitted
+ * SASL_FAIL -- OS error
+ * SASL_BADPARAM -- password too long
+ * SASL_OK -- successful
+ */
+LIBSASL_API int sasl_setpass(sasl_conn_t *conn,
+ const char *user,
+ const char *pass, unsigned passlen,
+ const char *oldpass, unsigned oldpasslen,
+ unsigned flags);
+#define SASL_SET_CREATE 0x01 /* create a new entry for user */
+#define SASL_SET_DISABLE 0x02 /* disable user account */
+#define SASL_SET_NOPLAIN 0x04 /* do not store secret in plain text */
+#define SASL_SET_CURMECH_ONLY 0x08 /* set the mechanism specific password only.
+ fail if no current mechanism */
+
+/*********************************************************
+ * Auxiliary Property Support -- added by cjn 1999-09-29 *
+ *********************************************************/
+
+#define SASL_AUX_END NULL /* last auxiliary property */
+
+#define SASL_AUX_ALL "*" /* A special flag to signal user deletion */
+
+/* traditional Posix items (should be implemented on Posix systems) */
+#define SASL_AUX_PASSWORD_PROP "userPassword" /* User Password */
+#define SASL_AUX_PASSWORD "*" SASL_AUX_PASSWORD_PROP /* User Password (of authid) */
+#define SASL_AUX_UIDNUM "uidNumber" /* UID number for the user */
+#define SASL_AUX_GIDNUM "gidNumber" /* GID for the user */
+#define SASL_AUX_FULLNAME "gecos" /* full name of the user, unix-style */
+#define SASL_AUX_HOMEDIR "homeDirectory" /* home directory for user */
+#define SASL_AUX_SHELL "loginShell" /* login shell for the user */
+
+/* optional additional items (not necessarily implemented) */
+/* single preferred mail address for user canonically-quoted
+ * RFC821/822 syntax */
+#define SASL_AUX_MAILADDR "mail"
+/* path to unix-style mailbox for user */
+#define SASL_AUX_UNIXMBX "mailMessageStore"
+/* SMTP mail channel name to use if user authenticates successfully */
+#define SASL_AUX_MAILCHAN "mailSMTPSubmitChannel"
+
+/* Request a set of auxiliary properties
+ * conn connection context
+ * propnames list of auxiliary property names to request ending with
+ * NULL.
+ *
+ * Subsequent calls will add items to the request list. Call with NULL
+ * to clear the request list.
+ *
+ * errors
+ * SASL_OK -- success
+ * SASL_BADPARAM -- bad count/conn parameter
+ * SASL_NOMEM -- out of memory
+ */
+LIBSASL_API int sasl_auxprop_request(sasl_conn_t *conn,
+ const char **propnames);
+
+/* Returns current auxiliary property context.
+ * Use functions in prop.h to access content
+ *
+ * if authentication hasn't completed, property values may be empty/NULL
+ *
+ * properties not recognized by active plug-ins will be left empty/NULL
+ *
+ * returns NULL if conn is invalid.
+ */
+LIBSASL_API struct propctx *sasl_auxprop_getctx(sasl_conn_t *conn);
+
+/* Store the set of auxiliary properties for the given user.
+ * Use functions in prop.h to set the content.
+ *
+ * conn connection context
+ * ctx property context from prop_new()/prop_request()/prop_set()
+ * user NUL terminated user
+ *
+ * Call with NULL 'ctx' to see if the backend allows storing properties.
+ *
+ * errors
+ * SASL_OK -- success
+ * SASL_NOMECH -- can not store some/all properties
+ * SASL_BADPARAM -- bad conn/ctx/user parameter
+ * SASL_NOMEM -- out of memory
+ * SASL_FAIL -- failed to store
+ */
+LIBSASL_API int sasl_auxprop_store(sasl_conn_t *conn,
+ struct propctx *ctx, const char *user);
+
+/**********************
+ * security layer API *
+ **********************/
+
+/* encode a block of data for transmission using security layer,
+ * returning the input buffer if there is no security layer.
+ * output is only valid until next call to sasl_encode or sasl_encodev
+ * returns:
+ * SASL_OK -- success (returns input if no layer negotiated)
+ * SASL_NOTDONE -- security layer negotiation not finished
+ * SASL_BADPARAM -- inputlen is greater than the SASL_MAXOUTBUF
+ */
+LIBSASL_API int sasl_encode(sasl_conn_t *conn,
+ const char *input, unsigned inputlen,
+ const char **output, unsigned *outputlen);
+
+/* encode a block of data for transmission using security layer
+ * output is only valid until next call to sasl_encode or sasl_encodev
+ * returns:
+ * SASL_OK -- success (returns input if no layer negotiated)
+ * SASL_NOTDONE -- security layer negotiation not finished
+ * SASL_BADPARAM -- input length is greater than the SASL_MAXOUTBUF
+ * or no security layer
+ */
+LIBSASL_API int sasl_encodev(sasl_conn_t *conn,
+ const struct iovec *invec, unsigned numiov,
+ const char **output, unsigned *outputlen);
+
+/* decode a block of data received using security layer
+ * returning the input buffer if there is no security layer.
+ * output is only valid until next call to sasl_decode
+ *
+ * if outputlen is 0 on return, than the value of output is undefined.
+ *
+ * returns:
+ * SASL_OK -- success (returns input if no layer negotiated)
+ * SASL_NOTDONE -- security layer negotiation not finished
+ * SASL_BADMAC -- bad message integrity check
+ */
+LIBSASL_API int sasl_decode(sasl_conn_t *conn,
+ const char *input, unsigned inputlen,
+ const char **output, unsigned *outputlen);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SASL_H */
diff --git a/contrib/libs/sasl/include/sasl/prop.h b/contrib/libs/sasl/include/sasl/prop.h
new file mode 100644
index 0000000000..bf091d67d8
--- /dev/null
+++ b/contrib/libs/sasl/include/sasl/prop.h
@@ -0,0 +1,170 @@
+/* prop.h -- property request/response management routines
+ *
+ * Author: Chris Newman
+ * Removal of implementation-specific details by: Rob Siemborski
+ *
+ * This is intended to be used to create a list of properties to request,
+ * and _then_ request values for all properties. Any change to the request
+ * list will discard any existing values. This assumption allows a very
+ * efficient and simple memory model. This was designed for SASL API auxiliary
+ * property support, but would be fine for other contexts where this property
+ * model is appropriate.
+ *
+ * The "struct propctx" is allocated by prop_new and is a fixed size structure.
+ * If a prop_init() call were added, it would be reasonable to embed a "struct
+ * propctx" in another structure. prop_new also allocates a pool of memory
+ * (in the vbase field) which will be used for an array of "struct propval"
+ * to list all the requested properties.
+ *
+ * Properties may be multi-valued.
+ */
+
+#ifndef PROP_H
+#define PROP_H 1
+
+/* The following ifdef block is the standard way of creating macros
+ * which make exporting from a DLL simpler. All files within this DLL
+ * are compiled with the LIBSASL_EXPORTS symbol defined on the command
+ * line. this symbol should not be defined on any project that uses
+ * this DLL. This way any other project whose source files include
+ * this file see LIBSASL_API functions as being imported from a DLL,
+ * wheras this DLL sees symbols defined with this macro as being
+ * exported. */
+/* Under Unix, life is simpler: we just need to mark library functions
+ * as extern. (Technically, we don't even have to do that.) */
+# define LIBSASL_API extern
+
+/* Same as above, but used during a variable declaration. */
+# define LIBSASL_VAR extern
+
+/* the resulting structure for property values
+ */
+struct propval {
+ const char *name; /* name of property; NULL = end of list */
+ /* same pointer used in request will be used here */
+ const char **values; /* list of strings, values == NULL if property not
+ * found, *values == NULL if property found with
+ * no values */
+ unsigned nvalues; /* total number of value strings */
+ unsigned valsize; /* total size in characters of all value strings */
+};
+
+/*
+ * private internal structure
+ */
+#define PROP_DEFAULT 4 /* default number of propvals to assume */
+struct propctx;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* create a property context
+ * estimate -- an estimate of the storage needed for requests & responses
+ * 0 will use module default
+ * returns a new property context on success and NULL on any error
+ */
+LIBSASL_API struct propctx *prop_new(unsigned estimate);
+
+/* create new propctx which duplicates the contents of an existing propctx
+ * returns SASL_OK on success
+ * possible other return values include: SASL_NOMEM, SASL_BADPARAM
+ */
+LIBSASL_API int prop_dup(struct propctx *src_ctx, struct propctx **dst_ctx);
+
+/* Add property names to request
+ * ctx -- context from prop_new()
+ * names -- list of property names; must persist until context freed
+ * or requests cleared (This extends to other contexts that
+ * are dup'ed from this one, and their children, etc)
+ *
+ * NOTE: may clear values from context as side-effect
+ * returns SASL_OK on success
+ * possible other return values include: SASL_NOMEM, SASL_BADPARAM
+ */
+LIBSASL_API int prop_request(struct propctx *ctx, const char **names);
+
+/* return array of struct propval from the context
+ * return value persists until next call to
+ * prop_request, prop_clear or prop_dispose on context
+ *
+ * returns NULL on error
+ */
+LIBSASL_API const struct propval *prop_get(struct propctx *ctx);
+
+/* Fill in an array of struct propval based on a list of property names
+ * return value persists until next call to
+ * prop_request, prop_clear or prop_dispose on context
+ * returns number of matching properties which were found (values != NULL)
+ * if a name requested here was never requested by a prop_request, then
+ * the name field of the associated vals entry will be set to NULL
+ *
+ * The vals array MUST be atleast as long as the names array.
+ *
+ * returns # of matching properties on success
+ * possible other return values include: SASL_BADPARAM
+ */
+LIBSASL_API int prop_getnames(struct propctx *ctx, const char **names,
+ struct propval *vals);
+
+/* clear values and optionally requests from property context
+ * ctx -- property context
+ * requests -- 0 = don't clear requests, 1 = clear requests
+ */
+LIBSASL_API void prop_clear(struct propctx *ctx, int requests);
+
+/* erase the value of a property
+ */
+LIBSASL_API void prop_erase(struct propctx *ctx, const char *name);
+
+/* dispose of property context
+ * ctx -- is disposed and set to NULL; noop if ctx or *ctx is NULL
+ */
+LIBSASL_API void prop_dispose(struct propctx **ctx);
+
+
+/****fetcher interfaces****/
+
+/* format the requested property names into a string
+ * ctx -- context from prop_new()/prop_request()
+ * sep -- separator between property names (unused if none requested)
+ * seplen -- length of separator, if < 0 then strlen(sep) will be used
+ * outbuf -- output buffer
+ * outmax -- maximum length of output buffer including NUL terminator
+ * outlen -- set to length of output string excluding NUL terminator
+ * returns SASL_OK on success
+ * returns SASL_BADPARAM or amount of additional space needed on failure
+ */
+LIBSASL_API int prop_format(struct propctx *ctx, const char *sep, int seplen,
+ char *outbuf, unsigned outmax, unsigned *outlen);
+
+/* add a property value to the context
+ * ctx -- context from prop_new()/prop_request()
+ * name -- name of property to which value will be added
+ * if NULL, add to the same name as previous prop_set/setvals call
+ * value -- a value for the property; will be copied into context
+ * if NULL, remove existing values
+ * vallen -- length of value, if <= 0 then strlen(value) will be used
+ * returns SASL_OK on success
+ * possible error return values include: SASL_BADPARAM, SASL_NOMEM
+ */
+LIBSASL_API int prop_set(struct propctx *ctx, const char *name,
+ const char *value, int vallen);
+
+/* set the values for a property
+ * ctx -- context from prop_new()/prop_request()
+ * name -- name of property to which value will be added
+ * if NULL, add to the same name as previous prop_set/setvals call
+ * values -- array of values, ending in NULL. Each value is a NUL terminated
+ * string
+ * returns SASL_OK on success
+ * possible error return values include: SASL_BADPARAM, SASL_NOMEM
+ */
+LIBSASL_API int prop_setvals(struct propctx *ctx, const char *name,
+ const char **values);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PROP_H */
diff --git a/contrib/libs/sasl/include/sasl/sasl.h b/contrib/libs/sasl/include/sasl/sasl.h
new file mode 100644
index 0000000000..dc04ca4714
--- /dev/null
+++ b/contrib/libs/sasl/include/sasl/sasl.h
@@ -0,0 +1,1332 @@
+/* This is a proposed C API for support of SASL
+ *
+ *********************************IMPORTANT*******************************
+ * send email to chris.newman@innosoft.com and cyrus-bugs@andrew.cmu.edu *
+ * if you need to add new error codes, callback types, property values, *
+ * etc. It is important to keep the multiple implementations of this *
+ * API from diverging. *
+ *********************************IMPORTANT*******************************
+ *
+ * Basic Type Summary:
+ * sasl_conn_t Context for a SASL connection negotiation
+ * sasl_ssf_t Security layer Strength Factor
+ * sasl_callback_t A typed client/server callback function and context
+ * sasl_interact_t A client interaction descriptor
+ * sasl_secret_t A client password
+ * sasl_rand_t Random data context structure
+ * sasl_security_properties_t An application's required security level
+ *
+ * Callbacks:
+ * sasl_getopt_t client/server: Get an option value
+ * sasl_logmsg_t client/server: Log message handler
+ * sasl_getsimple_t client: Get user/language list
+ * sasl_getsecret_t client: Get authentication secret
+ * sasl_chalprompt_t client: Display challenge and prompt for response
+ *
+ * Server only Callbacks:
+ * sasl_authorize_t user authorization policy callback
+ * sasl_getconfpath_t get path to search for config file
+ * sasl_server_userdb_checkpass check password and auxprops in userdb
+ * sasl_server_userdb_setpass set password in userdb
+ * sasl_server_canon_user canonicalize username routine
+ *
+ * Client/Server Function Summary:
+ * sasl_done Release all SASL global state
+ * sasl_dispose Connection done: Dispose of sasl_conn_t
+ * sasl_getprop Get property (e.g., user name, security layer info)
+ * sasl_setprop Set property (e.g., external ssf)
+ * sasl_errdetail Generate string from last error on connection
+ * sasl_errstring Translate sasl error code to a string
+ * sasl_encode Encode data to send using security layer
+ * sasl_decode Decode data received using security layer
+ *
+ * Utility functions:
+ * sasl_encode64 Encode data to send using MIME base64 encoding
+ * sasl_decode64 Decode data received using MIME base64 encoding
+ * sasl_erasebuffer Erase a buffer
+ *
+ * Client Function Summary:
+ * sasl_client_init Load and initialize client plug-ins (call once)
+ * sasl_client_new Initialize client connection context: sasl_conn_t
+ * sasl_client_start Select mechanism for connection
+ * sasl_client_step Perform one authentication step
+ *
+ * Server Function Summary
+ * sasl_server_init Load and initialize server plug-ins (call once)
+ * sasl_server_new Initialize server connection context: sasl_conn_t
+ * sasl_listmech Create list of available mechanisms
+ * sasl_server_start Begin an authentication exchange
+ * sasl_server_step Perform one authentication exchange step
+ * sasl_checkpass Check a plaintext passphrase
+ * sasl_checkapop Check an APOP challenge/response (uses pseudo "APOP"
+ * mechanism similar to CRAM-MD5 mechanism; optional)
+ * sasl_user_exists Check if user exists
+ * sasl_setpass Change a password or add a user entry
+ * sasl_auxprop_request Request auxiliary properties
+ * sasl_auxprop_getctx Get auxiliary property context for connection
+ * sasl_auxprop_store Store a set of auxiliary properties
+ *
+ * Basic client model:
+ * 1. client calls sasl_client_init() at startup to load plug-ins
+ * 2. when connection formed, call sasl_client_new()
+ * 3. once list of supported mechanisms received from server, client
+ * calls sasl_client_start(). goto 4a
+ * 4. client calls sasl_client_step()
+ * [4a. If SASL_INTERACT, fill in prompts and goto 4
+ * -- doesn't happen if callbacks provided]
+ * 4b. If SASL error, goto 7 or 3
+ * 4c. If SASL_OK, continue or goto 6 if last server response was success
+ * 5. send message to server, wait for response
+ * 5a. On data or success with server response, goto 4
+ * 5b. On failure goto 7 or 3
+ * 5c. On success with no server response continue
+ * 6. continue with application protocol until connection closes
+ * call sasl_getprop/sasl_encode/sasl_decode() if using security layer
+ * 7. call sasl_dispose(), may return to step 2
+ * 8. call sasl_done() when program terminates
+ *
+ * Basic Server model:
+ * 1. call sasl_server_init() at startup to load plug-ins
+ * 2. On connection, call sasl_server_new()
+ * 3. call sasl_listmech() and send list to client]
+ * 4. after client AUTH command, call sasl_server_start(), goto 5a
+ * 5. call sasl_server_step()
+ * 5a. If SASL_CONTINUE, output to client, wait response, repeat 5
+ * 5b. If SASL error, then goto 7
+ * 5c. If SASL_OK, move on
+ * 6. continue with application protocol until connection closes
+ * call sasl_getprop to get username
+ * call sasl_getprop/sasl_encode/sasl_decode() if using security layer
+ * 7. call sasl_dispose(), may return to step 2
+ * 8. call sasl_done() when program terminates
+ *
+ *************************************************
+ * IMPORTANT NOTE: server realms / username syntax
+ *
+ * If a user name contains a "@", then the rightmost "@" in the user name
+ * separates the account name from the realm in which this account is
+ * located. A single server may support multiple realms. If the
+ * server knows the realm at connection creation time (e.g., a server
+ * with multiple IP addresses tightly binds one address to a specific
+ * realm) then that realm must be passed in the user_realm field of
+ * the sasl_server_new call. If user_realm is non-empty and an
+ * unqualified user name is supplied, then the canon_user facility is
+ * expected to append "@" and user_realm to the user name. The canon_user
+ * facility may treat other characters such as "%" as equivalent to "@".
+ *
+ * If the server forbids the use of "@" in user names for other
+ * purposes, this simplifies security validation.
+ */
+
+#ifndef SASL_H
+#define SASL_H 1
+
+#include <stddef.h> /* For size_t */
+
+/* Keep in sync with win32/common.mak */
+#define SASL_VERSION_MAJOR 2
+#define SASL_VERSION_MINOR 1
+#define SASL_VERSION_STEP 28
+
+/* A convenience macro: same as was defined in the OpenLDAP LDAPDB */
+#define SASL_VERSION_FULL ((SASL_VERSION_MAJOR << 16) |\
+ (SASL_VERSION_MINOR << 8) | SASL_VERSION_STEP)
+
+#include "prop.h"
+
+/*************
+ * Basic API *
+ *************/
+
+/* SASL result codes: */
+#define SASL_CONTINUE 1 /* another step is needed in authentication */
+#define SASL_OK 0 /* successful result */
+#define SASL_FAIL -1 /* generic failure */
+#define SASL_NOMEM -2 /* memory shortage failure */
+#define SASL_BUFOVER -3 /* overflowed buffer */
+#define SASL_NOMECH -4 /* mechanism not supported */
+#define SASL_BADPROT -5 /* bad protocol / cancel */
+#define SASL_NOTDONE -6 /* can't request info until later in exchange */
+#define SASL_BADPARAM -7 /* invalid parameter supplied */
+#define SASL_TRYAGAIN -8 /* transient failure (e.g., weak key) */
+#define SASL_BADMAC -9 /* integrity check failed */
+#define SASL_NOTINIT -12 /* SASL library not initialized */
+ /* -- client only codes -- */
+#define SASL_INTERACT 2 /* needs user interaction */
+#define SASL_BADSERV -10 /* server failed mutual authentication step */
+#define SASL_WRONGMECH -11 /* mechanism doesn't support requested feature */
+ /* -- server only codes -- */
+#define SASL_BADAUTH -13 /* authentication failure */
+#define SASL_NOAUTHZ -14 /* authorization failure */
+#define SASL_TOOWEAK -15 /* mechanism too weak for this user */
+#define SASL_ENCRYPT -16 /* encryption needed to use mechanism */
+#define SASL_TRANS -17 /* One time use of a plaintext password will
+ enable requested mechanism for user */
+#define SASL_EXPIRED -18 /* passphrase expired, has to be reset */
+#define SASL_DISABLED -19 /* account disabled */
+#define SASL_NOUSER -20 /* user not found */
+#define SASL_BADVERS -23 /* version mismatch with plug-in */
+#define SASL_UNAVAIL -24 /* remote authentication server unavailable */
+#define SASL_NOVERIFY -26 /* user exists, but no verifier for user */
+ /* -- codes for password setting -- */
+#define SASL_PWLOCK -21 /* passphrase locked */
+#define SASL_NOCHANGE -22 /* requested change was not needed */
+#define SASL_WEAKPASS -27 /* passphrase is too weak for security policy */
+#define SASL_NOUSERPASS -28 /* user supplied passwords not permitted */
+#define SASL_NEED_OLD_PASSWD -29 /* sasl_setpass needs old password in order
+ to perform password change */
+#define SASL_CONSTRAINT_VIOLAT -30 /* a property can't be stored,
+ because of some constrains/policy violation */
+
+#define SASL_BADBINDING -32 /* channel binding failure */
+#define SASL_CONFIGERR -100 /* error when parsing configuration file */
+
+/* max size of a sasl mechanism name */
+#define SASL_MECHNAMEMAX 20
+
+#ifdef _WIN32
+/* Define to have the same layout as a WSABUF */
+#ifndef STRUCT_IOVEC_DEFINED
+#define STRUCT_IOVEC_DEFINED 1
+struct iovec {
+ long iov_len;
+ char *iov_base;
+};
+#endif
+#else
+struct iovec; /* Defined in OS headers */
+#endif
+
+
+/* per-connection SASL negotiation state for client or server
+ */
+typedef struct sasl_conn sasl_conn_t;
+
+/* Plain text password structure.
+ * len is the length of the password, data is the text.
+ */
+typedef struct sasl_secret {
+ unsigned long len;
+ unsigned char data[1]; /* variable sized */
+} sasl_secret_t;
+
+/* random data context structure
+ */
+typedef struct sasl_rand_s sasl_rand_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/****************************
+ * Configure Basic Services *
+ ****************************/
+
+/* the following functions are used to adjust how allocation and mutexes work
+ * they must be called before all other SASL functions:
+ */
+
+#include <sys/types.h>
+
+/* memory allocation functions which may optionally be replaced:
+ */
+typedef void *sasl_malloc_t(size_t);
+typedef void *sasl_calloc_t(size_t, size_t);
+typedef void *sasl_realloc_t(void *, size_t);
+typedef void sasl_free_t(void *);
+
+LIBSASL_API void sasl_set_alloc(sasl_malloc_t *,
+ sasl_calloc_t *,
+ sasl_realloc_t *,
+ sasl_free_t *);
+
+/* mutex functions which may optionally be replaced:
+ * sasl_mutex_alloc allocates a mutex structure
+ * sasl_mutex_lock blocks until mutex locked
+ * returns -1 on deadlock or parameter error
+ * returns 0 on success
+ * sasl_mutex_unlock unlocks mutex if it's locked
+ * returns -1 if not locked or parameter error
+ * returns 0 on success
+ * sasl_mutex_free frees a mutex structure
+ */
+typedef void *sasl_mutex_alloc_t(void);
+typedef int sasl_mutex_lock_t(void *mutex);
+typedef int sasl_mutex_unlock_t(void *mutex);
+typedef void sasl_mutex_free_t(void *mutex);
+LIBSASL_API void sasl_set_mutex(sasl_mutex_alloc_t *, sasl_mutex_lock_t *,
+ sasl_mutex_unlock_t *, sasl_mutex_free_t *);
+
+/*****************************
+ * Security preference types *
+ *****************************/
+
+/* security layer strength factor -- an unsigned integer usable by the caller
+ * to specify approximate security layer strength desired. Roughly
+ * correlated to effective key length for encryption.
+ * 0 = no protection
+ * 1 = integrity protection only
+ * 40 = 40-bit DES or 40-bit RC2/RC4
+ * 56 = DES
+ * 112 = triple-DES
+ * 128 = 128-bit RC2/RC4/BLOWFISH
+ * 256 = baseline AES
+ */
+typedef unsigned sasl_ssf_t;
+
+/* usage flags provided to sasl_server_new and sasl_client_new:
+ */
+#define SASL_SUCCESS_DATA 0x0004 /* server supports data on success */
+#define SASL_NEED_PROXY 0x0008 /* require a mech that allows proxying */
+#define SASL_NEED_HTTP 0x0010 /* require a mech that can do HTTP auth */
+
+/***************************
+ * Security Property Types *
+ ***************************/
+
+/* Structure specifying the client or server's security policy
+ * and optional additional properties.
+ */
+
+/* These are the various security flags apps can specify. */
+/* NOPLAINTEXT -- don't permit mechanisms susceptible to simple
+ * passive attack (e.g., PLAIN, LOGIN)
+ * NOACTIVE -- protection from active (non-dictionary) attacks
+ * during authentication exchange.
+ * Authenticates server.
+ * NODICTIONARY -- don't permit mechanisms susceptible to passive
+ * dictionary attack
+ * FORWARD_SECRECY -- require forward secrecy between sessions
+ * (breaking one won't help break next)
+ * NOANONYMOUS -- don't permit mechanisms that allow anonymous login
+ * PASS_CREDENTIALS -- require mechanisms which pass client
+ * credentials, and allow mechanisms which can pass
+ * credentials to do so
+ * MUTUAL_AUTH -- require mechanisms which provide mutual
+ * authentication
+ */
+#define SASL_SEC_NOPLAINTEXT 0x0001
+#define SASL_SEC_NOACTIVE 0x0002
+#define SASL_SEC_NODICTIONARY 0x0004
+#define SASL_SEC_FORWARD_SECRECY 0x0008
+#define SASL_SEC_NOANONYMOUS 0x0010
+#define SASL_SEC_PASS_CREDENTIALS 0x0020
+#define SASL_SEC_MUTUAL_AUTH 0x0040
+#define SASL_SEC_MAXIMUM 0xFFFF
+
+/* This is used when adding hash size to the security_flags field */
+/* NB: hash size is in bits */
+#define SASL_SET_HASH_STRENGTH_BITS(x) (((x) / 8) << 16)
+
+/* NB: This value is in bytes */
+#define SASL_GET_HASH_STRENGTH(x) ((x) >> 16)
+
+typedef struct sasl_security_properties
+{
+ /* security strength factor
+ * min_ssf = minimum acceptable final level
+ * max_ssf = maximum acceptable final level
+ */
+ sasl_ssf_t min_ssf;
+ sasl_ssf_t max_ssf;
+
+ /* Maximum security layer receive buffer size.
+ * 0=security layer not supported
+ */
+ unsigned maxbufsize;
+
+ /* bitfield for attacks to protect against */
+ unsigned security_flags;
+
+ /* NULL terminated array of additional property names, values */
+ const char **property_names;
+ const char **property_values;
+} sasl_security_properties_t;
+
+/******************
+ * Callback types *
+ ******************/
+
+/*
+ * Extensible type for a client/server callbacks
+ * id -- identifies callback type
+ * proc -- procedure call arguments vary based on id
+ * context -- context passed to procedure
+ */
+/* Note that any memory that is allocated by the callback needs to be
+ * freed by the application, be it via function call or interaction.
+ *
+ * It may be freed after sasl_*_step returns SASL_OK. if the mechanism
+ * requires this information to persist (for a security layer, for example)
+ * it must maintain a private copy.
+ */
+typedef struct sasl_callback {
+ /* Identifies the type of the callback function.
+ * Mechanisms must ignore callbacks with id's they don't recognize.
+ */
+ unsigned long id;
+ int (*proc)(void); /* Callback function. Types of arguments vary by 'id' */
+ void *context;
+} sasl_callback_t;
+
+/* callback ids & functions:
+ */
+#define SASL_CB_LIST_END 0 /* end of list */
+
+/* option reading callback -- this allows a SASL configuration to be
+ * encapsulated in the caller's configuration system. Some implementations
+ * may use default config file(s) if this is omitted. Configuration items
+ * may be plugin-specific and are arbitrary strings.
+ *
+ * inputs:
+ * context -- option context from callback record
+ * plugin_name -- name of plugin (NULL = general SASL option)
+ * option -- name of option
+ * output:
+ * result -- set to result which persists until next getopt in
+ * same thread, unchanged if option not found
+ * len -- length of result (may be NULL)
+ * returns:
+ * SASL_OK -- no error
+ * SASL_FAIL -- error
+ */
+typedef int sasl_getopt_t(void *context, const char *plugin_name,
+ const char *option,
+ const char **result, unsigned *len);
+#define SASL_CB_GETOPT 1
+
+/* Logging levels for use with the logging callback function. */
+#define SASL_LOG_NONE 0 /* don't log anything */
+#define SASL_LOG_ERR 1 /* log unusual errors (default) */
+#define SASL_LOG_FAIL 2 /* log all authentication failures */
+#define SASL_LOG_WARN 3 /* log non-fatal warnings */
+#define SASL_LOG_NOTE 4 /* more verbose than LOG_WARN */
+#define SASL_LOG_DEBUG 5 /* more verbose than LOG_NOTE */
+#define SASL_LOG_TRACE 6 /* traces of internal protocols */
+#define SASL_LOG_PASS 7 /* traces of internal protocols, including
+ * passwords */
+
+/* logging callback -- this allows plugins and the middleware to
+ * log operations they perform.
+ * inputs:
+ * context -- logging context from the callback record
+ * level -- logging level; see above
+ * message -- message to log
+ * returns:
+ * SASL_OK -- no error
+ * SASL_FAIL -- error
+ */
+typedef int sasl_log_t(void *context,
+ int level,
+ const char *message);
+#define SASL_CB_LOG 2
+
+/* getpath callback -- this allows applications to specify the
+ * colon-separated path to search for plugins (by default,
+ * taken from an implementation-specific location).
+ * inputs:
+ * context -- getpath context from the callback record
+ * outputs:
+ * path -- colon seperated path
+ * returns:
+ * SASL_OK -- no error
+ * SASL_FAIL -- error
+ */
+typedef int sasl_getpath_t(void *context,
+ const char **path);
+
+#define SASL_CB_GETPATH 3
+
+/* verify file callback -- this allows applications to check if they
+ * want SASL to use files, file by file. This is intended to allow
+ * applications to sanity check the environment to make sure plugins
+ * or the configuration file can't be written to, etc.
+ * inputs:
+ * context -- verifypath context from the callback record
+ * file -- full path to file to verify
+ * type -- type of file to verify (see below)
+
+ * returns:
+ * SASL_OK -- no error (file can safely be used)
+ * SASL_CONTINUE -- continue WITHOUT using this file
+ * SASL_FAIL -- error
+ */
+
+/* these are the types of files libsasl will ask about */
+typedef enum {
+ SASL_VRFY_PLUGIN=0, /* a DLL/shared library plug-in */
+ SASL_VRFY_CONF=1, /* a configuration file */
+ SASL_VRFY_PASSWD=2, /* a password storage file/db */
+ SASL_VRFY_OTHER=3 /* some other file */
+} sasl_verify_type_t;
+
+typedef int sasl_verifyfile_t(void *context,
+ const char *file, sasl_verify_type_t type);
+#define SASL_CB_VERIFYFILE 4
+
+/* getconfpath callback -- this allows applications to specify the
+ * colon-separated path to search for config files (by default,
+ * taken from the SASL_CONF_PATH environment variable).
+ * inputs:
+ * context -- getconfpath context from the callback record
+ * outputs:
+ * path -- colon seperated path (allocated on the heap; the
+ * library will free it using the sasl_free_t *
+ * passed to sasl_set_callback, or the standard free()
+ * library call).
+ * returns:
+ * SASL_OK -- no error
+ * SASL_FAIL -- error
+ */
+typedef int sasl_getconfpath_t(void *context,
+ char **path);
+
+#define SASL_CB_GETCONFPATH 5
+
+/* client/user interaction callbacks:
+ */
+/* Simple prompt -- result must persist until next call to getsimple on
+ * same connection or until connection context is disposed
+ * inputs:
+ * context -- context from callback structure
+ * id -- callback id
+ * outputs:
+ * result -- set to NUL terminated string
+ * NULL = user cancel
+ * len -- length of result
+ * returns SASL_OK
+ */
+typedef int sasl_getsimple_t(void *context, int id,
+ const char **result, unsigned *len);
+#define SASL_CB_USER 0x4001 /* client user identity to login as */
+#define SASL_CB_AUTHNAME 0x4002 /* client authentication name */
+#define SASL_CB_LANGUAGE 0x4003 /* comma separated list of RFC 1766
+ * language codes in order of preference
+ * to be used to localize client prompts
+ * or server error codes */
+#define SASL_CB_CNONCE 0x4007 /* caller supplies client-nonce
+ * primarily for testing purposes */
+
+/* get a sasl_secret_t (plaintext password with length)
+ * inputs:
+ * conn -- connection context
+ * context -- context from callback structure
+ * id -- callback id
+ * outputs:
+ * psecret -- set to NULL to cancel
+ * set to password structure which must persist until
+ * next call to getsecret in same connection, but middleware
+ * will erase password data when it's done with it.
+ * returns SASL_OK
+ */
+typedef int sasl_getsecret_t(sasl_conn_t *conn, void *context, int id,
+ sasl_secret_t **psecret);
+#define SASL_CB_PASS 0x4004 /* client passphrase-based secret */
+
+
+/* prompt for input in response to a challenge.
+ * input:
+ * context -- context from callback structure
+ * id -- callback id
+ * challenge -- server challenge
+ * output:
+ * result -- NUL terminated result, NULL = user cancel
+ * len -- length of result
+ * returns SASL_OK
+ */
+typedef int sasl_chalprompt_t(void *context, int id,
+ const char *challenge,
+ const char *prompt, const char *defresult,
+ const char **result, unsigned *len);
+#define SASL_CB_ECHOPROMPT 0x4005 /* challenge and client enterred result */
+#define SASL_CB_NOECHOPROMPT 0x4006 /* challenge and client enterred result */
+
+/* prompt (or autoselect) the realm to do authentication in.
+ * may get a list of valid realms.
+ * input:
+ * context -- context from callback structure
+ * id -- callback id
+ * availrealms -- available realms; string list; NULL terminated
+ * list may be empty.
+ * output:
+ * result -- NUL terminated realm; NULL is equivalent to ""
+ * returns SASL_OK
+ * result must persist until the next callback
+ */
+typedef int sasl_getrealm_t(void *context, int id,
+ const char **availrealms,
+ const char **result);
+#define SASL_CB_GETREALM (0x4008) /* realm to attempt authentication in */
+
+/* server callbacks:
+ */
+
+/* improved callback to verify authorization;
+ * canonicalization now handled elsewhere
+ * conn -- connection context
+ * requested_user -- the identity/username to authorize (NUL terminated)
+ * rlen -- length of requested_user
+ * auth_identity -- the identity associated with the secret (NUL terminated)
+ * alen -- length of auth_identity
+ * default_realm -- default user realm, as passed to sasl_server_new if
+ * urlen -- length of default realm
+ * propctx -- auxiliary properties
+ * returns SASL_OK on success,
+ * SASL_NOAUTHZ or other SASL response on failure
+ */
+typedef int sasl_authorize_t(sasl_conn_t *conn,
+ void *context,
+ const char *requested_user, unsigned rlen,
+ const char *auth_identity, unsigned alen,
+ const char *def_realm, unsigned urlen,
+ struct propctx *propctx);
+#define SASL_CB_PROXY_POLICY 0x8001
+
+/* functions for "userdb" based plugins to call to get/set passwords.
+ * the location for the passwords is determined by the caller or middleware.
+ * plug-ins may get passwords from other locations.
+ */
+
+/* callback to verify a plaintext password against the caller-supplied
+ * user database. This is necessary to allow additional <method>s for
+ * encoding of the userPassword property.
+ * user -- NUL terminated user name with user@realm syntax
+ * pass -- password to check (may not be NUL terminated)
+ * passlen -- length of password to check
+ * propctx -- auxiliary properties for user
+ */
+typedef int sasl_server_userdb_checkpass_t(sasl_conn_t *conn,
+ void *context,
+ const char *user,
+ const char *pass,
+ unsigned passlen,
+ struct propctx *propctx);
+#define SASL_CB_SERVER_USERDB_CHECKPASS (0x8005)
+
+/* callback to store/change a plaintext password in the user database
+ * user -- NUL terminated user name with user@realm syntax
+ * pass -- password to store (may not be NUL terminated)
+ * passlen -- length of password to store
+ * propctx -- auxiliary properties (not stored)
+ * flags -- see SASL_SET_* flags below (SASL_SET_CREATE optional)
+ */
+typedef int sasl_server_userdb_setpass_t(sasl_conn_t *conn,
+ void *context,
+ const char *user,
+ const char *pass,
+ unsigned passlen,
+ struct propctx *propctx,
+ unsigned flags);
+#define SASL_CB_SERVER_USERDB_SETPASS (0x8006)
+
+/* callback for a server-supplied user canonicalization function.
+ *
+ * This function is called directly after the mechanism has the
+ * authentication and authorization IDs. It is called before any
+ * User Canonicalization plugin is called. It has the responsibility
+ * of copying its output into the provided output buffers.
+ *
+ * in, inlen -- user name to canonicalize, may not be NUL terminated
+ * may be same buffer as out
+ * flags -- not currently used, supplied by auth mechanism
+ * user_realm -- the user realm (may be NULL in case of client)
+ * out -- buffer to copy user name
+ * out_max -- max length of user name
+ * out_len -- set to length of user name
+ *
+ * returns
+ * SASL_OK on success
+ * SASL_BADPROT username contains invalid character
+ */
+
+/* User Canonicalization Function Flags */
+
+#define SASL_CU_NONE 0x00 /* Not a valid flag to pass */
+/* One of the following two is required */
+#define SASL_CU_AUTHID 0x01
+#define SASL_CU_AUTHZID 0x02
+
+/* Combine the following with SASL_CU_AUTHID, if you don't want
+ to fail if auxprop returned SASL_NOUSER/SASL_NOMECH. */
+#define SASL_CU_EXTERNALLY_VERIFIED 0x04
+
+#define SASL_CU_OVERRIDE 0x08 /* mapped to SASL_AUXPROP_OVERRIDE */
+
+/* The following CU flags are passed "as is" down to auxprop lookup */
+#define SASL_CU_ASIS_MASK 0xFFF0
+/* NOTE: Keep in sync with SASL_AUXPROP_<XXX> flags */
+#define SASL_CU_VERIFY_AGAINST_HASH 0x10
+
+
+typedef int sasl_canon_user_t(sasl_conn_t *conn,
+ void *context,
+ const char *in, unsigned inlen,
+ unsigned flags,
+ const char *user_realm,
+ char *out,
+ unsigned out_max, unsigned *out_len);
+
+#define SASL_CB_CANON_USER (0x8007)
+
+/**********************************
+ * Common Client/server functions *
+ **********************************/
+
+/* Types of paths to set (see sasl_set_path below). */
+#define SASL_PATH_TYPE_PLUGIN 0
+#define SASL_PATH_TYPE_CONFIG 1
+
+/* a simpler way to set plugin path or configuration file path
+ * without the need to set sasl_getpath_t callback.
+ *
+ * This function can be called before sasl_server_init/sasl_client_init.
+ */
+LIBSASL_API int sasl_set_path (int path_type, char * path);
+
+/* get sasl library version information
+ * implementation is a vendor-defined string
+ * version is a vender-defined representation of the version #.
+ *
+ * This function is being deprecated in favor of sasl_version_info. */
+LIBSASL_API void sasl_version(const char **implementation,
+ int *version);
+
+/* Extended version of sasl_version().
+ *
+ * This function is to be used
+ * for library version display and logging
+ * for bug workarounds in old library versions
+ *
+ * The sasl_version_info is not to be used for API feature detection.
+ *
+ * All parameters are optional. If NULL is specified, the value is not returned.
+ */
+LIBSASL_API void sasl_version_info (const char **implementation,
+ const char **version_string,
+ int *version_major,
+ int *version_minor,
+ int *version_step,
+ int *version_patch);
+
+/* dispose of all SASL plugins. Connection
+ * states have to be disposed of before calling this.
+ *
+ * This function is DEPRECATED in favour of sasl_server_done/
+ * sasl_client_done.
+ */
+LIBSASL_API void sasl_done(void);
+
+/* dispose of all SASL plugins. Connection
+ * states have to be disposed of before calling this.
+ * This function should be called instead of sasl_done(),
+ whenever possible.
+ */
+LIBSASL_API int sasl_server_done(void);
+
+/* dispose of all SASL plugins. Connection
+ * states have to be disposed of before calling this.
+ * This function should be called instead of sasl_done(),
+ whenever possible.
+ */
+LIBSASL_API int sasl_client_done(void);
+
+/* dispose connection state, sets it to NULL
+ * checks for pointer to NULL
+ */
+LIBSASL_API void sasl_dispose(sasl_conn_t **pconn);
+
+/* translate an error number into a string
+ * input:
+ * saslerr -- the error number
+ * langlist -- comma separated list of RFC 1766 languages (may be NULL)
+ * results:
+ * outlang -- the language actually used (may be NULL if don't care)
+ * returns:
+ * the error message in UTF-8 (only the US-ASCII subset if langlist is NULL)
+ */
+LIBSASL_API const char *sasl_errstring(int saslerr,
+ const char *langlist,
+ const char **outlang);
+
+/* get detail about the last error that occurred on a connection
+ * text is sanitized so it's suitable to send over the wire
+ * (e.g., no distinction between SASL_BADAUTH and SASL_NOUSER)
+ * input:
+ * conn -- mandatory connection context
+ * returns:
+ * the error message in UTF-8 (only the US-ASCII subset permitted if no
+ * SASL_CB_LANGUAGE callback is present)
+ */
+LIBSASL_API const char *sasl_errdetail(sasl_conn_t *conn);
+
+/* set the error string which will be returned by sasl_errdetail() using
+ * syslog()-style formatting (e.g. printf-style with %m as most recent
+ * errno error)
+ *
+ * primarily for use by server callbacks such as the sasl_authorize_t
+ * callback and internally to plug-ins
+ *
+ * This will also trigger a call to the SASL logging callback (if any)
+ * with a level of SASL_LOG_FAIL unless the SASL_NOLOG flag is set.
+ *
+ * Messages should be sensitive to the current language setting. If there
+ * is no SASL_CB_LANGUAGE callback messages MUST be US-ASCII otherwise UTF-8
+ * is used and use of RFC 2482 for mixed-language text is encouraged.
+ *
+ * if conn is NULL, function does nothing
+ */
+LIBSASL_API void sasl_seterror(sasl_conn_t *conn, unsigned flags,
+ const char *fmt, ...);
+#define SASL_NOLOG 0x01
+
+/* get property from SASL connection state
+ * propnum -- property number
+ * pvalue -- pointer to value
+ * returns:
+ * SASL_OK -- no error
+ * SASL_NOTDONE -- property not available yet
+ * SASL_BADPARAM -- bad property number
+ */
+LIBSASL_API int sasl_getprop(sasl_conn_t *conn, int propnum,
+ const void **pvalue);
+#define SASL_USERNAME 0 /* pointer to NUL terminated user name */
+#define SASL_SSF 1 /* security layer security strength factor,
+ * if 0, call to sasl_encode, sasl_decode
+ * unnecessary */
+#define SASL_MAXOUTBUF 2 /* security layer max output buf unsigned */
+#define SASL_DEFUSERREALM 3 /* default realm passed to server_new */
+ /* or set with setprop */
+#define SASL_GETOPTCTX 4 /* context for getopt callback */
+#define SASL_CALLBACK 7 /* current callback function list */
+#define SASL_IPLOCALPORT 8 /* iplocalport string passed to server_new */
+#define SASL_IPREMOTEPORT 9 /* ipremoteport string passed to server_new */
+
+/* This returns a string which is either empty or has an error message
+ * from sasl_seterror (e.g., from a plug-in or callback). It differs
+ * from the result of sasl_errdetail() which also takes into account the
+ * last return status code.
+ */
+#define SASL_PLUGERR 10
+
+/* a handle to any delegated credentials or NULL if none is present
+ * is returned by the mechanism. The user will probably need to know
+ * which mechanism was used to actually known how to make use of them
+ * currently only implemented for the gssapi mechanism */
+#define SASL_DELEGATEDCREDS 11
+
+#define SASL_SERVICE 12 /* service passed to sasl_*_new */
+#define SASL_SERVERFQDN 13 /* serverFQDN passed to sasl_*_new */
+#define SASL_AUTHSOURCE 14 /* name of auth source last used, useful
+ * for failed authentication tracking */
+#define SASL_MECHNAME 15 /* active mechanism name, if any */
+#define SASL_AUTHUSER 16 /* authentication/admin user */
+#define SASL_APPNAME 17 /* application name (used for logging/
+ configuration), same as appname parameter
+ to sasl_server_init */
+
+/* GSS-API credential handle for sasl_client_step() or sasl_server_step().
+ * The application is responsible for releasing this credential handle. */
+#define SASL_GSS_CREDS 18
+
+/* GSS name (gss_name_t) of the peer, as output by gss_inquire_context()
+ * or gss_accept_sec_context().
+ * On server end this is similar to SASL_USERNAME, but the gss_name_t
+ * structure can contain additional attributes associated with the peer.
+ */
+#define SASL_GSS_PEER_NAME 19
+
+/* Local GSS name (gss_name_t) as output by gss_inquire_context(). This
+ * is particularly useful for servers that respond to multiple names. */
+#define SASL_GSS_LOCAL_NAME 20
+
+/* Channel binding information. Memory is managed by the caller. */
+typedef struct sasl_channel_binding {
+ const char *name;
+ int critical;
+ unsigned long len;
+ const unsigned char *data;
+} sasl_channel_binding_t;
+
+#define SASL_CHANNEL_BINDING 21
+
+/* HTTP Request (RFC 2616) - ONLY used for HTTP Digest Auth (RFC 2617) */
+typedef struct sasl_http_request {
+ const char *method; /* HTTP Method */
+ const char *uri; /* request-URI */
+ const unsigned char *entity; /* entity-body */
+ unsigned long elen; /* entity-body length */
+ unsigned non_persist; /* Is it a non-persistent connection? */
+} sasl_http_request_t;
+
+#define SASL_HTTP_REQUEST 22
+
+/* set property in SASL connection state
+ * returns:
+ * SASL_OK -- value set
+ * SASL_BADPARAM -- invalid property or value
+ */
+LIBSASL_API int sasl_setprop(sasl_conn_t *conn,
+ int propnum,
+ const void *value);
+#define SASL_SSF_EXTERNAL 100 /* external SSF active (sasl_ssf_t *) */
+#define SASL_SEC_PROPS 101 /* sasl_security_properties_t */
+#define SASL_AUTH_EXTERNAL 102 /* external authentication ID (const char *) */
+
+/* If the SASL_AUTH_EXTERNAL value is non-NULL, then a special version of the
+ * EXTERNAL mechanism is enabled (one for server-embedded EXTERNAL mechanisms).
+ * Otherwise, the EXTERNAL mechanism will be absent unless a plug-in
+ * including EXTERNAL is present.
+ */
+
+/* do precalculations during an idle period or network round trip
+ * may pass NULL to precompute for some mechanisms prior to connect
+ * returns 1 if action taken, 0 if no action taken
+ */
+LIBSASL_API int sasl_idle(sasl_conn_t *conn);
+
+/**************
+ * Client API *
+ **************/
+
+/* list of client interactions with user for caller to fill in
+ */
+typedef struct sasl_interact {
+ unsigned long id; /* same as client/user callback ID */
+ const char *challenge; /* presented to user (e.g. OTP challenge) */
+ const char *prompt; /* presented to user (e.g. "Username: ") */
+ const char *defresult; /* default result string */
+ const void *result; /* set to point to result */
+ unsigned len; /* set to length of result */
+} sasl_interact_t;
+
+/* initialize the SASL client drivers
+ * callbacks -- base callbacks for all client connections;
+ * must include getopt callback
+ * returns:
+ * SASL_OK -- Success
+ * SASL_NOMEM -- Not enough memory
+ * SASL_BADVERS -- Mechanism version mismatch
+ * SASL_BADPARAM -- missing getopt callback or error in config file
+ * SASL_NOMECH -- No mechanisms available
+ * ...
+ */
+LIBSASL_API int sasl_client_init(const sasl_callback_t *callbacks);
+
+/* initialize a client exchange based on the specified mechanism
+ * service -- registered name of the service using SASL (e.g. "imap")
+ * serverFQDN -- the fully qualified domain name of the server
+ * iplocalport -- client IPv4/IPv6 domain literal string with port
+ * (if NULL, then mechanisms requiring IPaddr are disabled)
+ * ipremoteport -- server IPv4/IPv6 domain literal string with port
+ * (if NULL, then mechanisms requiring IPaddr are disabled)
+ * prompt_supp -- list of client interactions supported
+ * may also include sasl_getopt_t context & call
+ * NULL prompt_supp = user/pass via SASL_INTERACT only
+ * NULL proc = interaction supported via SASL_INTERACT
+ * flags -- server usage flags (see above)
+ * in/out:
+ * pconn -- connection negotiation structure
+ * pointer to NULL => allocate new
+ *
+ * Returns:
+ * SASL_OK -- success
+ * SASL_NOMECH -- no mechanism meets requested properties
+ * SASL_NOMEM -- not enough memory
+ */
+LIBSASL_API int sasl_client_new(const char *service,
+ const char *serverFQDN,
+ const char *iplocalport,
+ const char *ipremoteport,
+ const sasl_callback_t *prompt_supp,
+ unsigned flags,
+ sasl_conn_t **pconn);
+
+/* select a mechanism for a connection
+ * mechlist -- mechanisms server has available (punctuation ignored)
+ * if NULL, then discard cached info and retry last mech
+ * output:
+ * prompt_need -- on SASL_INTERACT, list of prompts needed to continue
+ * may be NULL if callbacks provided
+ * clientout -- the initial client response to send to the server
+ * will be valid until next call to client_start/client_step
+ * NULL if mech doesn't include initial client challenge
+ * mech -- set to mechansm name of selected mechanism (may be NULL)
+ *
+ * Returns:
+ * SASL_OK -- success
+ * SASL_NOMEM -- not enough memory
+ * SASL_NOMECH -- no mechanism meets requested properties
+ * SASL_INTERACT -- user interaction needed to fill in prompt_need list
+ */
+LIBSASL_API int sasl_client_start(sasl_conn_t *conn,
+ const char *mechlist,
+ sasl_interact_t **prompt_need,
+ const char **clientout,
+ unsigned *clientoutlen,
+ const char **mech);
+
+/* do a single authentication step.
+ * serverin -- the server message received by the client, MUST have a NUL
+ * sentinel, not counted by serverinlen
+ * output:
+ * prompt_need -- on SASL_INTERACT, list of prompts needed to continue
+ * clientout -- the client response to send to the server
+ * will be valid until next call to client_start/client_step
+ *
+ * returns:
+ * SASL_OK -- success
+ * SASL_INTERACT -- user interaction needed to fill in prompt_need list
+ * SASL_BADPROT -- server protocol incorrect/cancelled
+ * SASL_BADSERV -- server failed mutual auth
+ */
+LIBSASL_API int sasl_client_step(sasl_conn_t *conn,
+ const char *serverin,
+ unsigned serverinlen,
+ sasl_interact_t **prompt_need,
+ const char **clientout,
+ unsigned *clientoutlen);
+
+/**************
+ * Server API *
+ **************/
+
+/* initialize server drivers, done once per process
+ * callbacks -- callbacks for all server connections; must include
+ * getopt callback
+ * appname -- name of calling application (for lower level logging)
+ * results:
+ * state -- server state
+ * returns:
+ * SASL_OK -- success
+ * SASL_BADPARAM -- error in config file
+ * SASL_NOMEM -- memory failure
+ * SASL_BADVERS -- Mechanism version mismatch
+ */
+LIBSASL_API int sasl_server_init(const sasl_callback_t *callbacks,
+ const char *appname);
+
+/* IP/port syntax:
+ * a.b.c.d;p where a-d are 0-255 and p is 0-65535 port number.
+ * e:f:g:h:i:j:k:l;p where e-l are 0000-ffff lower-case hexidecimal
+ * e:f:g:h:i:j:a.b.c.d;p alternate syntax for previous
+ *
+ * Note that one or more "0" fields in f-k can be replaced with "::"
+ * Thus: e:f:0000:0000:0000:j:k:l;p
+ * can be abbreviated: e:f::j:k:l;p
+ *
+ * A buffer of size 52 is adequate for the longest format with NUL terminator.
+ */
+
+/* create context for a single SASL connection
+ * service -- registered name of the service using SASL (e.g. "imap")
+ * serverFQDN -- Fully qualified domain name of server. NULL means use
+ * gethostname() or equivalent.
+ * Useful for multi-homed servers.
+ * user_realm -- permits multiple user realms on server, NULL = default
+ * iplocalport -- server IPv4/IPv6 domain literal string with port
+ * (if NULL, then mechanisms requiring IPaddr are disabled)
+ * ipremoteport -- client IPv4/IPv6 domain literal string with port
+ * (if NULL, then mechanisms requiring IPaddr are disabled)
+ * callbacks -- callbacks (e.g., authorization, lang, new getopt context)
+ * flags -- usage flags (see above)
+ * returns:
+ * pconn -- new connection context
+ *
+ * returns:
+ * SASL_OK -- success
+ * SASL_NOMEM -- not enough memory
+ */
+LIBSASL_API int sasl_server_new(const char *service,
+ const char *serverFQDN,
+ const char *user_realm,
+ const char *iplocalport,
+ const char *ipremoteport,
+ const sasl_callback_t *callbacks,
+ unsigned flags,
+ sasl_conn_t **pconn);
+
+/* Return an array of NUL-terminated strings, terminated by a NULL pointer,
+ * which lists all possible mechanisms that the library can supply
+ *
+ * Returns NULL on failure. */
+LIBSASL_API const char ** sasl_global_listmech(void);
+
+/* This returns a list of mechanisms in a NUL-terminated string
+ * conn -- the connection to list mechanisms for (either client
+ * or server)
+ * user -- restricts mechanisms to those available to that user
+ * (may be NULL, not used for client case)
+ * prefix -- appended to beginning of result
+ * sep -- appended between mechanisms
+ * suffix -- appended to end of result
+ * results:
+ * result -- NUL terminated result which persists until next
+ * call to sasl_listmech for this sasl_conn_t
+ * plen -- gets length of result (excluding NUL), may be NULL
+ * pcount -- gets number of mechanisms, may be NULL
+ *
+ * returns:
+ * SASL_OK -- success
+ * SASL_NOMEM -- not enough memory
+ * SASL_NOMECH -- no enabled mechanisms
+ */
+LIBSASL_API int sasl_listmech(sasl_conn_t *conn,
+ const char *user,
+ const char *prefix,
+ const char *sep,
+ const char *suffix,
+ const char **result,
+ unsigned *plen,
+ int *pcount);
+
+/* start a mechanism exchange within a connection context
+ * mech -- the mechanism name client requested
+ * clientin -- client initial response (NUL terminated), NULL if empty
+ * clientinlen -- length of initial response
+ * serverout -- initial server challenge, NULL if done
+ * (library handles freeing this string)
+ * serveroutlen -- length of initial server challenge
+ * output:
+ * pconn -- the connection negotiation state on success
+ *
+ * Same returns as sasl_server_step() or
+ * SASL_NOMECH if mechanism not available.
+ */
+LIBSASL_API int sasl_server_start(sasl_conn_t *conn,
+ const char *mech,
+ const char *clientin,
+ unsigned clientinlen,
+ const char **serverout,
+ unsigned *serveroutlen);
+
+/* perform one step of the SASL exchange
+ * inputlen & input -- client data
+ * NULL on first step if no optional client step
+ * outputlen & output -- set to the server data to transmit
+ * to the client in the next step
+ * (library handles freeing this)
+ *
+ * returns:
+ * SASL_OK -- exchange is complete.
+ * SASL_CONTINUE -- indicates another step is necessary.
+ * SASL_TRANS -- entry for user exists, but not for mechanism
+ * and transition is possible
+ * SASL_BADPARAM -- service name needed
+ * SASL_BADPROT -- invalid input from client
+ * ...
+ */
+LIBSASL_API int sasl_server_step(sasl_conn_t *conn,
+ const char *clientin,
+ unsigned clientinlen,
+ const char **serverout,
+ unsigned *serveroutlen);
+
+/* check if an apop exchange is valid
+ * (note this is an optional part of the SASL API)
+ * if challenge is NULL, just check if APOP is enabled
+ * inputs:
+ * challenge -- challenge which was sent to client
+ * challen -- length of challenge, 0 = strlen(challenge)
+ * response -- client response, "<user> <digest>" (RFC 1939)
+ * resplen -- length of response, 0 = strlen(response)
+ * returns
+ * SASL_OK -- success
+ * SASL_BADAUTH -- authentication failed
+ * SASL_BADPARAM -- missing challenge
+ * SASL_BADPROT -- protocol error (e.g., response in wrong format)
+ * SASL_NOVERIFY -- user found, but no verifier
+ * SASL_NOMECH -- mechanism not supported
+ * SASL_NOUSER -- user not found
+ */
+LIBSASL_API int sasl_checkapop(sasl_conn_t *conn,
+ const char *challenge, unsigned challen,
+ const char *response, unsigned resplen);
+
+/* check if a plaintext password is valid
+ * if user is NULL, check if plaintext passwords are enabled
+ * inputs:
+ * user -- user to query in current user_domain
+ * userlen -- length of username, 0 = strlen(user)
+ * pass -- plaintext password to check
+ * passlen -- length of password, 0 = strlen(pass)
+ * returns
+ * SASL_OK -- success
+ * SASL_NOMECH -- mechanism not supported
+ * SASL_NOVERIFY -- user found, but no verifier
+ * SASL_NOUSER -- user not found
+ */
+LIBSASL_API int sasl_checkpass(sasl_conn_t *conn,
+ const char *user, unsigned userlen,
+ const char *pass, unsigned passlen);
+
+/* check if a user exists on server
+ * conn -- connection context
+ * service -- registered name of the service using SASL (e.g. "imap")
+ * user_realm -- permits multiple user realms on server, NULL = default
+ * user -- NUL terminated user name
+ *
+ * returns:
+ * SASL_OK -- success
+ * SASL_DISABLED -- account disabled
+ * SASL_NOUSER -- user not found
+ * SASL_NOVERIFY -- user found, but no usable mechanism
+ * SASL_NOMECH -- no mechanisms enabled
+ * SASL_UNAVAIL -- remote authentication server unavailable, try again later
+ */
+LIBSASL_API int sasl_user_exists(sasl_conn_t *conn,
+ const char *service,
+ const char *user_realm,
+ const char *user);
+
+/* set the password for a user
+ * conn -- SASL connection
+ * user -- user name
+ * pass -- plaintext password, may be NULL to remove user
+ * passlen -- length of password, 0 = strlen(pass)
+ * oldpass -- NULL will sometimes work
+ * oldpasslen -- length of password, 0 = strlen(oldpass)
+ * flags -- see flags below
+ *
+ * returns:
+ * SASL_NOCHANGE -- proper entry already exists
+ * SASL_NOMECH -- no authdb supports password setting as configured
+ * SASL_NOVERIFY -- user exists, but no settable password present
+ * SASL_DISABLED -- account disabled
+ * SASL_PWLOCK -- password locked
+ * SASL_WEAKPASS -- password too weak for security policy
+ * SASL_NOUSERPASS -- user-supplied passwords not permitted
+ * SASL_FAIL -- OS error
+ * SASL_BADPARAM -- password too long
+ * SASL_OK -- successful
+ */
+LIBSASL_API int sasl_setpass(sasl_conn_t *conn,
+ const char *user,
+ const char *pass, unsigned passlen,
+ const char *oldpass, unsigned oldpasslen,
+ unsigned flags);
+#define SASL_SET_CREATE 0x01 /* create a new entry for user */
+#define SASL_SET_DISABLE 0x02 /* disable user account */
+#define SASL_SET_NOPLAIN 0x04 /* do not store secret in plain text */
+#define SASL_SET_CURMECH_ONLY 0x08 /* set the mechanism specific password only.
+ fail if no current mechanism */
+
+/*********************************************************
+ * Auxiliary Property Support -- added by cjn 1999-09-29 *
+ *********************************************************/
+
+#define SASL_AUX_END NULL /* last auxiliary property */
+
+#define SASL_AUX_ALL "*" /* A special flag to signal user deletion */
+
+/* traditional Posix items (should be implemented on Posix systems) */
+#define SASL_AUX_PASSWORD_PROP "userPassword" /* User Password */
+#define SASL_AUX_PASSWORD "*" SASL_AUX_PASSWORD_PROP /* User Password (of authid) */
+#define SASL_AUX_UIDNUM "uidNumber" /* UID number for the user */
+#define SASL_AUX_GIDNUM "gidNumber" /* GID for the user */
+#define SASL_AUX_FULLNAME "gecos" /* full name of the user, unix-style */
+#define SASL_AUX_HOMEDIR "homeDirectory" /* home directory for user */
+#define SASL_AUX_SHELL "loginShell" /* login shell for the user */
+
+/* optional additional items (not necessarily implemented) */
+/* single preferred mail address for user canonically-quoted
+ * RFC821/822 syntax */
+#define SASL_AUX_MAILADDR "mail"
+/* path to unix-style mailbox for user */
+#define SASL_AUX_UNIXMBX "mailMessageStore"
+/* SMTP mail channel name to use if user authenticates successfully */
+#define SASL_AUX_MAILCHAN "mailSMTPSubmitChannel"
+
+/* Request a set of auxiliary properties
+ * conn connection context
+ * propnames list of auxiliary property names to request ending with
+ * NULL.
+ *
+ * Subsequent calls will add items to the request list. Call with NULL
+ * to clear the request list.
+ *
+ * errors
+ * SASL_OK -- success
+ * SASL_BADPARAM -- bad count/conn parameter
+ * SASL_NOMEM -- out of memory
+ */
+LIBSASL_API int sasl_auxprop_request(sasl_conn_t *conn,
+ const char **propnames);
+
+/* Returns current auxiliary property context.
+ * Use functions in prop.h to access content
+ *
+ * if authentication hasn't completed, property values may be empty/NULL
+ *
+ * properties not recognized by active plug-ins will be left empty/NULL
+ *
+ * returns NULL if conn is invalid.
+ */
+LIBSASL_API struct propctx *sasl_auxprop_getctx(sasl_conn_t *conn);
+
+/* Store the set of auxiliary properties for the given user.
+ * Use functions in prop.h to set the content.
+ *
+ * conn connection context
+ * ctx property context from prop_new()/prop_request()/prop_set()
+ * user NUL terminated user
+ *
+ * Call with NULL 'ctx' to see if the backend allows storing properties.
+ *
+ * errors
+ * SASL_OK -- success
+ * SASL_NOMECH -- can not store some/all properties
+ * SASL_BADPARAM -- bad conn/ctx/user parameter
+ * SASL_NOMEM -- out of memory
+ * SASL_FAIL -- failed to store
+ */
+LIBSASL_API int sasl_auxprop_store(sasl_conn_t *conn,
+ struct propctx *ctx, const char *user);
+
+/**********************
+ * security layer API *
+ **********************/
+
+/* encode a block of data for transmission using security layer,
+ * returning the input buffer if there is no security layer.
+ * output is only valid until next call to sasl_encode or sasl_encodev
+ * returns:
+ * SASL_OK -- success (returns input if no layer negotiated)
+ * SASL_NOTDONE -- security layer negotiation not finished
+ * SASL_BADPARAM -- inputlen is greater than the SASL_MAXOUTBUF
+ */
+LIBSASL_API int sasl_encode(sasl_conn_t *conn,
+ const char *input, unsigned inputlen,
+ const char **output, unsigned *outputlen);
+
+/* encode a block of data for transmission using security layer
+ * output is only valid until next call to sasl_encode or sasl_encodev
+ * returns:
+ * SASL_OK -- success (returns input if no layer negotiated)
+ * SASL_NOTDONE -- security layer negotiation not finished
+ * SASL_BADPARAM -- input length is greater than the SASL_MAXOUTBUF
+ * or no security layer
+ */
+LIBSASL_API int sasl_encodev(sasl_conn_t *conn,
+ const struct iovec *invec, unsigned numiov,
+ const char **output, unsigned *outputlen);
+
+/* decode a block of data received using security layer
+ * returning the input buffer if there is no security layer.
+ * output is only valid until next call to sasl_decode
+ *
+ * if outputlen is 0 on return, than the value of output is undefined.
+ *
+ * returns:
+ * SASL_OK -- success (returns input if no layer negotiated)
+ * SASL_NOTDONE -- security layer negotiation not finished
+ * SASL_BADMAC -- bad message integrity check
+ */
+LIBSASL_API int sasl_decode(sasl_conn_t *conn,
+ const char *input, unsigned inputlen,
+ const char **output, unsigned *outputlen);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SASL_H */
diff --git a/contrib/libs/sasl/include/saslplug.h b/contrib/libs/sasl/include/saslplug.h
new file mode 100644
index 0000000000..ab79e68cf6
--- /dev/null
+++ b/contrib/libs/sasl/include/saslplug.h
@@ -0,0 +1,986 @@
+/* saslplug.h -- API for SASL plug-ins
+ */
+
+#ifndef SASLPLUG_H
+#define SASLPLUG_H 1
+
+#ifndef MD5GLOBAL_H
+#include "md5global.h"
+#endif
+#ifndef MD5_H
+#include "md5.h"
+#endif
+#ifndef HMAC_MD5_H
+#include "hmac-md5.h"
+#endif
+#ifndef PROP_H
+#include "prop.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* callback to lookup a sasl_callback_t for a connection
+ * input:
+ * conn -- the connection to lookup a callback for
+ * callbacknum -- the number of the callback
+ * output:
+ * pproc -- pointer to the callback function (set to NULL on failure)
+ * pcontext -- pointer to the callback context (set to NULL on failure)
+ * returns:
+ * SASL_OK -- no error
+ * SASL_FAIL -- unable to find a callback of the requested type
+ * SASL_INTERACT -- caller must use interaction to get data
+ */
+typedef int (*sasl_callback_ft)(void);
+typedef int sasl_getcallback_t(sasl_conn_t *conn,
+ unsigned long callbackid,
+ sasl_callback_ft * pproc,
+ void **pcontext);
+
+/* The sasl_utils structure will remain backwards compatible unless
+ * the SASL_*_PLUG_VERSION is changed incompatibly
+ * higher SASL_UTILS_VERSION numbers indicate more functions are available
+ */
+#define SASL_UTILS_VERSION 4
+
+/* utility function set for plug-ins
+ */
+typedef struct sasl_utils {
+ int version;
+
+ /* contexts */
+ sasl_conn_t *conn;
+ sasl_rand_t *rpool;
+ void *getopt_context;
+
+ /* option function */
+ sasl_getopt_t *getopt;
+
+ /* allocation functions: */
+ sasl_malloc_t *malloc;
+ sasl_calloc_t *calloc;
+ sasl_realloc_t *realloc;
+ sasl_free_t *free;
+
+ /* mutex functions: */
+ sasl_mutex_alloc_t *mutex_alloc;
+ sasl_mutex_lock_t *mutex_lock;
+ sasl_mutex_unlock_t *mutex_unlock;
+ sasl_mutex_free_t *mutex_free;
+
+ /* MD5 hash and HMAC functions */
+ void (*MD5Init)(MD5_CTX *);
+ void (*MD5Update)(MD5_CTX *, const unsigned char *text, unsigned int len);
+ void (*MD5Final)(unsigned char [16], MD5_CTX *);
+ void (*hmac_md5)(const unsigned char *text, int text_len,
+ const unsigned char *key, int key_len,
+ unsigned char [16]);
+ void (*hmac_md5_init)(HMAC_MD5_CTX *, const unsigned char *key, int len);
+ /* hmac_md5_update() is just a call to MD5Update on inner context */
+ void (*hmac_md5_final)(unsigned char [16], HMAC_MD5_CTX *);
+ void (*hmac_md5_precalc)(HMAC_MD5_STATE *,
+ const unsigned char *key, int len);
+ void (*hmac_md5_import)(HMAC_MD5_CTX *, HMAC_MD5_STATE *);
+
+ /* mechanism utility functions (same as above): */
+ int (*mkchal)(sasl_conn_t *conn, char *buf, unsigned maxlen,
+ unsigned hostflag);
+ int (*utf8verify)(const char *str, unsigned len);
+ void (*rand)(sasl_rand_t *rpool, char *buf, unsigned len);
+ void (*churn)(sasl_rand_t *rpool, const char *data, unsigned len);
+
+ /* This allows recursive calls to the sasl_checkpass() routine from
+ * within a SASL plug-in. This MUST NOT be used in the PLAIN mechanism
+ * as sasl_checkpass MAY be a front-end for the PLAIN mechanism.
+ * This is intended for use by the non-standard LOGIN mechanism and
+ * potentially by a future mechanism which uses public-key technology to
+ * set up a lightweight encryption layer just for sending a password.
+ */
+ int (*checkpass)(sasl_conn_t *conn,
+ const char *user, unsigned userlen,
+ const char *pass, unsigned passlen);
+
+ /* Access to base64 encode/decode routines */
+ int (*decode64)(const char *in, unsigned inlen,
+ char *out, unsigned outmax, unsigned *outlen);
+ int (*encode64)(const char *in, unsigned inlen,
+ char *out, unsigned outmax, unsigned *outlen);
+
+ /* erase a buffer */
+ void (*erasebuffer)(char *buf, unsigned len);
+
+ /* callback to sasl_getprop() and sasl_setprop() */
+ int (*getprop)(sasl_conn_t *conn, int propnum, const void **pvalue);
+ int (*setprop)(sasl_conn_t *conn, int propnum, const void *value);
+
+ /* callback function */
+ sasl_getcallback_t *getcallback;
+
+ /* format a message and then pass it to the SASL_CB_LOG callback
+ *
+ * use syslog()-style formatting (printf with %m as a human readable text
+ * (strerror()) for the error specified as the parameter).
+ * The implementation may use a fixed size buffer not smaller
+ * than 512 octets if it securely truncates the message.
+ *
+ * level is a SASL_LOG_* level (see sasl.h)
+ */
+ void (*log)(sasl_conn_t *conn, int level, const char *fmt, ...) __attribute__((format(printf, 3, 4)));
+
+ /* callback to sasl_seterror() */
+ void (*seterror)(sasl_conn_t *conn, unsigned flags, const char *fmt, ...) __attribute__((format(printf, 3, 4)));
+
+ /* spare function pointer */
+ int *(*spare_fptr)(void);
+
+ /* auxiliary property utilities */
+ struct propctx *(*prop_new)(unsigned estimate);
+ int (*prop_dup)(struct propctx *src_ctx, struct propctx **dst_ctx);
+ int (*prop_request)(struct propctx *ctx, const char **names);
+ const struct propval *(*prop_get)(struct propctx *ctx);
+ int (*prop_getnames)(struct propctx *ctx, const char **names,
+ struct propval *vals);
+ void (*prop_clear)(struct propctx *ctx, int requests);
+ void (*prop_dispose)(struct propctx **ctx);
+ int (*prop_format)(struct propctx *ctx, const char *sep, int seplen,
+ char *outbuf, unsigned outmax, unsigned *outlen);
+ int (*prop_set)(struct propctx *ctx, const char *name,
+ const char *value, int vallen);
+ int (*prop_setvals)(struct propctx *ctx, const char *name,
+ const char **values);
+ void (*prop_erase)(struct propctx *ctx, const char *name);
+ int (*auxprop_store)(sasl_conn_t *conn,
+ struct propctx *ctx, const char *user);
+
+ /* for additions which don't require a version upgrade; set to 0 */
+ int (*spare_fptr1)(void);
+ int (*spare_fptr2)(void);
+} sasl_utils_t;
+
+/*
+ * output parameters from SASL API
+ *
+ * created / destroyed by the glue code, though probably filled in
+ * by a combination of the plugin, the glue code, and the canon_user callback.
+ *
+ */
+typedef struct sasl_out_params {
+ unsigned doneflag; /* exchange complete */
+
+ const char *user; /* canonicalized user name */
+ const char *authid; /* canonicalized authentication id */
+
+ unsigned ulen; /* length of canonicalized user name */
+ unsigned alen; /* length of canonicalized authid */
+
+ /* security layer information */
+ unsigned maxoutbuf; /* Maximum buffer size, which will
+ produce buffer no bigger than the
+ negotiated SASL maximum buffer size */
+ sasl_ssf_t mech_ssf; /* Should be set non-zero if negotiation of a
+ * security layer was *attempted*, even if
+ * the negotiation failed */
+ void *encode_context;
+ int (*encode)(void *context, const struct iovec *invec, unsigned numiov,
+ const char **output, unsigned *outputlen);
+ void *decode_context;
+ int (*decode)(void *context, const char *input, unsigned inputlen,
+ const char **output, unsigned *outputlen);
+
+ /* Pointer to delegated (client's) credentials, if supported by
+ the SASL mechanism */
+ void *client_creds;
+
+ /* for additions which don't require a version upgrade; set to 0 */
+ const void *gss_peer_name;
+ const void *gss_local_name;
+ const char *cbindingname; /* channel binding name from packet */
+ int (*spare_fptr1)(void);
+ int (*spare_fptr2)(void);
+ unsigned int cbindingdisp; /* channel binding disposition from client */
+ int spare_int2;
+ int spare_int3;
+ int spare_int4;
+
+ /* set to 0 initially, this allows a plugin with extended parameters
+ * to work with an older framework by updating version as parameters
+ * are added.
+ */
+ int param_version;
+} sasl_out_params_t;
+
+
+
+/* Used by both client and server side plugins */
+typedef enum {
+ SASL_INFO_LIST_START = 0,
+ SASL_INFO_LIST_MECH,
+ SASL_INFO_LIST_END
+} sasl_info_callback_stage_t;
+
+/******************************
+ * Channel binding macros **
+ ******************************/
+
+typedef enum {
+ SASL_CB_DISP_NONE = 0, /* client did not support CB */
+ SASL_CB_DISP_WANT, /* client supports CB, thinks server does not */
+ SASL_CB_DISP_USED /* client supports and used CB */
+} sasl_cbinding_disp_t;
+
+/* TRUE if channel binding is non-NULL */
+#define SASL_CB_PRESENT(params) ((params)->cbinding != NULL)
+/* TRUE if channel binding is marked critical */
+#define SASL_CB_CRITICAL(params) (SASL_CB_PRESENT(params) && \
+ (params)->cbinding->critical)
+
+/******************************
+ * Client Mechanism Functions *
+ ******************************/
+
+/*
+ * input parameters to client SASL plugin
+ *
+ * created / destroyed by the glue code
+ *
+ */
+typedef struct sasl_client_params {
+ const char *service; /* service name */
+ const char *serverFQDN; /* server fully qualified domain name */
+ const char *clientFQDN; /* client's fully qualified domain name */
+ const sasl_utils_t *utils; /* SASL API utility routines --
+ * for a particular sasl_conn_t,
+ * MUST remain valid until mech_free is
+ * called */
+ const sasl_callback_t *prompt_supp; /* client callback list */
+ const char *iplocalport; /* server IP domain literal & port */
+ const char *ipremoteport; /* client IP domain literal & port */
+
+ unsigned servicelen; /* length of service */
+ unsigned slen; /* length of serverFQDN */
+ unsigned clen; /* length of clientFQDN */
+ unsigned iploclen; /* length of iplocalport */
+ unsigned ipremlen; /* length of ipremoteport */
+
+ /* application's security requirements & info */
+ sasl_security_properties_t props;
+ sasl_ssf_t external_ssf; /* external SSF active */
+
+ /* for additions which don't require a version upgrade; set to 0 */
+ const void *gss_creds; /* GSS credential handle */
+ const sasl_channel_binding_t *cbinding; /* client channel binding */
+ const sasl_http_request_t *http_request;/* HTTP Digest request method */
+ void *spare_ptr4;
+
+ /* Canonicalize a user name from on-wire to internal format
+ * added rjs3 2001-05-23
+ * Must be called once user name aquired if canon_user is non-NULL.
+ * conn connection context
+ * in user name from wire protocol (need not be NUL terminated)
+ * len length of user name from wire protocol (0 = strlen(user))
+ * flags for SASL_CU_* flags
+ * oparams the user, authid, ulen, alen, fields are
+ * set appropriately after canonicalization/copying and
+ * authorization of arguments
+ *
+ * responsible for setting user, ulen, authid, and alen in the oparams
+ * structure
+ *
+ * default behavior is to strip leading and trailing whitespace, as
+ * well as allocating space for and copying the parameters.
+ *
+ * results:
+ * SASL_OK -- success
+ * SASL_NOMEM -- out of memory
+ * SASL_BADPARAM -- invalid conn
+ * SASL_BADPROT -- invalid user/authid
+ */
+ int (*canon_user)(sasl_conn_t *conn,
+ const char *in, unsigned len,
+ unsigned flags,
+ sasl_out_params_t *oparams);
+
+ int (*spare_fptr1)(void);
+
+ unsigned int cbindingdisp;
+ int spare_int2;
+ int spare_int3;
+
+ /* flags field as passed to sasl_client_new */
+ unsigned flags;
+
+ /* set to 0 initially, this allows a plugin with extended parameters
+ * to work with an older framework by updating version as parameters
+ * are added.
+ */
+ int param_version;
+} sasl_client_params_t;
+
+/* features shared between client and server */
+/* These allow the glue code to handle client-first and server-last issues */
+
+/* This indicates that the mechanism prefers to do client-send-first
+ * if the protocol allows it. */
+#define SASL_FEAT_WANT_CLIENT_FIRST 0x0002
+
+/* This feature is deprecated. Instead, plugins should set *serverout to
+ * non-NULL and return SASL_OK intelligently to allow flexible use of
+ * server-last semantics
+#define SASL_FEAT_WANT_SERVER_LAST 0x0004
+*/
+
+/* This feature is deprecated. Instead, plugins should correctly set
+ * SASL_FEAT_SERVER_FIRST as needed
+#define SASL_FEAT_INTERNAL_CLIENT_FIRST 0x0008
+*/
+
+/* This indicates that the plugin is server-first only.
+ * Not defining either of SASL_FEAT_SERVER_FIRST or
+ * SASL_FEAT_WANT_CLIENT_FIRST indicates that the mechanism
+ * will handle the client-first situation internally.
+ */
+#define SASL_FEAT_SERVER_FIRST 0x0010
+
+/* This plugin allows proxying */
+#define SASL_FEAT_ALLOWS_PROXY 0x0020
+
+/* server plugin don't use cleartext userPassword attribute */
+#define SASL_FEAT_DONTUSE_USERPASSWD 0x0080
+
+/* Underlying mechanism uses GSS framing */
+#define SASL_FEAT_GSS_FRAMING 0x0100
+
+/* Underlying mechanism supports channel binding */
+#define SASL_FEAT_CHANNEL_BINDING 0x0800
+
+/* This plugin can be used for HTTP authentication */
+#define SASL_FEAT_SUPPORTS_HTTP 0x1000
+
+/* client plug-in features */
+#define SASL_FEAT_NEEDSERVERFQDN 0x0001
+
+/* a C object for a client mechanism
+ */
+typedef struct sasl_client_plug {
+ /* mechanism name */
+ const char *mech_name;
+
+ /* best mech additional security layer strength factor */
+ sasl_ssf_t max_ssf;
+
+ /* best security flags, as defined in sasl_security_properties_t */
+ unsigned security_flags;
+
+ /* features of plugin */
+ unsigned features;
+
+ /* required prompt ids, NULL = user/pass only */
+ const unsigned long *required_prompts;
+
+ /* global state for mechanism */
+ void *glob_context;
+
+ /* create context for mechanism, using params supplied
+ * glob_context -- from above
+ * params -- params from sasl_client_new
+ * conn_context -- context for one connection
+ * returns:
+ * SASL_OK -- success
+ * SASL_NOMEM -- not enough memory
+ * SASL_WRONGMECH -- mech doesn't support security params
+ */
+ int (*mech_new)(void *glob_context,
+ sasl_client_params_t *cparams,
+ void **conn_context);
+
+ /* perform one step of exchange. NULL is passed for serverin on
+ * first step.
+ * returns:
+ * SASL_OK -- success
+ * SASL_INTERACT -- user interaction needed to fill in prompts
+ * SASL_BADPROT -- server protocol incorrect/cancelled
+ * SASL_BADSERV -- server failed mutual auth
+ */
+ int (*mech_step)(void *conn_context,
+ sasl_client_params_t *cparams,
+ const char *serverin,
+ unsigned serverinlen,
+ sasl_interact_t **prompt_need,
+ const char **clientout,
+ unsigned *clientoutlen,
+ sasl_out_params_t *oparams);
+
+ /* dispose of connection context from mech_new
+ */
+ void (*mech_dispose)(void *conn_context, const sasl_utils_t *utils);
+
+ /* free all global space used by mechanism
+ * mech_dispose must be called on all mechanisms first
+ */
+ void (*mech_free)(void *glob_context, const sasl_utils_t *utils);
+
+ /* perform precalculations during a network round-trip
+ * or idle period. conn_context may be NULL
+ * returns 1 if action taken, 0 if no action taken
+ */
+ int (*idle)(void *glob_context,
+ void *conn_context,
+ sasl_client_params_t *cparams);
+
+ /* for additions which don't require a version upgrade; set to 0 */
+ int (*spare_fptr1)(void);
+ int (*spare_fptr2)(void);
+} sasl_client_plug_t;
+
+#define SASL_CLIENT_PLUG_VERSION 4
+
+/* plug-in entry point:
+ * utils -- utility callback functions
+ * max_version -- highest client plug version supported
+ * returns:
+ * out_version -- client plug version of result
+ * pluglist -- list of mechanism plug-ins
+ * plugcount -- number of mechanism plug-ins
+ * results:
+ * SASL_OK -- success
+ * SASL_NOMEM -- failure
+ * SASL_BADVERS -- max_version too small
+ * SASL_BADPARAM -- bad config string
+ * ...
+ */
+typedef int sasl_client_plug_init_t(const sasl_utils_t *utils,
+ int max_version,
+ int *out_version,
+ sasl_client_plug_t **pluglist,
+ int *plugcount);
+
+
+/* add a client plug-in
+ */
+LIBSASL_API int sasl_client_add_plugin(const char *plugname,
+ sasl_client_plug_init_t *cplugfunc);
+
+typedef struct client_sasl_mechanism
+{
+ int version;
+
+ char *plugname;
+ const sasl_client_plug_t *plug;
+} client_sasl_mechanism_t;
+
+typedef void sasl_client_info_callback_t (client_sasl_mechanism_t *m,
+ sasl_info_callback_stage_t stage,
+ void *rock);
+
+/* Dump information about available client plugins */
+LIBSASL_API int sasl_client_plugin_info (const char *mech_list,
+ sasl_client_info_callback_t *info_cb,
+ void *info_cb_rock);
+
+
+/********************
+ * Server Functions *
+ ********************/
+
+/* log message formatting routine */
+typedef void sasl_logmsg_p(sasl_conn_t *conn, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
+
+/*
+ * input parameters to server SASL plugin
+ *
+ * created / destroyed by the glue code
+ *
+ */
+typedef struct sasl_server_params {
+ const char *service; /* NULL = default service for user_exists
+ and setpass */
+ const char *appname; /* name of calling application */
+ const char *serverFQDN; /* server default fully qualified domain name
+ * (e.g., gethostname) */
+ const char *user_realm; /* realm for user (NULL = client supplied) */
+ const char *iplocalport; /* server IP domain literal & port */
+ const char *ipremoteport; /* client IP domain literal & port */
+
+ unsigned servicelen; /* length of service */
+ unsigned applen; /* length of appname */
+ unsigned slen; /* length of serverFQDN */
+ unsigned urlen; /* length of user_realm */
+ unsigned iploclen; /* length of iplocalport */
+ unsigned ipremlen; /* length of ipremoteport */
+
+ /* This indicates the level of logging desired. See SASL_LOG_*
+ * in sasl.h
+ *
+ * Plug-ins can ignore this and just pass their desired level to
+ * the log callback. This is primarily used to eliminate logging which
+ * might be a performance problem (e.g., full protocol trace) and
+ * to select between SASL_LOG_TRACE and SASL_LOG_PASS alternatives
+ */
+ int log_level;
+
+ const sasl_utils_t *utils; /* SASL API utility routines --
+ * for a particular sasl_conn_t,
+ * MUST remain valid until mech_free is
+ * called */
+ const sasl_callback_t *callbacks; /* Callbacks from application */
+
+ /* application's security requirements */
+ sasl_security_properties_t props;
+ sasl_ssf_t external_ssf; /* external SSF active */
+
+ /* Pointer to the function which takes the plaintext passphrase and
+ * transitions a user to non-plaintext mechanisms via setpass calls.
+ * (NULL = auto transition not enabled/supported)
+ *
+ * If passlen is 0, it defaults to strlen(pass).
+ * returns 0 if no entry added, 1 if entry added
+ */
+ int (*transition)(sasl_conn_t *conn, const char *pass, unsigned passlen);
+
+ /* Canonicalize a user name from on-wire to internal format
+ * added cjn 1999-09-21
+ * Must be called once user name acquired if canon_user is non-NULL.
+ * conn connection context
+ * user user name from wire protocol (need not be NUL terminated)
+ * ulen length of user name from wire protocol (0 = strlen(user))
+ * flags for SASL_CU_* flags
+ * oparams the user, authid, ulen, alen, fields are
+ * set appropriately after canonicalization/copying and
+ * authorization of arguments
+ *
+ * responsible for setting user, ulen, authid, and alen in the oparams
+ * structure
+ *
+ * default behavior is to strip leading and trailing whitespace, as
+ * well as allocating space for and copying the parameters.
+ *
+ * results:
+ * SASL_OK -- success
+ * SASL_NOMEM -- out of memory
+ * SASL_BADPARAM -- invalid conn
+ * SASL_BADPROT -- invalid user/authid
+ */
+ int (*canon_user)(sasl_conn_t *conn,
+ const char *user, unsigned ulen,
+ unsigned flags,
+ sasl_out_params_t *oparams);
+
+ /* auxiliary property context (see definitions in prop.h)
+ * added cjn 2000-01-30
+ *
+ * NOTE: these properties are the ones associated with the
+ * canonicalized "user" (user to login as / authorization id), not
+ * the "authid" (user whose credentials are used / authentication id)
+ * Prefix the property name with a "*" if a property associated with
+ * the "authid" is interesting.
+ */
+ struct propctx *propctx;
+
+ /* for additions which don't require a version upgrade; set to 0 */
+ const void *gss_creds; /* GSS credential handle */
+ const sasl_channel_binding_t *cbinding; /* server channel binding */
+ const sasl_http_request_t *http_request;/* HTTP Digest request method */
+ void *spare_ptr4;
+ int (*spare_fptr1)(void);
+ int (*spare_fptr2)(void);
+ int spare_int1;
+ int spare_int2;
+ int spare_int3;
+
+ /* flags field as passed to sasl_server_new */
+ unsigned flags;
+
+ /* set to 0 initially, this allows a plugin with extended parameters
+ * to work with an older framework by updating version as parameters
+ * are added.
+ */
+ int param_version;
+} sasl_server_params_t;
+
+/* logging levels (more levels may be added later, if necessary):
+ */
+#define SASL_LOG_NONE 0 /* don't log anything */
+#define SASL_LOG_ERR 1 /* log unusual errors (default) */
+#define SASL_LOG_FAIL 2 /* log all authentication failures */
+#define SASL_LOG_WARN 3 /* log non-fatal warnings */
+#define SASL_LOG_NOTE 4 /* more verbose than LOG_WARN */
+#define SASL_LOG_DEBUG 5 /* more verbose than LOG_NOTE */
+#define SASL_LOG_TRACE 6 /* traces of internal protocols */
+#define SASL_LOG_PASS 7 /* traces of internal protocols, including
+ * passwords */
+
+/* additional flags for setpass() function below:
+ */
+/* SASL_SET_CREATE create user if pass non-NULL */
+/* SASL_SET_DISABLE disable user */
+#define SASL_SET_REMOVE SASL_SET_CREATE /* remove user if pass is NULL */
+
+/* features for server plug-in
+ */
+#define SASL_FEAT_SERVICE 0x0200 /* service-specific passwords supported */
+#define SASL_FEAT_GETSECRET 0x0400 /* sasl_server_{get,put}secret_t callbacks
+ * required by plug-in */
+
+/* a C object for a server mechanism
+ */
+typedef struct sasl_server_plug {
+ /* mechanism name */
+ const char *mech_name;
+
+ /* best mech additional security layer strength factor */
+ sasl_ssf_t max_ssf;
+
+ /* best security flags, as defined in sasl_security_properties_t */
+ unsigned security_flags;
+
+ /* features of plugin */
+ unsigned features;
+
+ /* global state for mechanism */
+ void *glob_context;
+
+ /* create a new mechanism handler
+ * glob_context -- global context
+ * sparams -- server config params
+ * challenge -- server challenge from previous instance or NULL
+ * challen -- length of challenge from previous instance or 0
+ * out:
+ * conn_context -- connection context
+ * errinfo -- error information
+ *
+ * returns:
+ * SASL_OK -- successfully created mech instance
+ * SASL_* -- any other server error code
+ */
+ int (*mech_new)(void *glob_context,
+ sasl_server_params_t *sparams,
+ const char *challenge,
+ unsigned challen,
+ void **conn_context);
+
+ /* perform one step in exchange
+ *
+ * returns:
+ * SASL_OK -- success, all done
+ * SASL_CONTINUE -- success, one more round trip
+ * SASL_* -- any other server error code
+ */
+ int (*mech_step)(void *conn_context,
+ sasl_server_params_t *sparams,
+ const char *clientin,
+ unsigned clientinlen,
+ const char **serverout,
+ unsigned *serveroutlen,
+ sasl_out_params_t *oparams);
+
+ /* dispose of a connection state
+ */
+ void (*mech_dispose)(void *conn_context, const sasl_utils_t *utils);
+
+ /* free global state for mechanism
+ * mech_dispose must be called on all mechanisms first
+ */
+ void (*mech_free)(void *glob_context, const sasl_utils_t *utils);
+
+ /* set a password (optional)
+ * glob_context -- global context
+ * sparams -- service, middleware utilities, etc. props ignored
+ * user -- user name
+ * pass -- password/passphrase (NULL = disable/remove/delete)
+ * passlen -- length of password/passphrase
+ * oldpass -- old password/passphrase (NULL = transition)
+ * oldpasslen -- length of password/passphrase
+ * flags -- see above
+ *
+ * returns:
+ * SASL_NOCHANGE -- no change was needed
+ * SASL_NOUSER -- no entry for user
+ * SASL_NOVERIFY -- no mechanism compatible entry for user
+ * SASL_PWLOCK -- password locked
+ * SASL_DIABLED -- account disabled
+ * etc.
+ */
+ int (*setpass)(void *glob_context,
+ sasl_server_params_t *sparams,
+ const char *user,
+ const char *pass, unsigned passlen,
+ const char *oldpass, unsigned oldpasslen,
+ unsigned flags);
+
+ /* query which mechanisms are available for user
+ * glob_context -- context
+ * sparams -- service, middleware utilities, etc. props ignored
+ * user -- NUL terminated user name
+ * maxmech -- max number of strings in mechlist (0 = no output)
+ * output:
+ * mechlist -- an array of C string pointers, filled in with
+ * mechanism names available to the user
+ *
+ * returns:
+ * SASL_OK -- success
+ * SASL_NOMEM -- not enough memory
+ * SASL_FAIL -- lower level failure
+ * SASL_DISABLED -- account disabled
+ * SASL_NOUSER -- user not found
+ * SASL_BUFOVER -- maxmech is too small
+ * SASL_NOVERIFY -- user found, but no mechanisms available
+ */
+ int (*user_query)(void *glob_context,
+ sasl_server_params_t *sparams,
+ const char *user,
+ int maxmech,
+ const char **mechlist);
+
+ /* perform precalculations during a network round-trip
+ * or idle period. conn_context may be NULL (optional)
+ * returns 1 if action taken, 0 if no action taken
+ */
+ int (*idle)(void *glob_context,
+ void *conn_context,
+ sasl_server_params_t *sparams);
+
+ /* check if mechanism is available
+ * optional--if NULL, mechanism is available based on ENABLE= in config
+ *
+ * If this routine sets conn_context to a non-NULL value, then the call
+ * to mech_new will be skipped. This should not be done unless
+ * there's a significant performance benefit, since it can cause
+ * additional memory allocation in SASL core code to keep track of
+ * contexts potentially for multiple mechanisms.
+ *
+ * This is called by the first call to sasl_listmech() for a
+ * given connection context, thus for a given protocol it may
+ * never be called. Note that if mech_avail returns SASL_NOMECH,
+ * then that mechanism is considered disabled for the remainder
+ * of the session. If mech_avail returns SASL_NOTDONE, then a
+ * future call to mech_avail may still return either SASL_OK
+ * or SASL_NOMECH.
+ *
+ * returns SASL_OK on success,
+ * SASL_NOTDONE if mech is not available now, but may be later
+ * (e.g. EXTERNAL w/o auth_id)
+ * SASL_NOMECH if mech disabled
+ */
+ int (*mech_avail)(void *glob_context,
+ sasl_server_params_t *sparams,
+ void **conn_context);
+
+ /* for additions which don't require a version upgrade; set to 0 */
+ int (*spare_fptr2)(void);
+} sasl_server_plug_t;
+
+#define SASL_SERVER_PLUG_VERSION 4
+
+/* plug-in entry point:
+ * utils -- utility callback functions
+ * plugname -- name of plug-in (may be NULL)
+ * max_version -- highest server plug version supported
+ * returns:
+ * out_version -- server plug-in version of result
+ * pluglist -- list of mechanism plug-ins
+ * plugcount -- number of mechanism plug-ins
+ * results:
+ * SASL_OK -- success
+ * SASL_NOMEM -- failure
+ * SASL_BADVERS -- max_version too small
+ * SASL_BADPARAM -- bad config string
+ * ...
+ */
+typedef int sasl_server_plug_init_t(const sasl_utils_t *utils,
+ int max_version,
+ int *out_version,
+ sasl_server_plug_t **pluglist,
+ int *plugcount);
+
+/*
+ * add a server plug-in
+ */
+LIBSASL_API int sasl_server_add_plugin(const char *plugname,
+ sasl_server_plug_init_t *splugfunc);
+
+
+typedef struct server_sasl_mechanism
+{
+ int version;
+ int condition; /* set to SASL_NOUSER if no available users;
+ set to SASL_CONTINUE if delayed plugin loading */
+ char *plugname; /* for AUTHSOURCE tracking */
+ const sasl_server_plug_t *plug;
+ char *f; /* where should i load the mechanism from? */
+} server_sasl_mechanism_t;
+
+typedef void sasl_server_info_callback_t (server_sasl_mechanism_t *m,
+ sasl_info_callback_stage_t stage,
+ void *rock);
+
+
+/* Dump information about available server plugins (separate functions are
+ used for canon and auxprop plugins) */
+LIBSASL_API int sasl_server_plugin_info (const char *mech_list,
+ sasl_server_info_callback_t *info_cb,
+ void *info_cb_rock);
+
+
+/*********************************************************
+ * user canonicalization plug-in -- added cjn 1999-09-29 *
+ *********************************************************/
+
+typedef struct sasl_canonuser {
+ /* optional features of plugin (set to 0) */
+ int features;
+
+ /* spare integer (set to 0) */
+ int spare_int1;
+
+ /* global state for plugin */
+ void *glob_context;
+
+ /* name of plugin */
+ char *name;
+
+ /* free global state for plugin */
+ void (*canon_user_free)(void *glob_context, const sasl_utils_t *utils);
+
+ /* canonicalize a username
+ * glob_context -- global context from this structure
+ * sparams -- server params, note user_realm&propctx elements
+ * user -- user to login as (may not be NUL terminated)
+ * len -- length of user name (0 = strlen(user))
+ * flags -- for SASL_CU_* flags
+ * out -- buffer to copy user name
+ * out_max -- max length of user name
+ * out_len -- set to length of user name
+ *
+ * note that the output buffers MAY be the same as the input buffers.
+ *
+ * returns
+ * SASL_OK on success
+ * SASL_BADPROT username contains invalid character
+ */
+ int (*canon_user_server)(void *glob_context,
+ sasl_server_params_t *sparams,
+ const char *user, unsigned len,
+ unsigned flags,
+ char *out,
+ unsigned out_umax, unsigned *out_ulen);
+
+ int (*canon_user_client)(void *glob_context,
+ sasl_client_params_t *cparams,
+ const char *user, unsigned len,
+ unsigned flags,
+ char *out,
+ unsigned out_max, unsigned *out_len);
+
+ /* for additions which don't require a version upgrade; set to 0 */
+ int (*spare_fptr1)(void);
+ int (*spare_fptr2)(void);
+ int (*spare_fptr3)(void);
+} sasl_canonuser_plug_t;
+
+#define SASL_CANONUSER_PLUG_VERSION 5
+
+/* default name for canonuser plug-in entry point is "sasl_canonuser_init"
+ * similar to sasl_server_plug_init model, except only returns one
+ * sasl_canonuser_plug_t structure;
+ */
+typedef int sasl_canonuser_init_t(const sasl_utils_t *utils,
+ int max_version,
+ int *out_version,
+ sasl_canonuser_plug_t **plug,
+ const char *plugname);
+
+/* add a canonuser plugin
+ */
+LIBSASL_API int sasl_canonuser_add_plugin(const char *plugname,
+ sasl_canonuser_init_t *canonuserfunc);
+
+/******************************************************
+ * auxiliary property plug-in -- added cjn 1999-09-29 *
+ ******************************************************/
+
+typedef struct sasl_auxprop_plug {
+ /* optional features of plugin (none defined yet, set to 0) */
+ int features;
+
+ /* spare integer, must be set to 0 */
+ int spare_int1;
+
+ /* global state for plugin */
+ void *glob_context;
+
+ /* free global state for plugin (OPTIONAL) */
+ void (*auxprop_free)(void *glob_context, const sasl_utils_t *utils);
+
+ /* fill in fields of an auxiliary property context
+ * last element in array has id of SASL_AUX_END
+ * elements with non-0 len should be ignored.
+ */
+ int (*auxprop_lookup)(void *glob_context,
+ sasl_server_params_t *sparams,
+ unsigned flags,
+ const char *user, unsigned ulen);
+
+ /* name of the auxprop plugin */
+ char *name;
+
+ /* store the fields/values of an auxiliary property context (OPTIONAL)
+ *
+ * if ctx is NULL, just check if storing properties is enabled
+ *
+ * returns
+ * SASL_OK on success
+ * SASL_FAIL on failure
+ */
+ int (*auxprop_store)(void *glob_context,
+ sasl_server_params_t *sparams,
+ struct propctx *ctx,
+ const char *user, unsigned ulen);
+} sasl_auxprop_plug_t;
+
+/* auxprop lookup flags */
+#define SASL_AUXPROP_OVERRIDE 0x01 /* if clear, ignore auxiliary properties
+ * with non-zero len field. If set,
+ * override value of those properties */
+#define SASL_AUXPROP_AUTHZID 0x02 /* if clear, we are looking up the
+ * authid flags (prefixed with *), otherwise
+ * we are looking up the authzid flags
+ * (no prefix) */
+
+/* NOTE: Keep in sync with SASL_CU_<XXX> flags */
+#define SASL_AUXPROP_VERIFY_AGAINST_HASH 0x10
+
+
+#define SASL_AUXPROP_PLUG_VERSION 8
+
+/* default name for auxprop plug-in entry point is "sasl_auxprop_init"
+ * similar to sasl_server_plug_init model, except only returns one
+ * sasl_auxprop_plug_t structure;
+ */
+typedef int sasl_auxprop_init_t(const sasl_utils_t *utils,
+ int max_version,
+ int *out_version,
+ sasl_auxprop_plug_t **plug,
+ const char *plugname);
+
+/* add an auxiliary property plug-in
+ */
+LIBSASL_API int sasl_auxprop_add_plugin(const char *plugname,
+ sasl_auxprop_init_t *auxpropfunc);
+
+typedef void auxprop_info_callback_t (sasl_auxprop_plug_t *m,
+ sasl_info_callback_stage_t stage,
+ void *rock);
+
+/* Dump information about available auxprop plugins (separate functions are
+ used for canon and server authentication plugins) */
+LIBSASL_API int auxprop_plugin_info (const char *mech_list,
+ auxprop_info_callback_t *info_cb,
+ void *info_cb_rock);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SASLPLUG_H */
diff --git a/contrib/libs/sasl/include/saslutil.h b/contrib/libs/sasl/include/saslutil.h
new file mode 100644
index 0000000000..e0fa47c591
--- /dev/null
+++ b/contrib/libs/sasl/include/saslutil.h
@@ -0,0 +1,99 @@
+/* saslutil.h -- various utility functions in SASL library
+ */
+
+#ifndef SASLUTIL_H
+#define SASLUTIL_H 1
+
+#ifndef SASL_H
+#include "sasl.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* base64 decode
+ * in -- input data
+ * inlen -- length of input data
+ * out -- output data (may be same as in, must have enough space)
+ * outmax -- max size of output buffer
+ * result:
+ * outlen -- actual output length
+ *
+ * returns SASL_BADPROT on bad base64,
+ * SASL_BUFOVER if result won't fit
+ * SASL_OK on success
+ */
+LIBSASL_API int sasl_decode64(const char *in, unsigned inlen,
+ char *out, unsigned outmax, unsigned *outlen);
+
+/* base64 encode
+ * in -- input data
+ * inlen -- input data length
+ * out -- output buffer (will be NUL terminated)
+ * outmax -- max size of output buffer
+ * result:
+ * outlen -- gets actual length of output buffer (optional)
+ *
+ * Returns SASL_OK on success, SASL_BUFOVER if result won't fit
+ */
+LIBSASL_API int sasl_encode64(const char *in, unsigned inlen,
+ char *out, unsigned outmax, unsigned *outlen);
+
+/* make a challenge string (NUL terminated)
+ * buf -- buffer for result
+ * maxlen -- max length of result
+ * hostflag -- 0 = don't include hostname, 1 = include hostname
+ * returns final length or 0 if not enough space
+ */
+LIBSASL_API int sasl_mkchal(sasl_conn_t *conn, char *buf,
+ unsigned maxlen, unsigned hostflag);
+
+/* verify a string is valid UTF-8
+ * if len == 0, strlen(str) will be used.
+ * returns SASL_BADPROT on error, SASL_OK on success
+ */
+LIBSASL_API int sasl_utf8verify(const char *str, unsigned len);
+
+/* create random pool seeded with OS-based params */
+LIBSASL_API int sasl_randcreate(sasl_rand_t **rpool);
+
+/* free random pool from randcreate */
+LIBSASL_API void sasl_randfree(sasl_rand_t **rpool);
+
+/* seed random number generator */
+LIBSASL_API void sasl_randseed(sasl_rand_t *rpool, const char *seed,
+ unsigned len);
+
+/* generate random octets */
+LIBSASL_API void sasl_rand(sasl_rand_t *rpool, char *buf, unsigned len);
+
+/* churn data into random number generator */
+LIBSASL_API void sasl_churn(sasl_rand_t *rpool, const char *data,
+ unsigned len);
+
+/* erase a security sensitive buffer or password.
+ * Implementation may use recovery-resistant erase logic.
+ */
+LIBSASL_API void sasl_erasebuffer(char *pass, unsigned len);
+
+/* Lowercase string in place */
+LIBSASL_API char *sasl_strlower (char *val);
+
+LIBSASL_API int sasl_config_init(const char *filename);
+
+LIBSASL_API void sasl_config_done(void);
+
+#ifdef WIN32
+/* Just in case a different DLL defines this as well */
+#if defined(NEED_GETOPT)
+LIBSASL_API int getopt(int argc, char **argv, char *optstring);
+#endif
+LIBSASL_API char * getpass(const char *prompt);
+#endif /* WIN32 */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SASLUTIL_H */
diff --git a/contrib/libs/sasl/lib/auxprop.c b/contrib/libs/sasl/lib/auxprop.c
new file mode 100644
index 0000000000..1b0162db74
--- /dev/null
+++ b/contrib/libs/sasl/lib/auxprop.c
@@ -0,0 +1,1202 @@
+/* auxprop.c - auxilliary property support
+ * Rob Siemborski
+ */
+/*
+ * Copyright (c) 1998-2016 Carnegie Mellon University. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For permission or any other legal
+ * details, please contact
+ * Carnegie Mellon University
+ * Center for Technology Transfer and Enterprise Creation
+ * 4615 Forbes Avenue
+ * Suite 302
+ * Pittsburgh, PA 15213
+ * (412) 268-7393, fax: (412) 268-7395
+ * innovation@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Computing Services
+ * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+#include <sasl.h>
+#include <prop.h>
+#include <ctype.h>
+#include <stdio.h>
+#include "saslint.h"
+
+struct proppool
+{
+ struct proppool *next;
+
+ size_t size; /* Size of Block */
+ size_t unused; /* Space unused in this pool between end
+ * of char** area and beginning of char* area */
+
+ char data[1]; /* Variable Sized */
+};
+
+struct propctx {
+ struct propval *values;
+ struct propval *prev_val; /* Previous value used by set/setvalues */
+
+ unsigned used_values, allocated_values;
+
+ char *data_end; /* Bottom of string area in current pool */
+ char **list_end; /* Top of list area in current pool */
+
+ struct proppool *mem_base;
+ struct proppool *mem_cur;
+};
+
+typedef struct auxprop_plug_list
+{
+ struct auxprop_plug_list *next;
+ const sasl_auxprop_plug_t *plug;
+} auxprop_plug_list_t;
+
+static auxprop_plug_list_t *auxprop_head = NULL;
+
+static struct proppool *alloc_proppool(size_t size)
+{
+ struct proppool *ret;
+ /* minus 1 for the one that is already a part of the array
+ * in the struct */
+ size_t total_size = sizeof(struct proppool) + size - 1;
+ ret = sasl_ALLOC(total_size);
+ if(!ret) return NULL;
+
+ memset(ret, 0, total_size);
+
+ ret->size = ret->unused = size;
+
+ return ret;
+}
+
+/* Resize a proppool. Invalidates the unused value for this pool */
+static struct proppool *resize_proppool(struct proppool *pool, size_t size)
+{
+ struct proppool *ret;
+
+ if(pool->size >= size) return pool;
+ ret = sasl_REALLOC(pool, sizeof(struct proppool) + size);
+ if(!ret) return NULL;
+
+ ret->size = size;
+
+ return ret;
+}
+
+static int prop_init(struct propctx *ctx, unsigned estimate)
+{
+ const unsigned VALUES_SIZE = PROP_DEFAULT * sizeof(struct propval);
+
+ ctx->mem_base = alloc_proppool(VALUES_SIZE + estimate);
+ if(!ctx->mem_base) return SASL_NOMEM;
+
+ ctx->mem_cur = ctx->mem_base;
+
+ ctx->values = (struct propval *)ctx->mem_base->data;
+ ctx->mem_base->unused = ctx->mem_base->size - VALUES_SIZE;
+ ctx->allocated_values = PROP_DEFAULT;
+ ctx->used_values = 0;
+
+ ctx->data_end = ctx->mem_base->data + ctx->mem_base->size;
+ ctx->list_end = (char **)(ctx->mem_base->data + VALUES_SIZE);
+
+ ctx->prev_val = NULL;
+
+ return SASL_OK;
+}
+
+/* create a property context
+ * estimate -- an estimate of the storage needed for requests & responses
+ * 0 will use module default
+ * returns NULL on error
+ */
+struct propctx *prop_new(unsigned estimate)
+{
+ struct propctx *new_ctx;
+
+ if(!estimate) estimate = PROP_DEFAULT * 255;
+
+ new_ctx = sasl_ALLOC(sizeof(struct propctx));
+ if(!new_ctx) return NULL;
+
+ if(prop_init(new_ctx, estimate) != SASL_OK) {
+ prop_dispose(&new_ctx);
+ }
+
+ return new_ctx;
+}
+
+/* create new propctx which duplicates the contents of an existing propctx
+ * returns -1 on error
+ */
+int prop_dup(struct propctx *src_ctx, struct propctx **dst_ctx)
+{
+ struct proppool *pool;
+ struct propctx *retval = NULL;
+ unsigned i;
+ int result;
+ unsigned total_size = 0;
+ size_t values_size;
+
+ if(!src_ctx || !dst_ctx) return SASL_BADPARAM;
+
+ /* What is the total allocated size of src_ctx? */
+ pool = src_ctx->mem_base;
+ while(pool) {
+ total_size += (unsigned) pool->size;
+ pool = pool->next;
+ }
+
+ /* allocate the new context */
+ retval = prop_new(total_size);
+ if(!retval) return SASL_NOMEM;
+
+ retval->used_values = src_ctx->used_values;
+ retval->allocated_values = src_ctx->used_values + 1;
+
+ values_size = (retval->allocated_values * sizeof(struct propval));
+
+ retval->mem_base->unused = retval->mem_base->size - values_size;
+
+ retval->list_end = (char **)(retval->mem_base->data + values_size);
+ /* data_end should still be OK */
+
+ /* Now dup the values */
+ for(i=0; i<src_ctx->used_values; i++) {
+ retval->values[i].name = src_ctx->values[i].name;
+ result = prop_setvals(retval, retval->values[i].name,
+ src_ctx->values[i].values);
+ if(result != SASL_OK)
+ goto fail;
+ }
+
+ retval->prev_val = src_ctx->prev_val;
+
+ *dst_ctx = retval;
+ return SASL_OK;
+
+ fail:
+ if(retval) prop_dispose(&retval);
+ return result;
+}
+
+/*
+ * dispose of property context
+ * ctx -- is disposed and set to NULL; noop if ctx or *ctx is NULL
+ */
+void prop_dispose(struct propctx **ctx)
+{
+ struct proppool *tmp;
+
+ if(!ctx || !*ctx) return;
+
+ while((*ctx)->mem_base) {
+ tmp = (*ctx)->mem_base;
+ (*ctx)->mem_base = tmp->next;
+ sasl_FREE(tmp);
+ }
+
+ sasl_FREE(*ctx);
+ *ctx = NULL;
+
+ return;
+}
+
+/* Add property names to request
+ * ctx -- context from prop_new()
+ * names -- list of property names; must persist until context freed
+ * or requests cleared
+ *
+ * NOTE: may clear values from context as side-effect
+ * returns -1 on error
+ */
+int prop_request(struct propctx *ctx, const char **names)
+{
+ unsigned i, new_values, total_values;
+
+ if(!ctx || !names) return SASL_BADPARAM;
+
+ /* Count how many we need to add */
+ for(new_values=0; names[new_values]; new_values++);
+
+ /* Do we need to add ANY? */
+ if(!new_values) return SASL_OK;
+
+ /* We always want at least one extra to mark the end of the array */
+ total_values = new_values + ctx->used_values + 1;
+
+ /* Do we need to increase the size of our propval table? */
+ if(total_values > ctx->allocated_values) {
+ unsigned max_in_pool;
+
+ /* Do we need a larger base pool? */
+ max_in_pool = (unsigned) (ctx->mem_base->size / sizeof(struct propval));
+
+ if(total_values <= max_in_pool) {
+ /* Don't increase the size of the base pool, just use what
+ we need */
+ ctx->allocated_values = total_values;
+ ctx->mem_base->unused =
+ ctx->mem_base->size - (sizeof(struct propval)
+ * ctx->allocated_values);
+ } else {
+ /* We need to allocate more! */
+ unsigned new_alloc_length;
+ size_t new_size;
+
+ new_alloc_length = 2 * ctx->allocated_values;
+ while(total_values > new_alloc_length) {
+ new_alloc_length *= 2;
+ }
+
+ new_size = new_alloc_length * sizeof(struct propval);
+ ctx->mem_base = resize_proppool(ctx->mem_base, new_size);
+
+ if(!ctx->mem_base) {
+ ctx->values = NULL;
+ ctx->allocated_values = ctx->used_values = 0;
+ return SASL_NOMEM;
+ }
+
+ /* It worked! Update the structure! */
+ ctx->values = (struct propval *)ctx->mem_base->data;
+ ctx->allocated_values = new_alloc_length;
+ ctx->mem_base->unused = ctx->mem_base->size
+ - sizeof(struct propval) * ctx->allocated_values;
+ }
+
+ /* Clear out new propvals */
+ memset(&(ctx->values[ctx->used_values]), 0,
+ sizeof(struct propval) * (ctx->allocated_values - ctx->used_values));
+
+ /* Finish updating the context -- we've extended the list! */
+ /* ctx->list_end = (char **)(ctx->values + ctx->allocated_values); */
+ /* xxx test here */
+ ctx->list_end = (char **)(ctx->values + total_values);
+ }
+
+ /* Now do the copy, or referencing rather */
+ for(i=0;i<new_values;i++) {
+ unsigned j, flag;
+
+ flag = 0;
+
+ /* Check for dups */
+ for(j=0;j<ctx->used_values;j++) {
+ if(!strcmp(ctx->values[j].name, names[i])) {
+ flag = 1;
+ break;
+ }
+ }
+
+ /* We already have it... skip! */
+ if(flag) continue;
+
+ ctx->values[ctx->used_values++].name = names[i];
+ }
+
+ prop_clear(ctx, 0);
+
+ return SASL_OK;
+}
+
+/* return array of struct propval from the context
+ * return value persists until next call to
+ * prop_request, prop_clear or prop_dispose on context
+ */
+const struct propval *prop_get(struct propctx *ctx)
+{
+ if(!ctx) return NULL;
+
+ return ctx->values;
+}
+
+/* Fill in an array of struct propval based on a list of property names
+ * return value persists until next call to
+ * prop_request, prop_clear or prop_dispose on context
+ * returns -1 on error (no properties ever requested, ctx NULL, etc)
+ * returns number of matching properties which were found (values != NULL)
+ * if a name requested here was never requested by a prop_request, then
+ * the name field of the associated vals entry will be set to NULL
+ */
+int prop_getnames(struct propctx *ctx, const char **names,
+ struct propval *vals)
+{
+ int found_names = 0;
+
+ struct propval *cur = vals;
+ const char **curname;
+
+ if(!ctx || !names || !vals) return SASL_BADPARAM;
+
+ for(curname = names; *curname; curname++) {
+ struct propval *val;
+ for(val = ctx->values; val->name; val++) {
+ if(!strcmp(*curname,val->name)) {
+ found_names++;
+ memcpy(cur, val, sizeof(struct propval));
+ goto next;
+ }
+ }
+
+ /* If we are here, we didn't find it */
+ memset(cur, 0, sizeof(struct propval));
+
+ next:
+ cur++;
+ }
+
+ return found_names;
+}
+
+
+/* clear values and optionally requests from property context
+ * ctx -- property context
+ * requests -- 0 = don't clear requests, 1 = clear requests
+ */
+void prop_clear(struct propctx *ctx, int requests)
+{
+ struct proppool *new_pool, *tmp;
+ unsigned i;
+
+ /* We're going to need a new proppool once we reset things */
+ new_pool = alloc_proppool(ctx->mem_base->size +
+ (ctx->used_values+1) * sizeof(struct propval));
+ if (new_pool == NULL) {
+ _sasl_log(NULL, SASL_LOG_ERR, "failed to allocate memory\n");
+ exit(1);
+ }
+
+ if(requests) {
+ /* We're wiping the whole shebang */
+ ctx->used_values = 0;
+ } else {
+ /* Need to keep around old requets */
+ struct propval *new_values = (struct propval *)new_pool->data;
+ for(i=0; i<ctx->used_values; i++) {
+ new_values[i].name = ctx->values[i].name;
+ }
+ }
+
+ while(ctx->mem_base) {
+ tmp = ctx->mem_base;
+ ctx->mem_base = tmp->next;
+ sasl_FREE(tmp);
+ }
+
+ /* Update allocation-related metadata */
+ ctx->allocated_values = ctx->used_values+1;
+ new_pool->unused =
+ new_pool->size - (ctx->allocated_values * sizeof(struct propval));
+
+ /* Setup pointers for the values array */
+ ctx->values = (struct propval *)new_pool->data;
+ ctx->prev_val = NULL;
+
+ /* Setup the pools */
+ ctx->mem_base = ctx->mem_cur = new_pool;
+
+ /* Reset list_end and data_end for the new memory pool */
+ ctx->list_end =
+ (char **)((char *)ctx->mem_base->data + ctx->allocated_values * sizeof(struct propval));
+ ctx->data_end = (char *)ctx->mem_base->data + ctx->mem_base->size;
+
+ return;
+}
+
+/*
+ * erase the value of a property
+ */
+void prop_erase(struct propctx *ctx, const char *name)
+{
+ struct propval *val;
+ int i;
+
+ if(!ctx || !name) return;
+
+ for(val = ctx->values; val->name; val++) {
+ if(!strcmp(name,val->name)) {
+ if(!val->values) break;
+
+ /*
+ * Yes, this is casting away the const, but
+ * we should be okay because the only place this
+ * memory should be is in the proppool's
+ */
+ for(i=0;val->values[i];i++) {
+ memset((void *)(val->values[i]),0,strlen(val->values[i]));
+ val->values[i] = NULL;
+ }
+
+ val->values = NULL;
+ val->nvalues = 0;
+ val->valsize = 0;
+ break;
+ }
+ }
+
+ return;
+}
+
+/****fetcher interfaces****/
+
+/* format the requested property names into a string
+ * ctx -- context from prop_new()/prop_request()
+ * sep -- separator between property names (unused if none requested)
+ * seplen -- length of separator, if < 0 then strlen(sep) will be used
+ * outbuf -- output buffer
+ * outmax -- maximum length of output buffer including NUL terminator
+ * outlen -- set to length of output string excluding NUL terminator
+ * returns 0 on success and amount of additional space needed on failure
+ */
+int prop_format(struct propctx *ctx, const char *sep, int seplen,
+ char *outbuf, unsigned outmax, unsigned *outlen)
+{
+ unsigned needed, flag = 0;
+ struct propval *val;
+
+ if (!ctx || !outbuf) return SASL_BADPARAM;
+
+ if (!sep) seplen = 0;
+ if (seplen < 0) seplen = (int) strlen(sep);
+/* If seplen is negative now we have overflow.
+ But if you have a string longer than 2Gb, you are an idiot anyway */
+ if (seplen < 0) return SASL_BADPARAM;
+
+ needed = seplen * (ctx->used_values - 1);
+ for(val = ctx->values; val->name; val++) {
+ needed += (unsigned) strlen(val->name);
+ }
+
+ if(!outmax) return (needed + 1); /* Because of unsigned funkiness */
+ if(needed > (outmax - 1)) return (needed - (outmax - 1));
+
+ *outbuf = '\0';
+ if(outlen) *outlen = needed;
+
+ if(needed == 0) return SASL_OK;
+
+ for(val = ctx->values; val->name; val++) {
+ if(seplen && flag) {
+ strncat(outbuf, sep, seplen);
+ } else {
+ flag = 1;
+ }
+ strcat(outbuf, val->name);
+ }
+
+ return SASL_OK;
+}
+
+/* add a property value to the context
+ * ctx -- context from prop_new()/prop_request()
+ * name -- name of property to which value will be added
+ * if NULL, add to the same name as previous prop_set/setvals call
+ * value -- a value for the property; will be copied into context
+ * if NULL, remove existing values
+ * vallen -- length of value, if <= 0 then strlen(value) will be used
+ */
+int prop_set(struct propctx *ctx, const char *name,
+ const char *value, int vallen)
+{
+ struct propval *cur;
+
+ if(!ctx) return SASL_BADPARAM;
+ if(!name && !ctx->prev_val) return SASL_BADPARAM;
+
+ if(name) {
+ struct propval *val;
+
+ ctx->prev_val = NULL;
+
+ for(val = ctx->values; val->name; val++) {
+ if(!strcmp(name,val->name)){
+ ctx->prev_val = val;
+ break;
+ }
+ }
+
+ /* Couldn't find it! */
+ if(!ctx->prev_val) return SASL_BADPARAM;
+ }
+
+ cur = ctx->prev_val;
+
+ if(name) /* New Entry */ {
+ unsigned nvalues = 1; /* 1 for NULL entry */
+ const char **old_values = NULL;
+ char **tmp, **tmp2;
+ size_t size;
+
+ if(cur->values) {
+
+ if(!value) {
+ /* If we would be adding a null value, then we are done */
+ return SASL_OK;
+ }
+
+ old_values = cur->values;
+ tmp = (char **)cur->values;
+ while(*tmp) {
+ nvalues++;
+ tmp++;
+ }
+
+ }
+
+ if(value) {
+ nvalues++; /* for the new value */
+ }
+
+ size = nvalues * sizeof(char*);
+
+ if(size > ctx->mem_cur->unused) {
+ size_t needed;
+
+ for(needed = ctx->mem_cur->size * 2; needed < size; needed *= 2);
+
+ /* Allocate a new proppool */
+ ctx->mem_cur->next = alloc_proppool(needed);
+ if(!ctx->mem_cur->next) return SASL_NOMEM;
+
+ ctx->mem_cur = ctx->mem_cur->next;
+
+ ctx->list_end = (char **)ctx->mem_cur->data;
+ ctx->data_end = ctx->mem_cur->data + needed;
+ }
+
+ /* Grab the memory */
+ ctx->mem_cur->unused -= size;
+ cur->values = (const char **)ctx->list_end;
+ cur->values[nvalues - 1] = NULL;
+
+ /* Finish updating the context */
+ ctx->list_end = (char **)(cur->values + nvalues);
+
+ /* If we don't have an actual value to fill in, we are done */
+ if(!value)
+ return SASL_OK;
+
+ tmp2 = (char **)cur->values;
+ if(old_values) {
+ tmp = (char **)old_values;
+
+ while(*tmp) {
+ *tmp2 = *tmp;
+ tmp++; tmp2++;
+ }
+ }
+
+ /* Now allocate the last entry */
+ if(vallen <= 0)
+ size = (size_t)(strlen(value) + 1);
+ else
+ size = (size_t)(vallen + 1);
+
+ if(size > ctx->mem_cur->unused) {
+ size_t needed;
+
+ needed = ctx->mem_cur->size * 2;
+
+ while(needed < size) {
+ needed *= 2;
+ }
+
+ /* Allocate a new proppool */
+ ctx->mem_cur->next = alloc_proppool(needed);
+ if(!ctx->mem_cur->next) return SASL_NOMEM;
+
+ ctx->mem_cur = ctx->mem_cur->next;
+ ctx->list_end = (char **)ctx->mem_cur->data;
+ ctx->data_end = ctx->mem_cur->data + needed;
+ }
+
+ /* Update the data_end pointer */
+ ctx->data_end -= size;
+ ctx->mem_cur->unused -= size;
+
+ /* Copy and setup the new value! */
+ memcpy(ctx->data_end, value, size-1);
+ ctx->data_end[size - 1] = '\0';
+ cur->values[nvalues - 2] = ctx->data_end;
+
+ cur->nvalues++;
+ cur->valsize += ((unsigned) size - 1);
+ } else /* Appending an entry */ {
+ char **tmp;
+ size_t size;
+
+ /* If we are setting it to be NULL, we are done */
+ if(!value) return SASL_OK;
+
+ size = sizeof(char*);
+
+ /* Is it in the current pool, and will it fit in the unused space? */
+ if(size > ctx->mem_cur->unused &&
+ (void *)cur->values > (void *)(ctx->mem_cur->data) &&
+ (void *)cur->values < (void *)(ctx->mem_cur->data + ctx->mem_cur->size)) {
+ /* recursively call the not-fast way */
+ return prop_set(ctx, cur->name, value, vallen);
+ }
+
+ /* Note the invariant: the previous value list must be
+ at the top of the CURRENT pool at this point */
+
+ /* Grab the memory */
+ ctx->mem_cur->unused -= size;
+ ctx->list_end++;
+
+ *(ctx->list_end - 1) = NULL;
+ tmp = (ctx->list_end - 2);
+
+ /* Now allocate the last entry */
+ if(vallen <= 0)
+ size = strlen(value) + 1;
+ else
+ size = vallen + 1;
+
+ if(size > ctx->mem_cur->unused) {
+ size_t needed;
+
+ needed = ctx->mem_cur->size * 2;
+
+ while(needed < size) {
+ needed *= 2;
+ }
+
+ /* Allocate a new proppool */
+ ctx->mem_cur->next = alloc_proppool(needed);
+ if(!ctx->mem_cur->next) return SASL_NOMEM;
+
+ ctx->mem_cur = ctx->mem_cur->next;
+ ctx->list_end = (char **)ctx->mem_cur->data;
+ ctx->data_end = ctx->mem_cur->data + needed;
+ }
+
+ /* Update the data_end pointer */
+ ctx->data_end -= size;
+ ctx->mem_cur->unused -= size;
+
+ /* Copy and setup the new value! */
+ memcpy(ctx->data_end, value, size-1);
+ ctx->data_end[size - 1] = '\0';
+ *tmp = ctx->data_end;
+
+ cur->nvalues++;
+ cur->valsize += ((unsigned) size - 1);
+ }
+
+ return SASL_OK;
+}
+
+
+/* set the values for a property
+ * ctx -- context from prop_new()/prop_request()
+ * name -- name of property to which value will be added
+ * if NULL, add to the same name as previous prop_set/setvals call
+ * values -- array of values, ending in NULL. Each value is a NUL terminated
+ * string
+ */
+int prop_setvals(struct propctx *ctx, const char *name,
+ const char **values)
+{
+ const char **val = values;
+ int result = SASL_OK;
+
+ if(!ctx) return SASL_BADPARAM;
+
+ /* If they want us to add no values, we can do that */
+ if(!values) return SASL_OK;
+
+ /* Basically, use prop_set to do all our dirty work for us */
+ if(name) {
+ result = prop_set(ctx, name, *val, 0);
+ val++;
+ }
+
+ for(;*val;val++) {
+ if(result != SASL_OK) return result;
+ result = prop_set(ctx, NULL, *val,0);
+ }
+
+ return result;
+}
+
+/* Request a set of auxiliary properties
+ * conn connection context
+ * propnames list of auxiliary property names to request ending with
+ * NULL.
+ *
+ * Subsequent calls will add items to the request list. Call with NULL
+ * to clear the request list.
+ *
+ * errors
+ * SASL_OK -- success
+ * SASL_BADPARAM -- bad count/conn parameter
+ * SASL_NOMEM -- out of memory
+ */
+int sasl_auxprop_request(sasl_conn_t *conn, const char **propnames)
+{
+ int result;
+ sasl_server_conn_t *sconn;
+
+ if(!conn) return SASL_BADPARAM;
+ if(conn->type != SASL_CONN_SERVER)
+ PARAMERROR(conn);
+
+ sconn = (sasl_server_conn_t *)conn;
+
+ if(!propnames) {
+ prop_clear(sconn->sparams->propctx,1);
+ return SASL_OK;
+ }
+
+ result = prop_request(sconn->sparams->propctx, propnames);
+ RETURN(conn, result);
+}
+
+
+/* Returns current auxiliary property context.
+ * Use functions in prop.h to access content
+ *
+ * if authentication hasn't completed, property values may be empty/NULL
+ *
+ * properties not recognized by active plug-ins will be left empty/NULL
+ *
+ * returns NULL if conn is invalid.
+ */
+struct propctx *sasl_auxprop_getctx(sasl_conn_t *conn)
+{
+ sasl_server_conn_t *sconn;
+
+ if(!conn || conn->type != SASL_CONN_SERVER) return NULL;
+
+ sconn = (sasl_server_conn_t *)conn;
+
+ return sconn->sparams->propctx;
+}
+
+/* add an auxiliary property plugin */
+int sasl_auxprop_add_plugin(const char *plugname,
+ sasl_auxprop_init_t *auxpropfunc)
+{
+ int result, out_version;
+ auxprop_plug_list_t *new_item;
+ sasl_auxprop_plug_t *plug;
+
+ result = auxpropfunc(sasl_global_utils, SASL_AUXPROP_PLUG_VERSION,
+ &out_version, &plug, plugname);
+
+ /* Check if out_version is too old.
+ We only support the current at the moment */
+ if (result == SASL_OK && out_version < SASL_AUXPROP_PLUG_VERSION) {
+ result = SASL_BADVERS;
+ }
+
+ if(result != SASL_OK) {
+ _sasl_log(NULL, SASL_LOG_ERR, "auxpropfunc error %s\n",
+ sasl_errstring(result, NULL, NULL));
+ return result;
+ }
+
+ /* We require that this function is implemented */
+ if(!plug->auxprop_lookup) return SASL_BADPROT;
+
+ new_item = sasl_ALLOC(sizeof(auxprop_plug_list_t));
+ if(!new_item) return SASL_NOMEM;
+
+ /* These will load from least-important to most important */
+ new_item->plug = plug;
+ new_item->next = auxprop_head;
+ auxprop_head = new_item;
+
+ return SASL_OK;
+}
+
+void _sasl_auxprop_free()
+{
+ auxprop_plug_list_t *ptr, *ptr_next;
+
+ for(ptr = auxprop_head; ptr; ptr = ptr_next) {
+ ptr_next = ptr->next;
+ if(ptr->plug->auxprop_free)
+ ptr->plug->auxprop_free(ptr->plug->glob_context,
+ sasl_global_utils);
+ sasl_FREE(ptr);
+ }
+
+ auxprop_head = NULL;
+}
+
+/* Return the updated account status based on the current ("so far") and
+ the specific status returned by the latest auxprop call */
+static int
+_sasl_account_status (int current_status,
+ int specific_status)
+{
+ switch (specific_status) {
+ case SASL_NOVERIFY:
+ specific_status = SASL_OK;
+ /* fall through */
+ case SASL_OK:
+ if (current_status == SASL_NOMECH ||
+ current_status == SASL_NOUSER) {
+ current_status = specific_status;
+ }
+ break;
+
+ case SASL_NOUSER:
+ if (current_status == SASL_NOMECH) {
+ current_status = specific_status;
+ }
+ break;
+
+ /* NOTE: The disabled flag sticks, unless we hit an error */
+ case SASL_DISABLED:
+ if (current_status == SASL_NOMECH ||
+ current_status == SASL_NOUSER ||
+ current_status == SASL_OK) {
+ current_status = specific_status;
+ }
+ break;
+
+ case SASL_NOMECH:
+ /* ignore */
+ break;
+
+ /* SASL_UNAVAIL overrides everything */
+ case SASL_UNAVAIL:
+ current_status = specific_status;
+ break;
+
+ default:
+ current_status = specific_status;
+ break;
+ }
+ return (current_status);
+}
+
+/* Do the callbacks for auxprop lookups */
+int _sasl_auxprop_lookup(sasl_server_params_t *sparams,
+ unsigned flags,
+ const char *user, unsigned ulen)
+{
+ sasl_getopt_t *getopt;
+ int ret, found = 0;
+ void *context;
+ const char *plist = NULL;
+ auxprop_plug_list_t *ptr;
+ int result = SASL_NOMECH;
+
+ if(_sasl_getcallback(sparams->utils->conn,
+ SASL_CB_GETOPT,
+ (sasl_callback_ft *)&getopt,
+ &context) == SASL_OK) {
+ ret = getopt(context, NULL, "auxprop_plugin", &plist, NULL);
+ if(ret != SASL_OK) plist = NULL;
+ }
+
+ if(!plist) {
+ /* Do lookup in all plugins */
+
+ /* TODO: Ideally, each auxprop plugin should be marked if its failure
+ should be ignored or treated as a fatal error of the whole lookup. */
+ for(ptr = auxprop_head; ptr; ptr = ptr->next) {
+ found=1;
+ ret = ptr->plug->auxprop_lookup(ptr->plug->glob_context,
+ sparams, flags, user, ulen);
+ result = _sasl_account_status (result, ret);
+ }
+ } else {
+ char *pluginlist = NULL, *freeptr = NULL, *thisplugin = NULL;
+
+ if(_sasl_strdup(plist, &pluginlist, NULL) != SASL_OK) return SASL_NOMEM;
+ thisplugin = freeptr = pluginlist;
+
+ /* Do lookup in all *specified* plugins, in order */
+ while(*thisplugin) {
+ char *p;
+ int last=0;
+
+ while(*thisplugin && isspace((int)*thisplugin)) thisplugin++;
+ if(!(*thisplugin)) break;
+
+ for(p = thisplugin;*p != '\0' && !isspace((int)*p); p++);
+ if(*p == '\0') last = 1;
+ else *p='\0';
+
+ for(ptr = auxprop_head; ptr; ptr = ptr->next) {
+ /* Skip non-matching plugins */
+ if(!ptr->plug->name
+ || strcasecmp(ptr->plug->name, thisplugin))
+ continue;
+
+ found=1;
+ ret = ptr->plug->auxprop_lookup(ptr->plug->glob_context,
+ sparams, flags, user, ulen);
+ result = _sasl_account_status (result, ret);
+ }
+
+ if(last) break;
+
+ thisplugin = p+1;
+ }
+
+ sasl_FREE(freeptr);
+ }
+
+ if(!found) {
+ _sasl_log(sparams->utils->conn, SASL_LOG_DEBUG,
+ "could not find auxprop plugin, was searching for '%s'",
+ plist ? plist : "[all]");
+ }
+
+ return result;
+}
+
+/* Do the callbacks for auxprop stores */
+int sasl_auxprop_store(sasl_conn_t *conn,
+ struct propctx *ctx, const char *user)
+{
+ sasl_getopt_t *getopt;
+ int ret;
+ void *context;
+ const char *plist = NULL;
+ auxprop_plug_list_t *ptr;
+ sasl_server_params_t *sparams = NULL;
+ unsigned userlen = 0;
+ int num_constraint_violations = 0;
+ int total_plugins = 0;
+
+ if (ctx) {
+ if (!conn || !user)
+ return SASL_BADPARAM;
+
+ sparams = ((sasl_server_conn_t *) conn)->sparams;
+ userlen = (unsigned) strlen(user);
+ }
+
+ /* Pickup getopt callback from the connection, if conn is not NULL */
+ if(_sasl_getcallback(conn, SASL_CB_GETOPT, (sasl_callback_ft *)&getopt, &context) == SASL_OK) {
+ ret = getopt(context, NULL, "auxprop_plugin", &plist, NULL);
+ if(ret != SASL_OK) plist = NULL;
+ }
+
+ ret = SASL_OK;
+ if(!plist) {
+ /* Do store in all plugins */
+ for(ptr = auxprop_head; ptr && ret == SASL_OK; ptr = ptr->next) {
+ total_plugins++;
+ if (ptr->plug->auxprop_store) {
+ ret = ptr->plug->auxprop_store(ptr->plug->glob_context,
+ sparams, ctx, user, userlen);
+ if (ret == SASL_CONSTRAINT_VIOLAT) {
+ ret = SASL_OK;
+ num_constraint_violations++;
+ }
+ }
+ }
+ } else {
+ char *pluginlist = NULL, *freeptr = NULL, *thisplugin = NULL;
+
+ if(_sasl_strdup(plist, &pluginlist, NULL) != SASL_OK) return SASL_FAIL;
+ thisplugin = freeptr = pluginlist;
+
+ /* Do store in all *specified* plugins, in order */
+ while(*thisplugin) {
+ char *p;
+ int last=0;
+
+ while(*thisplugin && isspace((int)*thisplugin)) thisplugin++;
+ if(!(*thisplugin)) break;
+
+ for(p = thisplugin;*p != '\0' && !isspace((int)*p); p++);
+ if(*p == '\0') last = 1;
+ else *p='\0';
+
+ for(ptr = auxprop_head; ptr && ret == SASL_OK; ptr = ptr->next) {
+ /* Skip non-matching plugins */
+ if((!ptr->plug->name
+ || strcasecmp(ptr->plug->name, thisplugin)))
+ continue;
+
+ total_plugins++;
+ if (ptr->plug->auxprop_store) {
+ ret = ptr->plug->auxprop_store(ptr->plug->glob_context,
+ sparams, ctx, user, userlen);
+ if (ret == SASL_CONSTRAINT_VIOLAT) {
+ ret = SASL_OK;
+ num_constraint_violations++;
+ }
+ }
+ }
+
+ if(last) break;
+
+ thisplugin = p+1;
+ }
+
+ sasl_FREE(freeptr);
+ }
+
+ if(total_plugins == 0) {
+ _sasl_log(NULL, SASL_LOG_ERR,
+ "could not find auxprop plugin, was searching for %s",
+ plist ? plist : "[all]");
+ return SASL_FAIL;
+ } else if (total_plugins == num_constraint_violations) {
+ ret = SASL_CONSTRAINT_VIOLAT;
+ }
+
+ return ret;
+}
+
+/* It would be nice if we can show other information like Author, Company, Year, plugin version */
+static void
+_sasl_print_mechanism (sasl_auxprop_plug_t *m,
+ sasl_info_callback_stage_t stage,
+ void *rock __attribute__((unused))
+)
+{
+ if (stage == SASL_INFO_LIST_START) {
+ printf ("List of auxprop plugins follows\n");
+ return;
+ } else if (stage == SASL_INFO_LIST_END) {
+ return;
+ }
+
+ /* Process the mechanism */
+ printf ("Plugin \"%s\" ", m->name);
+
+#ifdef NOT_YET
+ switch (m->condition) {
+ case SASL_OK:
+ printf ("[loaded]");
+ break;
+
+ case SASL_CONTINUE:
+ printf ("[delayed]");
+ break;
+
+ case SASL_NOUSER:
+ printf ("[no users]");
+ break;
+
+ default:
+ printf ("[unknown]");
+ break;
+ }
+#endif
+
+ printf (", \tAPI version: %d\n", /* m->version */ SASL_AUXPROP_PLUG_VERSION);
+
+ /* TODO - Update for auxprop_export, etc. */
+ printf ("\tsupports store: %s\n",
+ (m->auxprop_store != NULL) ? "yes" : "no"
+ );
+
+ /* No features defined yet */
+#ifdef NOT_YET
+ printf ("\n\tfeatures:");
+#endif
+
+ printf ("\n");
+}
+
+/* Dump information about available auxprop plugins (separate functions are
+ used for canon and server authentication plugins) */
+int auxprop_plugin_info (
+ const char *c_mech_list, /* space separated mechanism list or NULL for ALL */
+ auxprop_info_callback_t *info_cb,
+ void *info_cb_rock
+)
+{
+ auxprop_plug_list_t *m;
+ sasl_auxprop_plug_t plug_data;
+ char * cur_mech;
+ char *mech_list = NULL;
+ char * p;
+
+ if (info_cb == NULL) {
+ info_cb = _sasl_print_mechanism;
+ }
+
+ if (auxprop_head != NULL) {
+ info_cb (NULL, SASL_INFO_LIST_START, info_cb_rock);
+
+ if (c_mech_list == NULL) {
+ m = auxprop_head; /* m point to beginning of the list */
+
+ while (m != NULL) {
+ /* TODO: Need to be careful when dealing with auxprop_export, etc. */
+ memcpy (&plug_data, m->plug, sizeof(plug_data));
+
+ info_cb (&plug_data, SASL_INFO_LIST_MECH, info_cb_rock);
+
+ m = m->next;
+ }
+ } else {
+ mech_list = strdup(c_mech_list);
+
+ cur_mech = mech_list;
+
+ while (cur_mech != NULL) {
+ p = strchr (cur_mech, ' ');
+ if (p != NULL) {
+ *p = '\0';
+ p++;
+ }
+
+ m = auxprop_head; /* m point to beginning of the list */
+
+ while (m != NULL) {
+ if (strcasecmp (cur_mech, m->plug->name) == 0) {
+ memcpy (&plug_data, m->plug, sizeof(plug_data));
+
+ info_cb (&plug_data, SASL_INFO_LIST_MECH, info_cb_rock);
+ }
+
+ m = m->next;
+ }
+
+ cur_mech = p;
+ }
+
+ free (mech_list);
+ }
+
+ info_cb (NULL, SASL_INFO_LIST_END, info_cb_rock);
+
+ return (SASL_OK);
+ }
+
+ return (SASL_NOTINIT);
+}
diff --git a/contrib/libs/sasl/lib/canonusr.c b/contrib/libs/sasl/lib/canonusr.c
new file mode 100644
index 0000000000..66f7e112a6
--- /dev/null
+++ b/contrib/libs/sasl/lib/canonusr.c
@@ -0,0 +1,465 @@
+/* canonusr.c - user canonicalization support
+ * Rob Siemborski
+ */
+/*
+ * Copyright (c) 1998-2016 Carnegie Mellon University. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For permission or any other legal
+ * details, please contact
+ * Carnegie Mellon University
+ * Center for Technology Transfer and Enterprise Creation
+ * 4615 Forbes Avenue
+ * Suite 302
+ * Pittsburgh, PA 15213
+ * (412) 268-7393, fax: (412) 268-7395
+ * innovation@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Computing Services
+ * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+#include <sasl.h>
+#include <string.h>
+#include <ctype.h>
+#include <prop.h>
+#include <stdio.h>
+
+#include "saslint.h"
+
+typedef struct canonuser_plug_list
+{
+ struct canonuser_plug_list *next;
+ char name[PATH_MAX];
+ const sasl_canonuser_plug_t *plug;
+} canonuser_plug_list_t;
+
+static canonuser_plug_list_t *canonuser_head = NULL;
+
+/* default behavior:
+ * eliminate leading & trailing whitespace,
+ * null-terminate, and get into the outparams
+ * (handled by INTERNAL plugin) */
+/* a zero ulen or alen indicates that it is strlen(value) */
+int _sasl_canon_user(sasl_conn_t *conn,
+ const char *user, unsigned ulen,
+ unsigned flags,
+ sasl_out_params_t *oparams)
+{
+ canonuser_plug_list_t *ptr;
+ sasl_server_conn_t *sconn = NULL;
+ sasl_client_conn_t *cconn = NULL;
+ sasl_canon_user_t *cuser_cb;
+ sasl_getopt_t *getopt;
+ void *context;
+ int result;
+ const char *plugin_name = NULL;
+ char *user_buf;
+ unsigned *lenp;
+
+ if(!conn) return SASL_BADPARAM;
+ if(!user || !oparams) return SASL_BADPARAM;
+
+ if(flags & SASL_CU_AUTHID) {
+ user_buf = conn->authid_buf;
+ lenp = &(oparams->alen);
+ } else if (flags & SASL_CU_AUTHZID) {
+ user_buf = conn->user_buf;
+ lenp = &(oparams->ulen);
+ } else {
+ return SASL_BADPARAM;
+ }
+
+ if (conn->type == SASL_CONN_SERVER)
+ sconn = (sasl_server_conn_t *)conn;
+ else if (conn->type == SASL_CONN_CLIENT)
+ cconn = (sasl_client_conn_t *)conn;
+ else return SASL_FAIL;
+
+ if(!ulen) ulen = (unsigned int)strlen(user);
+
+ /* check to see if we have a callback to make*/
+ result = _sasl_getcallback(conn,
+ SASL_CB_CANON_USER,
+ (sasl_callback_ft *)&cuser_cb,
+ &context);
+ if(result == SASL_OK && cuser_cb) {
+ result = cuser_cb(conn,
+ context,
+ user,
+ ulen,
+ flags,
+ (sconn ?
+ sconn->user_realm :
+ NULL),
+ user_buf,
+ CANON_BUF_SIZE,
+ lenp);
+
+
+ if (result != SASL_OK) return result;
+
+ /* Point the input copy at the stored buffer */
+ user = user_buf;
+ ulen = *lenp;
+ }
+
+ /* which plugin are we supposed to use? */
+ result = _sasl_getcallback(conn,
+ SASL_CB_GETOPT,
+ (sasl_callback_ft *)&getopt,
+ &context);
+ if (result == SASL_OK && getopt) {
+ getopt(context, NULL, "canon_user_plugin", &plugin_name, NULL);
+ }
+
+ if (!plugin_name) {
+ /* Use Default */
+ plugin_name = "INTERNAL";
+ }
+
+ for (ptr = canonuser_head; ptr; ptr = ptr->next) {
+ /* A match is if we match the internal name of the plugin, or if
+ * we match the filename (old-style) */
+ if ((ptr->plug->name && !strcmp(plugin_name, ptr->plug->name))
+ || !strcmp(plugin_name, ptr->name)) break;
+ }
+
+ /* We clearly don't have this one! */
+ if (!ptr) {
+ sasl_seterror(conn, 0, "desired canon_user plugin %s not found",
+ plugin_name);
+ return SASL_NOMECH;
+ }
+
+ if (sconn) {
+ /* we're a server */
+ result = ptr->plug->canon_user_server(ptr->plug->glob_context,
+ sconn->sparams,
+ user, ulen,
+ flags,
+ user_buf,
+ CANON_BUF_SIZE, lenp);
+ } else {
+ /* we're a client */
+ result = ptr->plug->canon_user_client(ptr->plug->glob_context,
+ cconn->cparams,
+ user, ulen,
+ flags,
+ user_buf,
+ CANON_BUF_SIZE, lenp);
+ }
+
+ if (result != SASL_OK) return result;
+
+ if ((flags & SASL_CU_AUTHID) && (flags & SASL_CU_AUTHZID)) {
+ /* We did both, so we need to copy the result into
+ * the buffer for the authzid from the buffer for the authid */
+ memcpy(conn->user_buf, conn->authid_buf, CANON_BUF_SIZE);
+ oparams->ulen = oparams->alen;
+ }
+
+ /* Set the appropriate oparams (lengths have already been set by lenp) */
+ if (flags & SASL_CU_AUTHID) {
+ oparams->authid = conn->authid_buf;
+ }
+
+ if (flags & SASL_CU_AUTHZID) {
+ oparams->user = conn->user_buf;
+ }
+
+ RETURN(conn, result);
+}
+
+/* Lookup all properties for authentication and/or authorization identity. */
+static int _sasl_auxprop_lookup_user_props (sasl_conn_t *conn,
+ unsigned flags,
+ sasl_out_params_t *oparams)
+{
+ sasl_server_conn_t *sconn = NULL;
+ int result = SASL_OK;
+
+ if (!conn) return SASL_BADPARAM;
+ if (!oparams) return SASL_BADPARAM;
+
+#ifndef macintosh
+ if (conn->type == SASL_CONN_SERVER) sconn = (sasl_server_conn_t *)conn;
+
+ /* do auxprop lookups (server only) */
+ if (sconn) {
+ int authz_result;
+ unsigned auxprop_lookup_flags = flags & SASL_CU_ASIS_MASK;
+
+ if (flags & SASL_CU_OVERRIDE) {
+ auxprop_lookup_flags |= SASL_AUXPROP_OVERRIDE;
+ }
+
+ if (flags & SASL_CU_AUTHID) {
+ result = _sasl_auxprop_lookup(sconn->sparams,
+ auxprop_lookup_flags,
+ oparams->authid,
+ oparams->alen);
+ } else {
+ result = SASL_CONTINUE;
+ }
+ if (flags & SASL_CU_AUTHZID) {
+ authz_result = _sasl_auxprop_lookup(sconn->sparams,
+ auxprop_lookup_flags | SASL_AUXPROP_AUTHZID,
+ oparams->user,
+ oparams->ulen);
+
+ if (result == SASL_CONTINUE) {
+ /* Only SASL_CU_AUTHZID was requested.
+ The authz_result value is authoritative. */
+ result = authz_result;
+ } else if (result == SASL_OK && authz_result != SASL_NOUSER) {
+ /* Use the authz_result value, unless "result"
+ already contains an error */
+ result = authz_result;
+ }
+ }
+
+ if ((flags & SASL_CU_EXTERNALLY_VERIFIED) && (result == SASL_NOUSER || result == SASL_NOMECH)) {
+ /* The called has explicitly told us that the authentication identity
+ was already verified or will be verified independently.
+ So a failure to retrieve any associated properties
+ is not an error. For example the caller is using Kerberos to verify user,
+ but the LDAPDB/SASLDB auxprop plugin doesn't contain any auxprops for
+ the user.
+ Another case is PLAIN/LOGIN not using auxprop to verify user passwords. */
+ result = SASL_OK;
+ }
+ }
+#endif
+
+ RETURN(conn, result);
+}
+
+/* default behavior:
+ * Eliminate leading & trailing whitespace,
+ * null-terminate, and get into the outparams
+ * (handled by INTERNAL plugin).
+ *
+ * Server only: Also does auxprop lookups once username
+ * is canonicalized. */
+int _sasl_canon_user_lookup (sasl_conn_t *conn,
+ const char *user,
+ unsigned ulen,
+ unsigned flags,
+ sasl_out_params_t *oparams)
+{
+ int result;
+
+ result = _sasl_canon_user (conn,
+ user,
+ ulen,
+ flags,
+ oparams);
+ if (result == SASL_OK) {
+ result = _sasl_auxprop_lookup_user_props (conn,
+ flags,
+ oparams);
+ }
+
+ RETURN(conn, result);
+}
+
+void _sasl_canonuser_free()
+{
+ canonuser_plug_list_t *ptr, *ptr_next;
+
+ for(ptr = canonuser_head; ptr; ptr = ptr_next) {
+ ptr_next = ptr->next;
+ if(ptr->plug->canon_user_free)
+ ptr->plug->canon_user_free(ptr->plug->glob_context,
+ sasl_global_utils);
+ sasl_FREE(ptr);
+ }
+
+ canonuser_head = NULL;
+}
+
+int sasl_canonuser_add_plugin(const char *plugname,
+ sasl_canonuser_init_t *canonuserfunc)
+{
+ int result, out_version;
+ canonuser_plug_list_t *new_item;
+ sasl_canonuser_plug_t *plug;
+
+ if(!plugname || strlen(plugname) > (PATH_MAX - 1)) {
+ sasl_seterror(NULL, 0,
+ "bad plugname passed to sasl_canonuser_add_plugin\n");
+ return SASL_BADPARAM;
+ }
+
+ result = canonuserfunc(sasl_global_utils, SASL_CANONUSER_PLUG_VERSION,
+ &out_version, &plug, plugname);
+
+ if(result != SASL_OK) {
+ _sasl_log(NULL, SASL_LOG_ERR, "%s_canonuser_plug_init() failed in sasl_canonuser_add_plugin(): %z\n",
+ plugname, result);
+ return result;
+ }
+
+ if(!plug->canon_user_server && !plug->canon_user_client) {
+ /* We need at least one of these implemented */
+ _sasl_log(NULL, SASL_LOG_ERR,
+ "canonuser plugin '%s' without either client or server side", plugname);
+ return SASL_BADPROT;
+ }
+
+ new_item = sasl_ALLOC(sizeof(canonuser_plug_list_t));
+ if(!new_item) return SASL_NOMEM;
+
+ strncpy(new_item->name, plugname, PATH_MAX - 1);
+ new_item->name[strlen(plugname)] = '\0';
+
+ new_item->plug = plug;
+ new_item->next = canonuser_head;
+ canonuser_head = new_item;
+
+ return SASL_OK;
+}
+
+#ifdef MIN
+#undef MIN
+#endif
+#define MIN(a,b) (((a) < (b))? (a):(b))
+
+static int _canonuser_internal(const sasl_utils_t *utils,
+ const char *user, unsigned ulen,
+ unsigned flags __attribute__((unused)),
+ char *out_user,
+ unsigned out_umax, unsigned *out_ulen)
+{
+ unsigned i;
+ char *in_buf, *userin;
+ const char *begin_u;
+ unsigned u_apprealm = 0;
+ sasl_server_conn_t *sconn = NULL;
+
+ if(!utils || !user) return SASL_BADPARAM;
+
+ in_buf = sasl_ALLOC((ulen + 2) * sizeof(char));
+ if(!in_buf) return SASL_NOMEM;
+
+ userin = in_buf;
+
+ memcpy(userin, user, ulen);
+ userin[ulen] = '\0';
+
+ /* Strip User ID */
+ for(i=0;isspace((int)userin[i]) && i<ulen;i++);
+ begin_u = &(userin[i]);
+ if(i>0) ulen -= i;
+
+ for(;ulen > 0 && isspace((int)begin_u[ulen-1]); ulen--);
+ if(begin_u == &(userin[ulen])) {
+ sasl_FREE(in_buf);
+ utils->seterror(utils->conn, 0, "All-whitespace username.");
+ return SASL_FAIL;
+ }
+
+ if(utils->conn && utils->conn->type == SASL_CONN_SERVER)
+ sconn = (sasl_server_conn_t *)utils->conn;
+
+ /* Need to append realm if necessary (see sasl.h) */
+ if(sconn && sconn->user_realm && !strchr(user, '@')) {
+ u_apprealm = (unsigned) strlen(sconn->user_realm) + 1;
+ }
+
+ /* Now Copy */
+ memcpy(out_user, begin_u, MIN(ulen, out_umax));
+ if(sconn && u_apprealm) {
+ if(ulen >= out_umax) return SASL_BUFOVER;
+ out_user[ulen] = '@';
+ memcpy(&(out_user[ulen+1]), sconn->user_realm,
+ MIN(u_apprealm-1, out_umax-ulen-1));
+ }
+ out_user[MIN(ulen + u_apprealm,out_umax)] = '\0';
+
+ if(ulen + u_apprealm > out_umax) return SASL_BUFOVER;
+
+ if(out_ulen) *out_ulen = MIN(ulen + u_apprealm,out_umax);
+
+ sasl_FREE(in_buf);
+ return SASL_OK;
+}
+
+static int _cu_internal_server(void *glob_context __attribute__((unused)),
+ sasl_server_params_t *sparams,
+ const char *user, unsigned ulen,
+ unsigned flags,
+ char *out_user,
+ unsigned out_umax, unsigned *out_ulen)
+{
+ return _canonuser_internal(sparams->utils,
+ user, ulen,
+ flags, out_user, out_umax, out_ulen);
+}
+
+static int _cu_internal_client(void *glob_context __attribute__((unused)),
+ sasl_client_params_t *cparams,
+ const char *user, unsigned ulen,
+ unsigned flags,
+ char *out_user,
+ unsigned out_umax, unsigned *out_ulen)
+{
+ return _canonuser_internal(cparams->utils,
+ user, ulen,
+ flags, out_user, out_umax, out_ulen);
+}
+
+static sasl_canonuser_plug_t canonuser_internal_plugin = {
+ 0, /* features */
+ 0, /* spare */
+ NULL, /* glob_context */
+ "INTERNAL", /* name */
+ NULL, /* canon_user_free */
+ _cu_internal_server,
+ _cu_internal_client,
+ NULL,
+ NULL,
+ NULL
+};
+
+int internal_canonuser_init(const sasl_utils_t *utils __attribute__((unused)),
+ int max_version,
+ int *out_version,
+ sasl_canonuser_plug_t **plug,
+ const char *plugname __attribute__((unused)))
+{
+ if(!out_version || !plug) return SASL_BADPARAM;
+
+ if(max_version < SASL_CANONUSER_PLUG_VERSION) return SASL_BADVERS;
+
+ *out_version = SASL_CANONUSER_PLUG_VERSION;
+
+ *plug = &canonuser_internal_plugin;
+
+ return SASL_OK;
+}
diff --git a/contrib/libs/sasl/lib/checkpw.c b/contrib/libs/sasl/lib/checkpw.c
new file mode 100644
index 0000000000..a13f526b7c
--- /dev/null
+++ b/contrib/libs/sasl/lib/checkpw.c
@@ -0,0 +1,1110 @@
+/* SASL server API implementation
+ * Rob Siemborski
+ * Tim Martin
+ */
+/*
+ * Copyright (c) 1998-2016 Carnegie Mellon University. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For permission or any other legal
+ * details, please contact
+ * Carnegie Mellon University
+ * Center for Technology Transfer and Enterprise Creation
+ * 4615 Forbes Avenue
+ * Suite 302
+ * Pittsburgh, PA 15213
+ * (412) 268-7393, fax: (412) 268-7395
+ * innovation@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Computing Services
+ * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+/* checkpw stuff */
+
+#include <stdio.h>
+#include "sasl.h"
+#include "saslutil.h"
+#include "saslplug.h"
+#include "saslint.h"
+
+#include <assert.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#ifdef USE_DOORS
+#include <sys/mman.h>
+#error #include <door.h>
+#endif
+
+#include <stdlib.h>
+
+#ifndef WIN32
+#include <strings.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/un.h>
+#else
+#include <string.h>
+#endif
+
+#include <limits.h>
+#include <sys/types.h>
+#include <ctype.h>
+
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif /* HAVE_PWD_H */
+#ifdef HAVE_SHADOW_H
+#include <shadow.h>
+#endif /* HAVE_SHADOW_H */
+
+#if defined(HAVE_PWCHECK) || defined(HAVE_SASLAUTHD) || defined(HAVE_AUTHDAEMON)
+# include <errno.h>
+# include <sys/types.h>
+# include <sys/socket.h>
+# include <sys/un.h>
+# ifdef HAVE_UNISTD_H
+# include <unistd.h>
+# endif
+#endif
+
+
+/* we store the following secret to check plaintext passwords:
+ *
+ * <salt> \0 <secret>
+ *
+ * where <secret> = MD5(<salt>, "sasldb", <pass>)
+ */
+static int _sasl_make_plain_secret(const char *salt,
+ const char *passwd, size_t passlen,
+ sasl_secret_t **secret)
+{
+ MD5_CTX ctx;
+ unsigned sec_len = 16 + 1 + 16; /* salt + "\0" + hash */
+
+ *secret = (sasl_secret_t *) sasl_ALLOC(sizeof(sasl_secret_t) +
+ sec_len * sizeof(char));
+ if (*secret == NULL) {
+ return SASL_NOMEM;
+ }
+
+ _sasl_MD5Init(&ctx);
+ _sasl_MD5Update(&ctx, (const unsigned char *) salt, 16);
+ _sasl_MD5Update(&ctx, (const unsigned char *) "sasldb", 6);
+ _sasl_MD5Update(&ctx, (const unsigned char *) passwd, (unsigned int) passlen);
+ memcpy((*secret)->data, salt, 16);
+ (*secret)->data[16] = '\0';
+ _sasl_MD5Final((*secret)->data + 17, &ctx);
+ (*secret)->len = sec_len;
+
+ return SASL_OK;
+}
+
+/* verify user password using auxprop plugins
+ */
+static int auxprop_verify_password(sasl_conn_t *conn,
+ const char *userstr,
+ const char *passwd,
+ const char *service __attribute__((unused)),
+ const char *user_realm __attribute__((unused)))
+{
+ int ret = SASL_FAIL;
+ int result = SASL_OK;
+ sasl_server_conn_t *sconn = (sasl_server_conn_t *)conn;
+ const char *password_request[] = { SASL_AUX_PASSWORD,
+ "*cmusaslsecretPLAIN",
+ NULL };
+ struct propval auxprop_values[3];
+
+ if (!conn || !userstr)
+ return SASL_BADPARAM;
+
+ /* We need to clear any previous results and re-canonify to
+ * ensure correctness */
+
+ prop_clear (sconn->sparams->propctx, 0);
+
+ /* ensure its requested */
+ result = prop_request(sconn->sparams->propctx, password_request);
+
+ if(result != SASL_OK) return result;
+
+ result = _sasl_canon_user_lookup (conn,
+ userstr,
+ 0,
+ SASL_CU_AUTHID | SASL_CU_AUTHZID,
+ &(conn->oparams));
+ if(result != SASL_OK) return result;
+
+ result = prop_getnames(sconn->sparams->propctx, password_request,
+ auxprop_values);
+ if (result < 0) {
+ return result;
+ }
+
+ /* Verify that the returned <name>s are correct.
+ But we defer checking for NULL values till after we verify
+ that a passwd is specified. */
+ if (!auxprop_values[0].name && !auxprop_values[1].name) {
+ return SASL_NOUSER;
+ }
+
+ /* It is possible for us to get useful information out of just
+ * the lookup, so we won't check that we have a password until now */
+ if(!passwd) {
+ ret = SASL_BADPARAM;
+ goto done;
+ }
+
+ if ((!auxprop_values[0].values || !auxprop_values[0].values[0])
+ && (!auxprop_values[1].values || !auxprop_values[1].values[0])) {
+ return SASL_NOUSER;
+ }
+
+ /* At the point this has been called, the username has been canonified
+ * and we've done the auxprop lookup. This should be easy. */
+ if(auxprop_values[0].name
+ && auxprop_values[0].values
+ && auxprop_values[0].values[0]
+ && !strcmp(auxprop_values[0].values[0], passwd)) {
+ /* We have a plaintext version and it matched! */
+ return SASL_OK;
+ } else if(auxprop_values[1].name
+ && auxprop_values[1].values
+ && auxprop_values[1].values[0]) {
+ const char *db_secret = auxprop_values[1].values[0];
+ sasl_secret_t *construct;
+
+ ret = _sasl_make_plain_secret(db_secret, passwd,
+ strlen(passwd),
+ &construct);
+ if (ret != SASL_OK) {
+ goto done;
+ }
+
+ if (!memcmp(db_secret, construct->data, construct->len)) {
+ /* password verified! */
+ ret = SASL_OK;
+ } else {
+ /* passwords do not match */
+ ret = SASL_BADAUTH;
+ }
+
+ sasl_FREE(construct);
+ } else {
+ /* passwords do not match */
+ ret = SASL_BADAUTH;
+ }
+
+ /* erase the plaintext password */
+ sconn->sparams->utils->prop_erase(sconn->sparams->propctx,
+ password_request[0]);
+
+ done:
+ /* We're not going to erase the property here because other people
+ * may want it */
+ return ret;
+}
+
+#if 0
+/* Verify user password using auxprop plugins. Allow verification against a hashed password,
+ * or non-retrievable password. Don't use cmusaslsecretPLAIN attribute.
+ *
+ * This function is similar to auxprop_verify_password().
+ */
+static int auxprop_verify_password_hashed(sasl_conn_t *conn,
+ const char *userstr,
+ const char *passwd,
+ const char *service __attribute__((unused)),
+ const char *user_realm __attribute__((unused)))
+{
+ int ret = SASL_FAIL;
+ int result = SASL_OK;
+ sasl_server_conn_t *sconn = (sasl_server_conn_t *)conn;
+ const char *password_request[] = { SASL_AUX_PASSWORD,
+ NULL };
+ struct propval auxprop_values[2];
+ unsigned extra_cu_flags = 0;
+
+ if (!conn || !userstr)
+ return SASL_BADPARAM;
+
+ /* We need to clear any previous results and re-canonify to
+ * ensure correctness */
+
+ prop_clear(sconn->sparams->propctx, 0);
+
+ /* ensure its requested */
+ result = prop_request(sconn->sparams->propctx, password_request);
+
+ if (result != SASL_OK) return result;
+
+ /* We need to pass "password" down to the auxprop_lookup */
+ /* NB: We don't support binary passwords */
+ if (passwd != NULL) {
+ prop_set (sconn->sparams->propctx,
+ SASL_AUX_PASSWORD,
+ passwd,
+ -1);
+ extra_cu_flags = SASL_CU_VERIFY_AGAINST_HASH;
+ }
+
+ result = _sasl_canon_user_lookup (conn,
+ userstr,
+ 0,
+ SASL_CU_AUTHID | SASL_CU_AUTHZID | extra_cu_flags,
+ &(conn->oparams));
+
+ if (result != SASL_OK) return result;
+
+ result = prop_getnames(sconn->sparams->propctx, password_request,
+ auxprop_values);
+ if (result < 0) {
+ return result;
+ }
+
+ /* Verify that the returned <name>s are correct.
+ But we defer checking for NULL values till after we verify
+ that a passwd is specified. */
+ if (!auxprop_values[0].name && !auxprop_values[1].name) {
+ return SASL_NOUSER;
+ }
+
+ /* It is possible for us to get useful information out of just
+ * the lookup, so we won't check that we have a password until now */
+ if (!passwd) {
+ ret = SASL_BADPARAM;
+ goto done;
+ }
+
+ if ((!auxprop_values[0].values || !auxprop_values[0].values[0])) {
+ return SASL_NOUSER;
+ }
+
+ /* At the point this has been called, the username has been canonified
+ * and we've done the auxprop lookup. This should be easy. */
+
+ /* NB: Note that if auxprop_lookup failed to verify the password,
+ then the userPassword property value would be NULL */
+ if (auxprop_values[0].name
+ && auxprop_values[0].values
+ && auxprop_values[0].values[0]
+ && !strcmp(auxprop_values[0].values[0], passwd)) {
+ /* We have a plaintext version and it matched! */
+ return SASL_OK;
+ } else {
+ /* passwords do not match */
+ ret = SASL_BADAUTH;
+ }
+
+ done:
+ /* We're not going to erase the property here because other people
+ * may want it */
+ return ret;
+}
+#endif
+
+#ifdef DO_SASL_CHECKAPOP
+int _sasl_auxprop_verify_apop(sasl_conn_t *conn,
+ const char *userstr,
+ const char *challenge,
+ const char *response,
+ const char *user_realm __attribute__((unused)))
+{
+ int ret = SASL_BADAUTH;
+ char *userid = NULL;
+ char *realm = NULL;
+ unsigned char digest[16];
+ char digeststr[33];
+ const char *password_request[] = { SASL_AUX_PASSWORD, NULL };
+ struct propval auxprop_values[2];
+ sasl_server_conn_t *sconn = (sasl_server_conn_t *)conn;
+ MD5_CTX ctx;
+ int i;
+
+ if (!conn || !userstr || !challenge || !response)
+ PARAMERROR(conn)
+
+ /* We've done the auxprop lookup already (in our caller) */
+ /* sadly, APOP has no provision for storing secrets */
+ ret = prop_getnames(sconn->sparams->propctx, password_request,
+ auxprop_values);
+ if(ret < 0) {
+ sasl_seterror(conn, 0, "could not perform password lookup");
+ goto done;
+ }
+
+ if(!auxprop_values[0].name ||
+ !auxprop_values[0].values ||
+ !auxprop_values[0].values[0]) {
+ sasl_seterror(conn, 0, "could not find password");
+ ret = SASL_NOUSER;
+ goto done;
+ }
+
+ _sasl_MD5Init(&ctx);
+ _sasl_MD5Update(&ctx, (const unsigned char *) challenge, strlen(challenge));
+ _sasl_MD5Update(&ctx, (const unsigned char *) auxprop_values[0].values[0],
+ strlen(auxprop_values[0].values[0]));
+ _sasl_MD5Final(digest, &ctx);
+
+ /* erase the plaintext password */
+ sconn->sparams->utils->prop_erase(sconn->sparams->propctx,
+ password_request[0]);
+
+ /* convert digest from binary to ASCII hex */
+ for (i = 0; i < 16; i++)
+ sprintf(digeststr + (i*2), "%02x", digest[i]);
+
+ if (!strncasecmp(digeststr, response, 32)) {
+ /* password verified! */
+ ret = SASL_OK;
+ } else {
+ /* passwords do not match */
+ ret = SASL_BADAUTH;
+ }
+
+ done:
+ if (ret == SASL_BADAUTH) sasl_seterror(conn, SASL_NOLOG,
+ "login incorrect");
+ if (userid) sasl_FREE(userid);
+ if (realm) sasl_FREE(realm);
+
+ return ret;
+}
+#endif /* DO_SASL_CHECKAPOP */
+
+#if defined(HAVE_PWCHECK) || defined(HAVE_SASLAUTHD) || defined(HAVE_AUTHDAEMON)
+/*
+ * Wait for file descriptor to be writable. Return with error if timeout.
+ */
+static int write_wait(int fd, unsigned delta)
+{
+ fd_set wfds;
+ fd_set efds;
+ struct timeval tv;
+
+ /*
+ * Wait for file descriptor fd to be writable. Retry on
+ * interruptions. Return with error upon timeout.
+ */
+ while (1) {
+ FD_ZERO(&wfds);
+ FD_ZERO(&efds);
+ FD_SET(fd, &wfds);
+ FD_SET(fd, &efds);
+ tv.tv_sec = (long) delta;
+ tv.tv_usec = 0;
+ switch(select(fd + 1, 0, &wfds, &efds, &tv)) {
+ case 0:
+ /* Timeout. */
+ errno = ETIMEDOUT;
+ return -1;
+ case +1:
+ if (FD_ISSET(fd, &wfds)) {
+ /* Success, file descriptor is writable. */
+ return 0;
+ }
+ return -1;
+ case -1:
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+ return -1;
+ default:
+ /* Error catch-all. */
+ return -1;
+ }
+ }
+ /* Not reached. */
+ return -1;
+}
+
+/*
+ * Keep calling the writev() system call with 'fd', 'iov', and 'iovcnt'
+ * until all the data is written out or an error/timeout occurs.
+ */
+static int retry_writev(int fd, struct iovec *iov, int iovcnt, unsigned delta)
+{
+ int n;
+ int i;
+ int written = 0;
+ static int iov_max =
+#ifdef MAXIOV
+ MAXIOV
+#else
+#ifdef IOV_MAX
+ IOV_MAX
+#else
+ 8192
+#endif
+#endif
+ ;
+
+ for (;;) {
+ while (iovcnt && iov[0].iov_len == 0) {
+ iov++;
+ iovcnt--;
+ }
+
+ if (!iovcnt) return written;
+
+ if (delta > 0) {
+ if (write_wait(fd, delta))
+ return -1;
+ }
+ n = writev(fd, iov, iovcnt > iov_max ? iov_max : iovcnt);
+ if (n == -1) {
+ if (errno == EINVAL && iov_max > 10) {
+ iov_max /= 2;
+ continue;
+ }
+ if (errno == EINTR) continue;
+ return -1;
+ }
+
+ written += n;
+
+ for (i = 0; i < iovcnt; i++) {
+ if ((int) iov[i].iov_len > n) {
+ iov[i].iov_base = (char *)iov[i].iov_base + n;
+ iov[i].iov_len -= n;
+ break;
+ }
+ n -= iov[i].iov_len;
+ iov[i].iov_len = 0;
+ }
+
+ if (i == iovcnt) return written;
+ }
+}
+
+#endif
+
+#ifdef HAVE_PWCHECK
+/* pwcheck daemon-authenticated login */
+static int pwcheck_verify_password(sasl_conn_t *conn,
+ const char *userid,
+ const char *passwd,
+ const char *service __attribute__((unused)),
+ const char *user_realm
+ __attribute__((unused)))
+{
+ int s;
+ struct sockaddr_un srvaddr;
+ int r;
+ struct iovec iov[10];
+ static char response[1024];
+ unsigned start, n;
+ char pwpath[1024];
+
+ if (strlen(PWCHECKDIR)+8+1 > sizeof(pwpath)) return SASL_FAIL;
+
+ strcpy(pwpath, PWCHECKDIR);
+ strcat(pwpath, "/pwcheck");
+
+ s = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (s == -1) return errno;
+
+ memset((char *)&srvaddr, 0, sizeof(srvaddr));
+ srvaddr.sun_family = AF_UNIX;
+ strncpy(srvaddr.sun_path, pwpath, sizeof(srvaddr.sun_path));
+ r = connect(s, (struct sockaddr *)&srvaddr, sizeof(srvaddr));
+ if (r == -1) {
+ sasl_seterror(conn,0,"cannot connect to pwcheck server");
+ return SASL_FAIL;
+ }
+
+ iov[0].iov_base = (char *)userid;
+ iov[0].iov_len = strlen(userid)+1;
+ iov[1].iov_base = (char *)passwd;
+ iov[1].iov_len = strlen(passwd)+1;
+
+ retry_writev(s, iov, 2, 0);
+
+ start = 0;
+ while (start < sizeof(response) - 1) {
+ n = read(s, response+start, sizeof(response) - 1 - start);
+ if (n < 1) break;
+ start += n;
+ }
+
+ close(s);
+
+ if (start > 1 && !strncmp(response, "OK", 2)) {
+ return SASL_OK;
+ }
+
+ response[start] = '\0';
+ sasl_seterror(conn,0,response);
+ return SASL_BADAUTH;
+}
+
+#endif
+
+#if defined(HAVE_SASLAUTHD) || defined(HAVE_AUTHDAEMON)
+static int read_wait(int fd, unsigned delta)
+{
+ fd_set rfds;
+ fd_set efds;
+ struct timeval tv;
+ /*
+ * Wait for file descriptor fd to be readable. Retry on
+ * interruptions. Return with error upon timeout.
+ */
+ while (1) {
+ FD_ZERO(&rfds);
+ FD_ZERO(&efds);
+ FD_SET(fd, &rfds);
+ FD_SET(fd, &efds);
+ tv.tv_sec = (long) delta;
+ tv.tv_usec = 0;
+ switch(select(fd + 1, &rfds, 0, &efds, &tv)) {
+ case 0:
+ /* Timeout. */
+ errno = ETIMEDOUT;
+ return -1;
+ case +1:
+ case +2:
+ if (FD_ISSET(fd, &rfds)) {
+ /* Success, file descriptor is readable. */
+ return 0;
+ }
+ return -1;
+ case -1:
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+ return -1;
+ default:
+ /* Error catch-all. */
+ return -1;
+ }
+ }
+ /* Not reached. */
+ return -1;
+}
+
+/*
+ * Keep calling the read() system call until all the data is read in,
+ * timeout, EOF, or an error occurs. This function returns the number
+ * of useful bytes, or -1 if timeout/error.
+ */
+static int retry_read(int fd, void *buf0, unsigned nbyte, unsigned delta)
+{
+ int nr;
+ unsigned nleft = nbyte;
+ char *buf = (char*) buf0;
+
+ while (nleft >= 1) {
+ if (delta > 0) {
+ if (read_wait(fd, delta))
+ return -1;
+ }
+ nr = read(fd, buf, nleft);
+ if (nr < 0) {
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+ return -1;
+ } else if (nr == 0) {
+ break;
+ }
+ buf += nr;
+ nleft -= nr;
+ }
+ return nbyte - nleft;
+}
+#endif
+
+#ifdef HAVE_SASLAUTHD
+/* saslauthd-authenticated login */
+static int saslauthd_verify_password(sasl_conn_t *conn,
+ const char *userid,
+ const char *passwd,
+ const char *service,
+ const char *user_realm)
+{
+ char response[1024];
+ char query[8192];
+ char *query_end = query;
+ int s;
+ struct sockaddr_un srvaddr;
+ sasl_getopt_t *getopt;
+ void *context;
+ char pwpath[sizeof(srvaddr.sun_path)];
+ const char *p = NULL;
+ char *freeme = NULL;
+#ifdef USE_DOORS
+ door_arg_t arg;
+#endif
+
+ /* check to see if the user configured a rundir */
+ if (_sasl_getcallback(conn, SASL_CB_GETOPT,
+ (sasl_callback_ft *)&getopt, &context) == SASL_OK) {
+ getopt(context, NULL, "saslauthd_path", &p, NULL);
+ }
+ if (p) {
+ if (strlen(p) >= sizeof(pwpath))
+ return SASL_FAIL;
+
+ strncpy(pwpath, p, sizeof(pwpath) - 1);
+ pwpath[strlen(p)] = '\0';
+ } else {
+ if (strlen(PATH_SASLAUTHD_RUNDIR) + 4 + 1 > sizeof(pwpath))
+ return SASL_FAIL;
+
+ strcpy(pwpath, PATH_SASLAUTHD_RUNDIR "/mux");
+ }
+
+ /* Split out username/realm if necessary */
+ if(strrchr(userid,'@') != NULL) {
+ char *rtmp;
+
+ if(_sasl_strdup(userid, &freeme, NULL) != SASL_OK)
+ goto fail;
+
+ userid = freeme;
+ rtmp = strrchr(userid,'@');
+ *rtmp = '\0';
+ user_realm = rtmp + 1;
+ }
+
+ /*
+ * build request of the form:
+ *
+ * count authid count password count service count realm
+ */
+ {
+ unsigned short max_len, req_len, u_len, p_len, s_len, r_len;
+
+ max_len = (unsigned short) sizeof(query);
+
+ /* prevent buffer overflow */
+ if ((strlen(userid) > USHRT_MAX) ||
+ (strlen(passwd) > USHRT_MAX) ||
+ (strlen(service) > USHRT_MAX) ||
+ (user_realm && (strlen(user_realm) > USHRT_MAX))) {
+ goto toobig;
+ }
+
+ u_len = (strlen(userid));
+ p_len = (strlen(passwd));
+ s_len = (strlen(service));
+ r_len = ((user_realm ? strlen(user_realm) : 0));
+
+ /* prevent buffer overflow */
+ req_len = 30;
+ if (max_len - req_len < u_len) goto toobig;
+ req_len += u_len;
+ if (max_len - req_len < p_len) goto toobig;
+ req_len += p_len;
+ if (max_len - req_len < s_len) goto toobig;
+ req_len += s_len;
+ if (max_len - req_len < r_len) goto toobig;
+
+ u_len = htons(u_len);
+ p_len = htons(p_len);
+ s_len = htons(s_len);
+ r_len = htons(r_len);
+
+ memcpy(query_end, &u_len, sizeof(unsigned short));
+ query_end += sizeof(unsigned short);
+ while (*userid) *query_end++ = *userid++;
+
+ memcpy(query_end, &p_len, sizeof(unsigned short));
+ query_end += sizeof(unsigned short);
+ while (*passwd) *query_end++ = *passwd++;
+
+ memcpy(query_end, &s_len, sizeof(unsigned short));
+ query_end += sizeof(unsigned short);
+ while (*service) *query_end++ = *service++;
+
+ memcpy(query_end, &r_len, sizeof(unsigned short));
+ query_end += sizeof(unsigned short);
+ if (user_realm) while (*user_realm) *query_end++ = *user_realm++;
+ }
+
+#ifdef USE_DOORS
+ s = open(pwpath, O_RDONLY);
+ if (s < 0) {
+ sasl_seterror(conn, 0, "cannot open door to saslauthd server: %m", errno);
+ goto fail;
+ }
+
+ arg.data_ptr = query;
+ arg.data_size = query_end - query;
+ arg.desc_ptr = NULL;
+ arg.desc_num = 0;
+ arg.rbuf = response;
+ arg.rsize = sizeof(response);
+
+ if (door_call(s, &arg) < 0) {
+ /* Parameters are undefined */
+ close(s);
+ sasl_seterror(conn, 0, "door call to saslauthd server failed: %m", errno);
+ goto fail;
+ }
+
+ if (arg.data_ptr != response || arg.data_size >= sizeof(response)) {
+ /* oh damn, we got back a really long response */
+ munmap(arg.rbuf, arg.rsize);
+ close(s);
+ sasl_seterror(conn, 0, "saslauthd sent an overly long response");
+ goto fail;
+ }
+ response[arg.data_size] = '\0';
+
+ close(s);
+#else
+ /* unix sockets */
+
+ s = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (s == -1) {
+ sasl_seterror(conn, 0, "cannot create socket for saslauthd: %m", errno);
+ goto fail;
+ }
+
+ memset((char *)&srvaddr, 0, sizeof(srvaddr));
+ srvaddr.sun_family = AF_UNIX;
+ strncpy(srvaddr.sun_path, pwpath, sizeof(srvaddr.sun_path) - 1);
+ srvaddr.sun_path[strlen(pwpath)] = '\0';
+
+ {
+ int r = connect(s, (struct sockaddr *) &srvaddr, sizeof(srvaddr));
+ if (r == -1) {
+ close(s);
+ sasl_seterror(conn, 0, "cannot connect to saslauthd server: %m", errno);
+ goto fail;
+ }
+ }
+
+ {
+ struct iovec iov[8];
+
+ iov[0].iov_len = query_end - query;
+ iov[0].iov_base = query;
+
+ if (retry_writev(s, iov, 1, 0) == -1) {
+ close(s);
+ sasl_seterror(conn, 0, "write failed");
+ goto fail;
+ }
+ }
+
+ {
+ unsigned short count = 0;
+
+ /*
+ * read response of the form:
+ *
+ * count result
+ */
+ if (retry_read(s, &count, sizeof(count), 0) < (int) sizeof(count)) {
+ sasl_seterror(conn, 0, "size read failed");
+ goto fail;
+ }
+
+ count = ntohs(count);
+ if (count < 2) { /* MUST have at least "OK" or "NO" */
+ close(s);
+ sasl_seterror(conn, 0, "bad response from saslauthd");
+ goto fail;
+ }
+
+ count = (int)sizeof(response) <= count ? sizeof(response) - 1 : count;
+ if (retry_read(s, response, count, 0) < count) {
+ close(s);
+ sasl_seterror(conn, 0, "read failed");
+ goto fail;
+ }
+ response[count] = '\0';
+ }
+
+ close(s);
+#endif /* USE_DOORS */
+
+ if(freeme) free(freeme);
+
+ if (!strncmp(response, "OK", 2)) {
+ return SASL_OK;
+ }
+
+ sasl_seterror(conn, SASL_NOLOG, "authentication failed");
+ return SASL_BADAUTH;
+
+ toobig:
+ /* request just too damn big */
+ sasl_seterror(conn, 0, "saslauthd request too large");
+
+ fail:
+ if (freeme) free(freeme);
+ return SASL_FAIL;
+}
+
+#endif
+
+#ifdef HAVE_AUTHDAEMON
+/*
+ * Preliminary support for Courier's authdaemond.
+ */
+#define AUTHDAEMON_IO_TIMEOUT 30
+
+static int authdaemon_blocking(int fd, int block)
+{
+ int f, r;
+
+ /* Get the fd's blocking bit. */
+ f = fcntl(fd, F_GETFL, 0);
+ if (f == -1)
+ return -1;
+
+ /* Adjust the bitmap accordingly. */
+#ifndef O_NONBLOCK
+#define NB_BITMASK FNDELAY
+#else
+#define NB_BITMASK O_NONBLOCK
+#endif
+ if (block)
+ f &= ~NB_BITMASK;
+ else
+ f |= NB_BITMASK;
+#undef NB_BITMASK
+
+ /* Adjust the fd's blocking bit. */
+ r = fcntl(fd, F_SETFL, f);
+ if (r)
+ return -1;
+
+ /* Success. */
+ return 0;
+}
+
+static int authdaemon_connect(sasl_conn_t *conn, const char *path)
+{
+ int r, s = -1;
+ struct sockaddr_un srvaddr;
+
+ if (strlen(path) >= sizeof(srvaddr.sun_path)) {
+ sasl_seterror(conn, 0, "unix socket path too large", errno);
+ goto fail;
+ }
+
+ s = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (s == -1) {
+ sasl_seterror(conn, 0, "cannot create socket for connection to Courier authdaemond: %m", errno);
+ goto fail;
+ }
+
+ memset((char *)&srvaddr, 0, sizeof(srvaddr));
+ srvaddr.sun_family = AF_UNIX;
+ strncpy(srvaddr.sun_path, path, sizeof(srvaddr.sun_path) - 1);
+
+ /* Use nonblocking unix socket connect(2). */
+ if (authdaemon_blocking(s, 0)) {
+ sasl_seterror(conn, 0, "cannot set nonblocking bit: %m", errno);
+ goto fail;
+ }
+
+ r = connect(s, (struct sockaddr *) &srvaddr, sizeof(srvaddr));
+ if (r == -1) {
+ sasl_seterror(conn, 0, "cannot connect to Courier authdaemond: %m", errno);
+ goto fail;
+ }
+
+ if (authdaemon_blocking(s, 1)) {
+ sasl_seterror(conn, 0, "cannot clear nonblocking bit: %m", errno);
+ goto fail;
+ }
+
+ return s;
+fail:
+ if (s >= 0)
+ close(s);
+ return -1;
+}
+
+static char *authdaemon_build_query(const char *service,
+ const char *authtype,
+ const char *user,
+ const char *passwd)
+{
+ int sz;
+ int l = strlen(service)
+ + 1
+ + strlen(authtype)
+ + 1
+ + strlen(user)
+ + 1
+ + strlen(passwd)
+ + 1;
+ char *buf, n[5];
+ if (snprintf(n, sizeof(n), "%d", l) >= (int)sizeof(n))
+ return NULL;
+ sz = strlen(n) + l + 20;
+ if (!(buf = sasl_ALLOC(sz)))
+ return NULL;
+ snprintf(buf,
+ sz,
+ "AUTH %s\n%s\n%s\n%s\n%s\n\n",
+ n,
+ service,
+ authtype,
+ user,
+ passwd);
+ return buf;
+}
+
+static int authdaemon_read(int fd, void *buf0, unsigned sz)
+{
+ int nr;
+ char *buf = (char*) buf0;
+ if (sz <= 1)
+ return -1;
+ if ((nr = retry_read(fd, buf0, sz - 1, AUTHDAEMON_IO_TIMEOUT)) < 0)
+ return -1;
+ /* We need a null-terminated buffer. */
+ buf[nr] = 0;
+ /* Check for overflow condition. */
+ return nr + 1 < (int)sz ? 0 : -1;
+}
+
+static int authdaemon_write(int fd, void *buf0, unsigned sz)
+{
+ int nw;
+ struct iovec io;
+ io.iov_len = sz;
+ io.iov_base = buf0;
+ nw = retry_writev(fd, &io, 1, AUTHDAEMON_IO_TIMEOUT);
+ return nw == (int)sz ? 0 : -1;
+}
+
+static int authdaemon_talk(sasl_conn_t *conn, int sock, char *authreq)
+{
+ char *str;
+ char buf[8192];
+
+ if (authdaemon_write(sock, authreq, strlen(authreq)))
+ goto _err_out;
+ if (authdaemon_read(sock, buf, sizeof(buf)))
+ goto _err_out;
+ for (str = buf; *str; ) {
+ char *sub;
+
+ for (sub = str; *str; ++str) {
+ if (*str == '\n') {
+ *str++ = 0;
+ break;
+ }
+ }
+ if (strcmp(sub, ".") == 0) {
+ /* success */
+ return SASL_OK;
+ }
+ if (strcmp(sub, "FAIL") == 0) {
+ /* passwords do not match */
+ sasl_seterror(conn, SASL_NOLOG, "authentication failed");
+ return SASL_BADAUTH;
+ }
+ }
+_err_out:
+ /* catchall: authentication error */
+ sasl_seterror(conn, 0, "could not verify password");
+ return SASL_FAIL;
+}
+
+static int authdaemon_verify_password(sasl_conn_t *conn,
+ const char *userid,
+ const char *passwd,
+ const char *service,
+ const char *user_realm __attribute__((unused)))
+{
+ const char *p = NULL;
+ sasl_getopt_t *getopt;
+ void *context;
+ int result = SASL_FAIL;
+ char *query = NULL;
+ int sock = -1;
+
+ /* check to see if the user configured a rundir */
+ if (_sasl_getcallback(conn, SASL_CB_GETOPT,
+ (sasl_callback_ft *)&getopt, &context) == SASL_OK) {
+ getopt(context, NULL, "authdaemond_path", &p, NULL);
+ }
+ if (!p) {
+ /*
+ * XXX should we peek at Courier's build-time config ?
+ */
+ p = PATH_AUTHDAEMON_SOCKET;
+ }
+
+ if ((sock = authdaemon_connect(conn, p)) < 0)
+ goto out;
+ if (!(query = authdaemon_build_query(service, "login", userid, passwd)))
+ goto out;
+ result = authdaemon_talk(conn, sock, query);
+out:
+ if (sock >= 0)
+ close(sock), sock = -1;
+ if (query)
+ sasl_FREE(query), query = 0;
+ return result;
+}
+#endif
+
+#ifdef HAVE_ALWAYSTRUE
+static int always_true(sasl_conn_t *conn,
+ const char *userstr,
+ const char *passwd __attribute__((unused)),
+ const char *service __attribute__((unused)),
+ const char *user_realm __attribute__((unused)))
+{
+ _sasl_log(conn, SASL_LOG_WARN, "AlwaysTrue Password Verifier Verified: %s",
+ userstr);
+ return SASL_OK;
+}
+#endif
+
+struct sasl_verify_password_s _sasl_verify_password[] = {
+ { "auxprop", &auxprop_verify_password },
+#if 0 /* totally undocumented. wtf is this? */
+ { "auxprop-hashed", &auxprop_verify_password_hashed },
+#endif
+#ifdef HAVE_PWCHECK
+ { "pwcheck", &pwcheck_verify_password },
+#endif
+#ifdef HAVE_SASLAUTHD
+ { "saslauthd", &saslauthd_verify_password },
+#endif
+#ifdef HAVE_AUTHDAEMON
+ { "authdaemond", &authdaemon_verify_password },
+#endif
+#ifdef HAVE_ALWAYSTRUE
+ { "alwaystrue", &always_true },
+#endif
+ { NULL, NULL }
+};
diff --git a/contrib/libs/sasl/lib/client.c b/contrib/libs/sasl/lib/client.c
new file mode 100644
index 0000000000..3784bb0e42
--- /dev/null
+++ b/contrib/libs/sasl/lib/client.c
@@ -0,0 +1,1317 @@
+/* SASL client API implementation
+ * Rob Siemborski
+ * Tim Martin
+ */
+/*
+ * Copyright (c) 1998-2016 Carnegie Mellon University. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For permission or any other legal
+ * details, please contact
+ * Carnegie Mellon University
+ * Center for Technology Transfer and Enterprise Creation
+ * 4615 Forbes Avenue
+ * Suite 302
+ * Pittsburgh, PA 15213
+ * (412) 268-7393, fax: (412) 268-7395
+ * innovation@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Computing Services
+ * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <ctype.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+/* SASL Headers */
+#include "sasl.h"
+#include "saslplug.h"
+#include "saslutil.h"
+#include "saslint.h"
+
+static cmech_list_t *cmechlist; /* global var which holds the list */
+static sasl_global_callbacks_t global_callbacks_client;
+static int _sasl_client_active = 0;
+
+static int init_mechlist()
+{
+ cmechlist->utils=_sasl_alloc_utils(NULL, &global_callbacks_client);
+ if (cmechlist->utils==NULL)
+ return SASL_NOMEM;
+
+ cmechlist->mech_list=NULL;
+ cmechlist->mech_length=0;
+
+ return SASL_OK;
+}
+
+int sasl_client_done(void)
+{
+ int result = SASL_CONTINUE;
+
+ if (_sasl_server_cleanup_hook == NULL && _sasl_client_cleanup_hook == NULL) {
+ return SASL_NOTINIT;
+ }
+
+ if (_sasl_client_cleanup_hook) {
+ result = _sasl_client_cleanup_hook();
+
+ if (result == SASL_OK) {
+ _sasl_client_idle_hook = NULL;
+ _sasl_client_cleanup_hook = NULL;
+ } else {
+ return result;
+ }
+ }
+
+ if (_sasl_server_cleanup_hook || _sasl_client_cleanup_hook) {
+ return result;
+ }
+
+ sasl_common_done();
+
+ return SASL_OK;
+}
+
+static int client_done(void) {
+ cmechanism_t *cm;
+ cmechanism_t *cprevm;
+
+ if (!_sasl_client_active) {
+ return SASL_NOTINIT;
+ } else {
+ _sasl_client_active--;
+ }
+
+ if(_sasl_client_active) {
+ /* Don't de-init yet! Our refcount is nonzero. */
+ return SASL_CONTINUE;
+ }
+
+ cm = cmechlist->mech_list; /* m point to beginning of the list */
+ while (cm != NULL) {
+ cprevm = cm;
+ cm = cm->next;
+
+ if (cprevm->m.plug->mech_free) {
+ cprevm->m.plug->mech_free(cprevm->m.plug->glob_context,
+ cmechlist->utils);
+ }
+
+ sasl_FREE(cprevm->m.plugname);
+ sasl_FREE(cprevm);
+ }
+ _sasl_free_utils(&cmechlist->utils);
+ sasl_FREE(cmechlist);
+
+ cmechlist = NULL;
+
+ return SASL_OK;
+}
+
+/* This is nearly identical to the version in server.c.
+ Keep in sync. */
+static int mech_compare(const sasl_client_plug_t *a,
+ const sasl_client_plug_t *b)
+{
+ unsigned sec_diff;
+ unsigned features_diff;
+
+ /* XXX the following is fairly arbitrary, but its independent
+ of the order in which the plugins are loaded
+ */
+#ifdef PREFER_MECH
+ if (!strcasecmp(a->mech_name, PREFER_MECH)) return 1;
+ if (!strcasecmp(b->mech_name, PREFER_MECH)) return -1;
+#endif
+
+ sec_diff = a->security_flags ^ b->security_flags;
+ if (sec_diff & a->security_flags & SASL_SEC_NOANONYMOUS) return 1;
+ if (sec_diff & b->security_flags & SASL_SEC_NOANONYMOUS) return -1;
+ if (sec_diff & a->security_flags & SASL_SEC_NOPLAINTEXT) return 1;
+ if (sec_diff & b->security_flags & SASL_SEC_NOPLAINTEXT) return -1;
+ if (sec_diff & a->security_flags & SASL_SEC_MUTUAL_AUTH) return 1;
+ if (sec_diff & b->security_flags & SASL_SEC_MUTUAL_AUTH) return -1;
+ if (sec_diff & a->security_flags & SASL_SEC_NOACTIVE) return 1;
+ if (sec_diff & b->security_flags & SASL_SEC_NOACTIVE) return -1;
+ if (sec_diff & a->security_flags & SASL_SEC_NODICTIONARY) return 1;
+ if (sec_diff & b->security_flags & SASL_SEC_NODICTIONARY) return -1;
+ if (sec_diff & a->security_flags & SASL_SEC_FORWARD_SECRECY) return 1;
+ if (sec_diff & b->security_flags & SASL_SEC_FORWARD_SECRECY) return -1;
+
+ features_diff = a->features ^ b->features;
+ if (features_diff & a->features & SASL_FEAT_CHANNEL_BINDING) return 1;
+ if (features_diff & b->features & SASL_FEAT_CHANNEL_BINDING) return -1;
+
+ if (a->max_ssf > b->max_ssf) return 1;
+ if (a->max_ssf < b->max_ssf) return -1;
+
+ if (SASL_GET_HASH_STRENGTH(a->security_flags) > SASL_GET_HASH_STRENGTH(b->security_flags)) return 1;
+ if (SASL_GET_HASH_STRENGTH(a->security_flags) < SASL_GET_HASH_STRENGTH(b->security_flags)) return -1;
+
+ return 0;
+}
+
+int sasl_client_add_plugin(const char *plugname,
+ sasl_client_plug_init_t *entry_point)
+{
+ int plugcount;
+ sasl_client_plug_t *pluglist;
+ cmechanism_t *mech, *mp;
+ int result;
+ int version;
+ int lupe;
+
+ if (!plugname || !entry_point) return SASL_BADPARAM;
+
+ result = entry_point(cmechlist->utils,
+ SASL_CLIENT_PLUG_VERSION,
+ &version,
+ &pluglist,
+ &plugcount);
+
+ if (result != SASL_OK)
+ {
+ _sasl_log(NULL, SASL_LOG_WARN,
+ "sasl_client_add_plugin(): entry_point(): failed for plugname %s: %z",
+ plugname, result);
+ return result;
+ }
+
+ if (version != SASL_CLIENT_PLUG_VERSION)
+ {
+ _sasl_log(NULL, SASL_LOG_WARN,
+ "version conflict in sasl_client_add_plugin for %s", plugname);
+ return SASL_BADVERS;
+ }
+
+ for (lupe=0; lupe < plugcount; lupe++, pluglist++)
+ {
+ mech = sasl_ALLOC(sizeof(cmechanism_t));
+ if (!mech) return SASL_NOMEM;
+
+ mech->m.plug = pluglist;
+ if (_sasl_strdup(plugname, &mech->m.plugname, NULL) != SASL_OK) {
+ sasl_FREE(mech);
+ return SASL_NOMEM;
+ }
+ mech->m.version = version;
+
+ /* sort mech_list by relative "strength" */
+ mp = cmechlist->mech_list;
+ if (!mp || mech_compare(pluglist, mp->m.plug) >= 0) {
+ /* add mech to head of list */
+ mech->next = cmechlist->mech_list;
+ cmechlist->mech_list = mech;
+ } else {
+ /* find where to insert mech into list */
+ while (mp->next &&
+ mech_compare(pluglist, mp->next->m.plug) <= 0) mp = mp->next;
+ mech->next = mp->next;
+ mp->next = mech;
+ }
+
+ cmechlist->mech_length++;
+ }
+
+ return SASL_OK;
+}
+
+static int
+client_idle(sasl_conn_t *conn)
+{
+ cmechanism_t *m;
+ if (! cmechlist)
+ return 0;
+
+ for (m = cmechlist->mech_list;
+ m;
+ m = m->next)
+ if (m->m.plug->idle
+ && m->m.plug->idle(m->m.plug->glob_context,
+ conn,
+ conn ? ((sasl_client_conn_t *)conn)->cparams : NULL))
+ return 1;
+ return 0;
+}
+
+/* initialize the SASL client drivers
+ * callbacks -- base callbacks for all client connections
+ * returns:
+ * SASL_OK -- Success
+ * SASL_NOMEM -- Not enough memory
+ * SASL_BADVERS -- Mechanism version mismatch
+ * SASL_BADPARAM -- error in config file
+ * SASL_NOMECH -- No mechanisms available
+ * ...
+ */
+
+int sasl_client_init(const sasl_callback_t *callbacks)
+{
+ int ret;
+ const add_plugin_list_t ep_list[] = {
+ { "sasl_client_plug_init", (add_plugin_t *)sasl_client_add_plugin },
+ { "sasl_canonuser_init", (add_plugin_t *)sasl_canonuser_add_plugin },
+ { NULL, NULL }
+ };
+
+ /* lock allocation type */
+ _sasl_allocation_locked++;
+
+ if(_sasl_client_active) {
+ /* We're already active, just increase our refcount */
+ /* xxx do something with the callback structure? */
+ _sasl_client_active++;
+ return SASL_OK;
+ }
+
+ global_callbacks_client.callbacks = callbacks;
+ global_callbacks_client.appname = NULL;
+
+ cmechlist=sasl_ALLOC(sizeof(cmech_list_t));
+ if (cmechlist==NULL) return SASL_NOMEM;
+
+ /* We need to call client_done if we fail now */
+ _sasl_client_active = 1;
+
+ /* load plugins */
+ ret=init_mechlist();
+ if (ret!=SASL_OK) {
+ client_done();
+ return ret;
+ }
+
+ sasl_client_add_plugin("EXTERNAL", &external_client_plug_init);
+
+ ret = _sasl_common_init(&global_callbacks_client);
+
+ if (ret == SASL_OK)
+ ret = _sasl_load_plugins(ep_list,
+ _sasl_find_getpath_callback(callbacks),
+ _sasl_find_verifyfile_callback(callbacks));
+
+ if (ret == SASL_OK) {
+ _sasl_client_cleanup_hook = &client_done;
+ _sasl_client_idle_hook = &client_idle;
+
+ ret = _sasl_build_mechlist();
+ } else {
+ client_done();
+ }
+
+ return ret;
+}
+
+static void client_dispose(sasl_conn_t *pconn)
+{
+ sasl_client_conn_t *c_conn=(sasl_client_conn_t *) pconn;
+
+ if (c_conn->mech && c_conn->mech->m.plug->mech_dispose) {
+ c_conn->mech->m.plug->mech_dispose(pconn->context,
+ c_conn->cparams->utils);
+ }
+
+ pconn->context = NULL;
+
+ if (c_conn->clientFQDN)
+ sasl_FREE(c_conn->clientFQDN);
+
+ if (c_conn->cparams) {
+ _sasl_free_utils(&(c_conn->cparams->utils));
+ sasl_FREE(c_conn->cparams);
+ }
+
+ if (c_conn->mech_list != cmechlist->mech_list) {
+ /* free connection-specific mech_list */
+ cmechanism_t *m, *prevm;
+
+ m = c_conn->mech_list; /* m point to beginning of the list */
+
+ while (m) {
+ prevm = m;
+ m = m->next;
+ sasl_FREE(prevm);
+ }
+ }
+
+ _sasl_conn_dispose(pconn);
+}
+
+/* initialize a client exchange based on the specified mechanism
+ * service -- registered name of the service using SASL (e.g. "imap")
+ * serverFQDN -- the fully qualified domain name of the server
+ * iplocalport -- client IPv4/IPv6 domain literal string with port
+ * (if NULL, then mechanisms requiring IPaddr are disabled)
+ * ipremoteport -- server IPv4/IPv6 domain literal string with port
+ * (if NULL, then mechanisms requiring IPaddr are disabled)
+ * prompt_supp -- list of client interactions supported
+ * may also include sasl_getopt_t context & call
+ * NULL prompt_supp = user/pass via SASL_INTERACT only
+ * NULL proc = interaction supported via SASL_INTERACT
+ * secflags -- security flags (see above)
+ * in/out:
+ * pconn -- connection negotiation structure
+ * pointer to NULL => allocate new
+ * non-NULL => recycle storage and go for next available mech
+ *
+ * Returns:
+ * SASL_OK -- success
+ * SASL_NOMECH -- no mechanism meets requested properties
+ * SASL_NOMEM -- not enough memory
+ */
+int sasl_client_new(const char *service,
+ const char *serverFQDN,
+ const char *iplocalport,
+ const char *ipremoteport,
+ const sasl_callback_t *prompt_supp,
+ unsigned flags,
+ sasl_conn_t **pconn)
+{
+ int result;
+ char name[MAXFQDNLEN];
+ sasl_client_conn_t *conn;
+ sasl_utils_t *utils;
+ sasl_getopt_t *getopt;
+ void *context;
+ const char *mlist = NULL;
+ int plus = 0;
+
+ if (_sasl_client_active == 0) return SASL_NOTINIT;
+
+ /* Remember, serverFQDN, iplocalport and ipremoteport can be NULL and be valid! */
+ if (!pconn || !service)
+ return SASL_BADPARAM;
+
+ *pconn=sasl_ALLOC(sizeof(sasl_client_conn_t));
+ if (*pconn==NULL) {
+ _sasl_log(NULL, SASL_LOG_ERR,
+ "Out of memory allocating connection context");
+ return SASL_NOMEM;
+ }
+ memset(*pconn, 0, sizeof(sasl_client_conn_t));
+
+ (*pconn)->destroy_conn = &client_dispose;
+
+ conn = (sasl_client_conn_t *)*pconn;
+
+ conn->mech = NULL;
+
+ conn->cparams=sasl_ALLOC(sizeof(sasl_client_params_t));
+ if (conn->cparams==NULL)
+ MEMERROR(*pconn);
+ memset(conn->cparams,0,sizeof(sasl_client_params_t));
+
+ result = _sasl_conn_init(*pconn, service, flags, SASL_CONN_CLIENT,
+ &client_idle, serverFQDN,
+ iplocalport, ipremoteport,
+ prompt_supp, &global_callbacks_client);
+ if (result != SASL_OK) RETURN(*pconn, result);
+
+ utils = _sasl_alloc_utils(*pconn, &global_callbacks_client);
+ if (utils == NULL) {
+ MEMERROR(*pconn);
+ }
+
+ utils->conn= *pconn;
+ conn->cparams->utils = utils;
+
+ if(_sasl_getcallback(*pconn, SASL_CB_GETOPT, (sasl_callback_ft *)&getopt, &context) == SASL_OK) {
+ getopt(context, NULL, "client_mech_list", &mlist, NULL);
+ }
+
+ /* if we have a client_mech_list, create ordered list of
+ available mechanisms for this conn */
+ if (mlist) {
+ const char *cp;
+ cmechanism_t *mptr, *tail = NULL;
+ cmechanism_t *new;
+
+ while (*mlist) {
+ /* find end of current mech name */
+ for (cp = mlist; *cp && !isspace((int) *cp); cp++);
+
+ /* search for mech name in loaded plugins */
+ for (mptr = cmechlist->mech_list; mptr; mptr = mptr->next) {
+ const sasl_client_plug_t *plug = mptr->m.plug;
+
+ if (_sasl_is_equal_mech(mlist, plug->mech_name, (size_t) (cp - mlist), &plus)) {
+ /* found a match */
+ break;
+ }
+ }
+ if (mptr) {
+ new = sasl_ALLOC(sizeof(cmechanism_t));
+ if (!new) {
+ result = SASL_NOMEM;
+ goto failed_client_new;
+ }
+ memcpy(&new->m, &mptr->m, sizeof(client_sasl_mechanism_t));
+ new->next = NULL;
+
+ if (!conn->mech_list) {
+ conn->mech_list = new;
+ tail = conn->mech_list;
+ } else {
+ if (tail)
+ tail->next = new;
+ tail = new;
+ }
+ conn->mech_length++;
+ }
+
+ /* find next mech name */
+ mlist = cp;
+ while (*mlist && isspace((int) *mlist)) mlist++;
+ }
+ } else {
+ conn->mech_list = cmechlist->mech_list;
+ conn->mech_length = cmechlist->mech_length;
+ }
+
+ if (conn->mech_list == NULL) {
+ sasl_seterror(*pconn, 0, "No worthy mechs found");
+ result = SASL_NOMECH;
+ goto failed_client_new;
+ }
+
+ /* Setup the non-lazy parts of cparams, the rest is done in
+ * sasl_client_start */
+ conn->cparams->canon_user = &_sasl_canon_user_lookup;
+ conn->cparams->flags = flags;
+ conn->cparams->prompt_supp = (*pconn)->callbacks;
+
+ /* get the clientFQDN (serverFQDN was set in _sasl_conn_init) */
+ memset(name, 0, sizeof(name));
+ if (get_fqhostname (name, MAXFQDNLEN, 0) != 0) {
+ return (SASL_FAIL);
+ }
+
+ result = _sasl_strdup(name, &conn->clientFQDN, NULL);
+
+ if (result == SASL_OK) return SASL_OK;
+
+failed_client_new:
+ /* result isn't SASL_OK */
+ _sasl_conn_dispose(*pconn);
+ sasl_FREE(*pconn);
+ *pconn = NULL;
+ _sasl_log(NULL, SASL_LOG_ERR, "Out of memory in sasl_client_new");
+ return result;
+}
+
+static int have_prompts(sasl_conn_t *conn,
+ const sasl_client_plug_t *mech)
+{
+ static const unsigned long default_prompts[] = {
+ SASL_CB_AUTHNAME,
+ SASL_CB_PASS,
+ SASL_CB_LIST_END
+ };
+
+ const unsigned long *prompt;
+ sasl_callback_ft pproc;
+ void *pcontext;
+ int result;
+
+ for (prompt = (mech->required_prompts
+ ? mech->required_prompts :
+ default_prompts);
+ *prompt != SASL_CB_LIST_END;
+ prompt++) {
+ result = _sasl_getcallback(conn, *prompt, &pproc, &pcontext);
+ if (result != SASL_OK && result != SASL_INTERACT)
+ return 0; /* we don't have this required prompt */
+ }
+
+ return 1; /* we have all the prompts */
+}
+
+static int
+_mech_plus_p(const char *mech, size_t len)
+{
+ return (len > 5 && strncasecmp(&mech[len - 5], "-PLUS", 5) == 0);
+}
+
+/*
+ * Order PLUS mechanisms first. Returns NUL separated list of
+ * *count items.
+ */
+static int
+_sasl_client_order_mechs(const sasl_utils_t *utils,
+ const char *mechs,
+ int has_cb_data,
+ char **ordered_mechs,
+ size_t *count,
+ int *server_can_cb)
+{
+ char *list, *listp;
+ size_t i, mechslen, start;
+
+ *count = 0;
+ *server_can_cb = 0;
+
+ if (mechs == NULL || mechs[0] == '\0')
+ return SASL_NOMECH;
+
+ mechslen = strlen(mechs);
+
+ listp = list = utils->malloc(mechslen + 1);
+ if (list == NULL)
+ return SASL_NOMEM;
+
+ /* As per RFC 4422:
+ * SASL mechanism allowable characters are "AZ-_"
+ * separators can be any other characters and of any length
+ * even variable lengths between.
+ *
+ * But for convenience we accept lowercase ASCII.
+ *
+ * Apps should be encouraged to simply use space or comma space
+ * though
+ */
+#define ismechchar(c) (isalnum((c)) || (c) == '_' || (c) == '-')
+ do {
+ for (i = start = 0; i <= mechslen; i++) {
+ if (!ismechchar(mechs[i])) {
+ const char *mechp = &mechs[start];
+ size_t len = i - start;
+
+ if (len != 0 &&
+ _mech_plus_p(mechp, len) == has_cb_data) {
+ memcpy(listp, mechp, len);
+ listp[len] = '\0';
+ listp += len + 1;
+ (*count)++;
+ if (*server_can_cb == 0 && has_cb_data)
+ *server_can_cb = 1;
+ }
+ start = i+1;
+ }
+ }
+ if (has_cb_data)
+ has_cb_data = 0;
+ else
+ break;
+ } while (1);
+
+ if (*count == 0) {
+ utils->free(list);
+ return SASL_NOMECH;
+ }
+
+ *ordered_mechs = list;
+
+ return SASL_OK;
+}
+
+static INLINE int
+_sasl_cbinding_disp(sasl_client_params_t *cparams,
+ int mech_nego,
+ int server_can_cb,
+ sasl_cbinding_disp_t *cbindingdisp)
+{
+ /*
+ * If negotiating mechanisms, then we fail immediately if the
+ * client requires channel binding and the server does not
+ * advertise support. Otherwise we send "y" (which later will
+ * become "p" if we select a supporting mechanism).
+ *
+ * If the client explicitly selected a mechanism, then we only
+ * send channel bindings if they're marked critical.
+ */
+
+ *cbindingdisp = SASL_CB_DISP_NONE;
+
+ if (SASL_CB_PRESENT(cparams)) {
+ if (mech_nego) {
+ if (!server_can_cb && SASL_CB_CRITICAL(cparams)) {
+ return SASL_NOMECH;
+ } else {
+ *cbindingdisp = SASL_CB_DISP_WANT;
+ }
+ } else if (SASL_CB_CRITICAL(cparams)) {
+ *cbindingdisp = SASL_CB_DISP_USED;
+ }
+ }
+
+ return SASL_OK;
+}
+
+/* select a mechanism for a connection
+ * mechlist -- mechanisms server has available (punctuation ignored)
+ * secret -- optional secret from previous session
+ * output:
+ * prompt_need -- on SASL_INTERACT, list of prompts needed to continue
+ * clientout -- the initial client response to send to the server
+ * mech -- set to mechanism name
+ *
+ * Returns:
+ * SASL_OK -- success
+ * SASL_NOMEM -- not enough memory
+ * SASL_NOMECH -- no mechanism meets requested properties
+ * SASL_INTERACT -- user interaction needed to fill in prompt_need list
+ */
+
+/*
+ * SASL mechanism allowable characters are "AZ-_"
+ * separators can be any other characters and of any length
+ * even variable lengths between.
+ *
+ * But for convenience we accept lowercase ASCII.
+ *
+ * Apps should be encouraged to simply use space or comma space
+ * though
+ */
+int sasl_client_start(sasl_conn_t *conn,
+ const char *mechlist,
+ sasl_interact_t **prompt_need,
+ const char **clientout,
+ unsigned *clientoutlen,
+ const char **mech)
+{
+ sasl_client_conn_t *c_conn = (sasl_client_conn_t *) conn;
+ char *ordered_mechs = NULL, *name;
+ cmechanism_t *m = NULL, *bestm = NULL;
+ size_t i, list_len, name_len;
+ sasl_ssf_t minssf = 0;
+ int result, server_can_cb = 0;
+ sasl_cbinding_disp_t cbindingdisp;
+ sasl_cbinding_disp_t cur_cbindingdisp;
+ sasl_cbinding_disp_t best_cbindingdisp = SASL_CB_DISP_NONE;
+
+ if (_sasl_client_active == 0) return SASL_NOTINIT;
+
+ if (!conn) return SASL_BADPARAM;
+
+ /* verify parameters */
+ if (mechlist == NULL) {
+ PARAMERROR(conn);
+ }
+
+ /* if prompt_need != NULL we've already been here
+ and just need to do the continue step again */
+
+ /* do a step */
+ /* FIXME: Hopefully they only give us our own prompt_need back */
+ if (prompt_need && *prompt_need != NULL) {
+ goto dostep;
+ }
+
+ if (conn->props.min_ssf < conn->external.ssf) {
+ minssf = 0;
+ } else {
+ minssf = conn->props.min_ssf - conn->external.ssf;
+ }
+
+ /* Order mechanisms so -PLUS are preferred */
+ result = _sasl_client_order_mechs(c_conn->cparams->utils,
+ mechlist,
+ SASL_CB_PRESENT(c_conn->cparams),
+ &ordered_mechs,
+ &list_len,
+ &server_can_cb);
+ if (result != 0)
+ goto done;
+
+ /*
+ * Determine channel binding disposition based on whether we
+ * are doing mechanism negotiation and whether server supports
+ * channel bindings.
+ */
+ result = _sasl_cbinding_disp(c_conn->cparams,
+ (list_len > 1),
+ server_can_cb,
+ &cbindingdisp);
+ if (result != 0)
+ goto done;
+
+ /* for each mechanism in client's list */
+ for (m = c_conn->mech_list; !bestm && m != NULL; m = m->next) {
+
+ for (i = 0, name = ordered_mechs; i < list_len; i++, name += name_len + 1) {
+ unsigned myflags;
+ int plus;
+
+ name_len = strlen(name);
+
+ if (!_sasl_is_equal_mech(name, m->m.plug->mech_name, name_len, &plus)) {
+ continue;
+ }
+
+ /* Do we have the prompts for it? */
+ if (!have_prompts(conn, m->m.plug))
+ break;
+
+ /* Is it strong enough? */
+ if (minssf > m->m.plug->max_ssf)
+ break;
+
+ myflags = conn->props.security_flags;
+
+ /* if there's an external layer with a better SSF then this is no
+ * longer considered a plaintext mechanism
+ */
+ if ((conn->props.min_ssf <= conn->external.ssf) &&
+ (conn->external.ssf > 1)) {
+ myflags &= ~SASL_SEC_NOPLAINTEXT;
+ }
+
+ /* Does it meet our security properties? */
+ if (((myflags ^ m->m.plug->security_flags) & myflags) != 0) {
+ break;
+ }
+
+ /* Can we meet it's features? */
+ if (cbindingdisp == SASL_CB_DISP_USED &&
+ !(m->m.plug->features & SASL_FEAT_CHANNEL_BINDING)) {
+ break;
+ }
+
+ if ((m->m.plug->features & SASL_FEAT_NEEDSERVERFQDN)
+ && !conn->serverFQDN) {
+ break;
+ }
+
+ /* Can it meet our features? */
+ if ((conn->flags & SASL_NEED_PROXY) &&
+ !(m->m.plug->features & SASL_FEAT_ALLOWS_PROXY)) {
+ break;
+ }
+
+ if ((conn->flags & SASL_NEED_HTTP) &&
+ !(m->m.plug->features & SASL_FEAT_SUPPORTS_HTTP)) {
+ break;
+ }
+
+ if (SASL_CB_PRESENT(c_conn->cparams) && plus) {
+ cur_cbindingdisp = SASL_CB_DISP_USED;
+ } else {
+ cur_cbindingdisp = cbindingdisp;
+ }
+
+ if (mech) {
+ *mech = m->m.plug->mech_name;
+ }
+
+ /* Since the list of client mechs is ordered by preference/strength,
+ the first mech in our list that is available on the server and
+ meets our security properties and features is the "best" */
+ best_cbindingdisp = cur_cbindingdisp;
+ bestm = m;
+ break;
+ }
+ }
+
+ if (bestm == NULL) {
+ sasl_seterror(conn, 0, "No worthy mechs found");
+ result = SASL_NOMECH;
+ goto done;
+ }
+
+ /* make (the rest of) cparams */
+ c_conn->cparams->service = conn->service;
+ c_conn->cparams->servicelen = (unsigned) strlen(conn->service);
+
+ if (conn->serverFQDN) {
+ c_conn->cparams->serverFQDN = conn->serverFQDN;
+ c_conn->cparams->slen = (unsigned) strlen(conn->serverFQDN);
+ }
+
+ c_conn->cparams->clientFQDN = c_conn->clientFQDN;
+ c_conn->cparams->clen = (unsigned) strlen(c_conn->clientFQDN);
+
+ c_conn->cparams->external_ssf = conn->external.ssf;
+ c_conn->cparams->props = conn->props;
+ c_conn->cparams->cbindingdisp = best_cbindingdisp;
+ c_conn->mech = bestm;
+
+ /* init that plugin */
+ result = c_conn->mech->m.plug->mech_new(c_conn->mech->m.plug->glob_context,
+ c_conn->cparams,
+ &(conn->context));
+ if (result != SASL_OK) goto done;
+
+ /* do a step -- but only if we can do a client-send-first */
+ dostep:
+ if(clientout) {
+ if(c_conn->mech->m.plug->features & SASL_FEAT_SERVER_FIRST) {
+ *clientout = NULL;
+ *clientoutlen = 0;
+ result = SASL_CONTINUE;
+ } else {
+ result = sasl_client_step(conn, NULL, 0, prompt_need,
+ clientout, clientoutlen);
+ }
+ }
+ else
+ result = SASL_CONTINUE;
+
+ done:
+ if (ordered_mechs != NULL)
+ c_conn->cparams->utils->free(ordered_mechs);
+ RETURN(conn, result);
+}
+
+/* do a single authentication step.
+ * serverin -- the server message received by the client, MUST have a NUL
+ * sentinel, not counted by serverinlen
+ * output:
+ * prompt_need -- on SASL_INTERACT, list of prompts needed to continue
+ * clientout -- the client response to send to the server
+ *
+ * returns:
+ * SASL_OK -- success
+ * SASL_INTERACT -- user interaction needed to fill in prompt_need list
+ * SASL_BADPROT -- server protocol incorrect/cancelled
+ * SASL_BADSERV -- server failed mutual auth
+ */
+
+int sasl_client_step(sasl_conn_t *conn,
+ const char *serverin,
+ unsigned serverinlen,
+ sasl_interact_t **prompt_need,
+ const char **clientout,
+ unsigned *clientoutlen)
+{
+ sasl_client_conn_t *c_conn= (sasl_client_conn_t *) conn;
+ int result;
+
+ if (_sasl_client_active == 0) return SASL_NOTINIT;
+ if (!conn) return SASL_BADPARAM;
+
+ /* check parameters */
+ if ((serverin==NULL) && (serverinlen>0))
+ PARAMERROR(conn);
+
+ /* Don't do another step if the plugin told us that we're done */
+ if (conn->oparams.doneflag) {
+ _sasl_log(conn, SASL_LOG_ERR, "attempting client step after doneflag");
+ return SASL_FAIL;
+ }
+
+ if(clientout) *clientout = NULL;
+ if(clientoutlen) *clientoutlen = 0;
+
+ /* do a step */
+ result = c_conn->mech->m.plug->mech_step(conn->context,
+ c_conn->cparams,
+ serverin,
+ serverinlen,
+ prompt_need,
+ clientout, clientoutlen,
+ &conn->oparams);
+
+ if (result == SASL_OK) {
+ /* So we're done on this end, but if both
+ * 1. the mech does server-send-last
+ * 2. the protocol does not
+ * we need to return no data */
+ if(!*clientout && !(conn->flags & SASL_SUCCESS_DATA)) {
+ *clientout = "";
+ *clientoutlen = 0;
+ }
+
+ if(!conn->oparams.maxoutbuf) {
+ conn->oparams.maxoutbuf = conn->props.maxbufsize;
+ }
+
+ if(conn->oparams.user == NULL || conn->oparams.authid == NULL) {
+ sasl_seterror(conn, 0,
+ "mech did not call canon_user for both authzid and authid");
+ result = SASL_BADPROT;
+ }
+ }
+
+ RETURN(conn,result);
+}
+
+/* returns the length of all the mechanisms
+ * added up
+ */
+
+static unsigned mech_names_len(cmechanism_t *mech_list)
+{
+ cmechanism_t *listptr;
+ unsigned result = 0;
+
+ for (listptr = mech_list;
+ listptr;
+ listptr = listptr->next)
+ result += (unsigned) strlen(listptr->m.plug->mech_name);
+
+ return result;
+}
+
+
+int _sasl_client_listmech(sasl_conn_t *conn,
+ const char *prefix,
+ const char *sep,
+ const char *suffix,
+ const char **result,
+ unsigned *plen,
+ int *pcount)
+{
+ sasl_client_conn_t *c_conn = (sasl_client_conn_t *)conn;
+ cmechanism_t *m = NULL;
+ sasl_ssf_t minssf = 0;
+ int ret;
+ size_t resultlen;
+ int flag;
+ const char *mysep;
+
+ if (_sasl_client_active == 0) return SASL_NOTINIT;
+ if (!conn) return SASL_BADPARAM;
+ if (conn->type != SASL_CONN_CLIENT) PARAMERROR(conn);
+
+ if (! result)
+ PARAMERROR(conn);
+
+ if (plen != NULL)
+ *plen = 0;
+ if (pcount != NULL)
+ *pcount = 0;
+
+ if (sep) {
+ mysep = sep;
+ } else {
+ mysep = " ";
+ }
+
+ if (conn->props.min_ssf < conn->external.ssf) {
+ minssf = 0;
+ } else {
+ minssf = conn->props.min_ssf - conn->external.ssf;
+ }
+
+ if (!c_conn->mech_list || c_conn->mech_length <= 0) {
+ INTERROR(conn, SASL_NOMECH);
+ }
+
+ resultlen = (prefix ? strlen(prefix) : 0)
+ + (strlen(mysep) * (c_conn->mech_length - 1))
+ + mech_names_len(c_conn->mech_list)
+ + (suffix ? strlen(suffix) : 0)
+ + 1;
+ ret = _buf_alloc(&conn->mechlist_buf,
+ &conn->mechlist_buf_len,
+ resultlen);
+ if (ret != SASL_OK) MEMERROR(conn);
+
+ if (prefix) {
+ strcpy (conn->mechlist_buf,prefix);
+ } else {
+ *(conn->mechlist_buf) = '\0';
+ }
+
+ flag = 0;
+ for (m = c_conn->mech_list; m != NULL; m = m->next) {
+ /* do we have the prompts for it? */
+ if (!have_prompts(conn, m->m.plug)) {
+ continue;
+ }
+
+ /* is it strong enough? */
+ if (minssf > m->m.plug->max_ssf) {
+ continue;
+ }
+
+ /* does it meet our security properties? */
+ if (((conn->props.security_flags ^ m->m.plug->security_flags)
+ & conn->props.security_flags) != 0) {
+ continue;
+ }
+
+ /* Can we meet it's features? */
+ if ((m->m.plug->features & SASL_FEAT_NEEDSERVERFQDN)
+ && !conn->serverFQDN) {
+ continue;
+ }
+
+ /* Can it meet our features? */
+ if ((conn->flags & SASL_NEED_PROXY) &&
+ !(m->m.plug->features & SASL_FEAT_ALLOWS_PROXY)) {
+ continue;
+ }
+
+ /* Okay, we like it, add it to the list! */
+
+ if (pcount != NULL)
+ (*pcount)++;
+
+ /* print seperator */
+ if (flag) {
+ strcat(conn->mechlist_buf, mysep);
+ } else {
+ flag = 1;
+ }
+
+ /* now print the mechanism name */
+ strcat(conn->mechlist_buf, m->m.plug->mech_name);
+ }
+
+ if (suffix)
+ strcat(conn->mechlist_buf,suffix);
+
+ if (plen!=NULL)
+ *plen = (unsigned) strlen(conn->mechlist_buf);
+
+ *result = conn->mechlist_buf;
+
+ return SASL_OK;
+}
+
+sasl_string_list_t *_sasl_client_mechs(void)
+{
+ cmechanism_t *listptr;
+ sasl_string_list_t *retval = NULL, *next=NULL;
+
+ if(!_sasl_client_active) return NULL;
+
+ /* make list */
+ for (listptr = cmechlist->mech_list; listptr; listptr = listptr->next) {
+ next = sasl_ALLOC(sizeof(sasl_string_list_t));
+
+ if(!next && !retval) return NULL;
+ else if(!next) {
+ next = retval->next;
+ do {
+ sasl_FREE(retval);
+ retval = next;
+ next = retval->next;
+ } while(next);
+ return NULL;
+ }
+
+ next->d = listptr->m.plug->mech_name;
+
+ if(!retval) {
+ next->next = NULL;
+ retval = next;
+ } else {
+ next->next = retval;
+ retval = next;
+ }
+ }
+
+ return retval;
+}
+
+
+
+
+/* It would be nice if we can show other information like Author, Company, Year, plugin version */
+static void
+_sasl_print_mechanism (
+ client_sasl_mechanism_t *m,
+ sasl_info_callback_stage_t stage,
+ void *rock __attribute__((unused))
+)
+{
+ char delimiter;
+
+ if (stage == SASL_INFO_LIST_START) {
+ printf ("List of client plugins follows\n");
+ return;
+ } else if (stage == SASL_INFO_LIST_END) {
+ return;
+ }
+
+ /* Process the mechanism */
+ printf ("Plugin \"%s\" ", m->plugname);
+
+ /* There is no delay loading for client side plugins */
+ printf ("[loaded]");
+
+ printf (", \tAPI version: %d\n", m->version);
+
+ if (m->plug != NULL) {
+ printf ("\tSASL mechanism: %s, best SSF: %d\n",
+ m->plug->mech_name,
+ m->plug->max_ssf);
+
+ printf ("\tsecurity flags:");
+
+ delimiter = ' ';
+ if (m->plug->security_flags & SASL_SEC_NOANONYMOUS) {
+ printf ("%cNO_ANONYMOUS", delimiter);
+ delimiter = '|';
+ }
+
+ if (m->plug->security_flags & SASL_SEC_NOPLAINTEXT) {
+ printf ("%cNO_PLAINTEXT", delimiter);
+ delimiter = '|';
+ }
+
+ if (m->plug->security_flags & SASL_SEC_NOACTIVE) {
+ printf ("%cNO_ACTIVE", delimiter);
+ delimiter = '|';
+ }
+
+ if (m->plug->security_flags & SASL_SEC_NODICTIONARY) {
+ printf ("%cNO_DICTIONARY", delimiter);
+ delimiter = '|';
+ }
+
+ if (m->plug->security_flags & SASL_SEC_FORWARD_SECRECY) {
+ printf ("%cFORWARD_SECRECY", delimiter);
+ delimiter = '|';
+ }
+
+ if (m->plug->security_flags & SASL_SEC_PASS_CREDENTIALS) {
+ printf ("%cPASS_CREDENTIALS", delimiter);
+ delimiter = '|';
+ }
+
+ if (m->plug->security_flags & SASL_SEC_MUTUAL_AUTH) {
+ printf ("%cMUTUAL_AUTH", delimiter);
+ delimiter = '|';
+ }
+
+
+
+ printf ("\n\tfeatures:");
+
+ delimiter = ' ';
+ if (m->plug->features & SASL_FEAT_WANT_CLIENT_FIRST) {
+ printf ("%cWANT_CLIENT_FIRST", delimiter);
+ delimiter = '|';
+ }
+
+ if (m->plug->features & SASL_FEAT_SERVER_FIRST) {
+ printf ("%cSERVER_FIRST", delimiter);
+ delimiter = '|';
+ }
+
+ if (m->plug->features & SASL_FEAT_ALLOWS_PROXY) {
+ printf ("%cPROXY_AUTHENTICATION", delimiter);
+ delimiter = '|';
+ }
+
+ if (m->plug->features & SASL_FEAT_NEEDSERVERFQDN) {
+ printf ("%cNEED_SERVER_FQDN", delimiter);
+ delimiter = '|';
+ }
+
+ if (m->plug->features & SASL_FEAT_GSS_FRAMING) {
+ printf ("%cGSS_FRAMING", delimiter);
+ delimiter = '|';
+ }
+
+ if (m->plug->features & SASL_FEAT_CHANNEL_BINDING) {
+ printf ("%cCHANNEL_BINDING", delimiter);
+ delimiter = '|';
+ }
+
+ if (m->plug->features & SASL_FEAT_SUPPORTS_HTTP) {
+ printf ("%cSUPPORTS_HTTP", delimiter);
+ delimiter = '|';
+ }
+ }
+
+/* Delay loading is not supported for the client side plugins:
+ if (m->f) {
+ printf ("\n\twill be loaded from \"%s\"", m->f);
+ }
+ */
+
+ printf ("\n");
+}
+
+
+/* Dump information about available client plugins */
+int sasl_client_plugin_info (
+ const char *c_mech_list, /* space separated mechanism list or NULL for ALL */
+ sasl_client_info_callback_t *info_cb,
+ void *info_cb_rock
+)
+{
+ cmechanism_t *m;
+ client_sasl_mechanism_t plug_data;
+ char * cur_mech;
+ char * mech_list = NULL;
+ char * p;
+
+ if (info_cb == NULL) {
+ info_cb = _sasl_print_mechanism;
+ }
+
+ if (cmechlist != NULL) {
+ info_cb (NULL, SASL_INFO_LIST_START, info_cb_rock);
+
+ if (c_mech_list == NULL) {
+ m = cmechlist->mech_list; /* m point to beginning of the list */
+
+ while (m != NULL) {
+ memcpy (&plug_data, &m->m, sizeof(plug_data));
+
+ info_cb (&plug_data, SASL_INFO_LIST_MECH, info_cb_rock);
+
+ m = m->next;
+ }
+ } else {
+ mech_list = strdup (c_mech_list);
+
+ cur_mech = mech_list;
+
+ while (cur_mech != NULL) {
+ p = strchr (cur_mech, ' ');
+ if (p != NULL) {
+ *p = '\0';
+ p++;
+ }
+
+ m = cmechlist->mech_list; /* m point to beginning of the list */
+
+ while (m != NULL) {
+ if (strcasecmp (cur_mech, m->m.plug->mech_name) == 0) {
+ memcpy (&plug_data, &m->m, sizeof(plug_data));
+
+ info_cb (&plug_data, SASL_INFO_LIST_MECH, info_cb_rock);
+ }
+
+ m = m->next;
+ }
+
+ cur_mech = p;
+ }
+
+ free (mech_list);
+ }
+
+ info_cb (NULL, SASL_INFO_LIST_END, info_cb_rock);
+
+ return (SASL_OK);
+ }
+
+ return (SASL_NOTINIT);
+}
diff --git a/contrib/libs/sasl/lib/common.c b/contrib/libs/sasl/lib/common.c
new file mode 100644
index 0000000000..d9104c8956
--- /dev/null
+++ b/contrib/libs/sasl/lib/common.c
@@ -0,0 +1,2674 @@
+/* common.c - Functions that are common to server and clinet
+ * Rob Siemborski
+ * Tim Martin
+ */
+/*
+ * Copyright (c) 1998-2016 Carnegie Mellon University. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For permission or any other legal
+ * details, please contact
+ * Carnegie Mellon University
+ * Center for Technology Transfer and Enterprise Creation
+ * 4615 Forbes Avenue
+ * Suite 302
+ * Pittsburgh, PA 15213
+ * (412) 268-7393, fax: (412) 268-7395
+ * innovation@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Computing Services
+ * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+#ifdef HAVE_SYSLOG
+#include <syslog.h>
+#endif
+#include <stdarg.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include <sasl.h>
+#include <saslutil.h>
+#include <saslplug.h>
+#include "saslint.h"
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+static const char *implementation_string = "Cyrus SASL";
+
+#define VSTR0(maj, min, step) #maj "." #min "." #step
+#define VSTR(maj, min, step) VSTR0(maj, min, step)
+#define SASL_VERSION_STRING VSTR(SASL_VERSION_MAJOR, SASL_VERSION_MINOR, \
+ SASL_VERSION_STEP)
+
+static int _sasl_getpath(void *context __attribute__((unused)), const char **path);
+static int _sasl_getpath_simple(void *context __attribute__((unused)), const char **path);
+static int _sasl_getconfpath(void *context __attribute__((unused)), char ** path);
+static int _sasl_getconfpath_simple(void *context __attribute__((unused)), const char **path);
+
+#if !defined(WIN32)
+static char * _sasl_get_default_unix_path(void *context __attribute__((unused)),
+ char * env_var_name, char * default_value);
+#else
+/* NB: Always returned allocated value */
+static char * _sasl_get_default_win_path(void *context __attribute__((unused)),
+ TCHAR * reg_attr_name, char * default_value);
+#endif
+
+
+/* It turns out to be convenient to have a shared sasl_utils_t */
+const sasl_utils_t *sasl_global_utils = NULL;
+
+/* Should be a null-terminated array that lists the available mechanisms */
+static char **global_mech_list = NULL;
+
+void *free_mutex = NULL;
+
+int (*_sasl_client_cleanup_hook)(void) = NULL;
+int (*_sasl_server_cleanup_hook)(void) = NULL;
+int (*_sasl_client_idle_hook)(sasl_conn_t *conn) = NULL;
+int (*_sasl_server_idle_hook)(sasl_conn_t *conn) = NULL;
+
+sasl_allocation_utils_t _sasl_allocation_utils={
+ (sasl_malloc_t *) &malloc,
+ (sasl_calloc_t *) &calloc,
+ (sasl_realloc_t *) &realloc,
+ (sasl_free_t *) &free
+};
+int _sasl_allocation_locked = 0;
+
+#define SASL_ENCODEV_EXTRA 4096
+
+/* Default getpath/getconfpath callbacks. These can be edited by sasl_set_path(). */
+static sasl_callback_t default_getpath_cb = {
+ SASL_CB_GETPATH, (sasl_callback_ft)&_sasl_getpath, NULL
+};
+static sasl_callback_t default_getconfpath_cb = {
+ SASL_CB_GETCONFPATH, (sasl_callback_ft)&_sasl_getconfpath, NULL
+};
+
+static char * default_plugin_path = NULL;
+static char * default_conf_path = NULL;
+
+static int _sasl_global_getopt(void *context,
+ const char *plugin_name,
+ const char *option,
+ const char ** result,
+ unsigned *len);
+
+/* Intenal mutex functions do as little as possible (no thread protection) */
+static void *sasl_mutex_alloc(void)
+{
+ return (void *)0x1;
+}
+
+static int sasl_mutex_lock(void *mutex __attribute__((unused)))
+{
+ return SASL_OK;
+}
+
+static int sasl_mutex_unlock(void *mutex __attribute__((unused)))
+{
+ return SASL_OK;
+}
+
+static void sasl_mutex_free(void *mutex __attribute__((unused)))
+{
+ return;
+}
+
+sasl_mutex_utils_t _sasl_mutex_utils={
+ &sasl_mutex_alloc,
+ &sasl_mutex_lock,
+ &sasl_mutex_unlock,
+ &sasl_mutex_free
+};
+
+void sasl_set_mutex(sasl_mutex_alloc_t *n,
+ sasl_mutex_lock_t *l,
+ sasl_mutex_unlock_t *u,
+ sasl_mutex_free_t *d)
+{
+ /* Disallow mutex function changes once sasl_client_init
+ and/or sasl_server_init is called */
+ if (_sasl_server_cleanup_hook || _sasl_client_cleanup_hook) {
+ return;
+ }
+
+ _sasl_mutex_utils.alloc=n;
+ _sasl_mutex_utils.lock=l;
+ _sasl_mutex_utils.unlock=u;
+ _sasl_mutex_utils.free=d;
+}
+
+/* copy a string to malloced memory */
+int _sasl_strdup(const char *in, char **out, size_t *outlen)
+{
+ size_t len = strlen(in);
+ if (outlen) *outlen = len;
+ *out=sasl_ALLOC((unsigned) len + 1);
+ if (! *out) return SASL_NOMEM;
+ strcpy((char *) *out, in);
+ return SASL_OK;
+}
+
+/* adds a string to the buffer; reallocing if need be */
+int _sasl_add_string(char **out, size_t *alloclen,
+ size_t *outlen, const char *add)
+{
+ size_t addlen;
+
+ if (add==NULL) add = "(null)";
+
+ addlen=strlen(add); /* only compute once */
+ if (_buf_alloc(out, alloclen, (*outlen)+addlen+1)!=SASL_OK)
+ return SASL_NOMEM;
+
+ strcpy(*out + *outlen, add);
+ *outlen += addlen;
+
+ return SASL_OK;
+}
+
+/* a simpler way to set plugin path or configuration file path
+ * without the need to set sasl_getpath_t callback.
+ *
+ * This function can be called before sasl_server_init/sasl_client_init.
+ *
+ * Don't call this function without locking in a multithreaded application.
+ */
+int sasl_set_path (int path_type, char * path)
+{
+ int result;
+
+ if (path == NULL) {
+ return (SASL_FAIL);
+ }
+
+ switch (path_type) {
+ case SASL_PATH_TYPE_PLUGIN:
+ if (default_plugin_path != NULL) {
+ sasl_FREE (default_plugin_path);
+ default_plugin_path = NULL;
+ }
+ result = _sasl_strdup (path, &default_plugin_path, NULL);
+ if (result != SASL_OK) {
+ return (result);
+ }
+
+ /* Update the default getpath_t callback */
+ default_getpath_cb.proc = (sasl_callback_ft)&_sasl_getpath_simple;
+ break;
+
+ case SASL_PATH_TYPE_CONFIG:
+ if (default_conf_path != NULL) {
+ sasl_FREE (default_conf_path);
+ default_conf_path = NULL;
+ }
+ result = _sasl_strdup (path, &default_conf_path, NULL);
+ if (result != SASL_OK) {
+ return (result);
+ }
+
+ /* Update the default getpath_t callback */
+ default_getconfpath_cb.proc = (sasl_callback_ft)&_sasl_getconfpath_simple;
+ break;
+
+ default:
+ return (SASL_FAIL);
+ }
+
+ return (SASL_OK);
+}
+
+/* return the version of the cyrus sasl library as compiled,
+ * using 32 bits: high byte is major version, second byte is minor version,
+ * low 16 bits are step #.
+ * Patch version is not available using this function,
+ * use sasl_version_info() instead.
+ */
+void sasl_version(const char **implementation, int *version)
+{
+ if(implementation) *implementation = implementation_string;
+ /* NB: the format is not the same as in SASL_VERSION_FULL */
+ if(version) *version = (SASL_VERSION_MAJOR << 24) |
+ (SASL_VERSION_MINOR << 16) |
+ (SASL_VERSION_STEP);
+}
+
+/* Extended version of sasl_version above */
+void sasl_version_info (const char **implementation, const char **version_string,
+ int *version_major, int *version_minor, int *version_step,
+ int *version_patch)
+{
+ if (implementation) *implementation = implementation_string;
+ if (version_string) *version_string = SASL_VERSION_STRING;
+ if (version_major) *version_major = SASL_VERSION_MAJOR;
+ if (version_minor) *version_minor = SASL_VERSION_MINOR;
+ if (version_step) *version_step = SASL_VERSION_STEP;
+ /* Version patch is always 0 for CMU SASL */
+ if (version_patch) *version_patch = 0;
+}
+
+/* security-encode a regular string. Mostly a wrapper for sasl_encodev */
+/* output is only valid until next call to sasl_encode or sasl_encodev */
+int sasl_encode(sasl_conn_t *conn, const char *input,
+ unsigned inputlen,
+ const char **output, unsigned *outputlen)
+{
+ int result;
+ struct iovec tmp;
+
+ if(!conn) return SASL_BADPARAM;
+ if(!input || !inputlen || !output || !outputlen)
+ PARAMERROR(conn);
+
+ /* maxoutbuf checking is done in sasl_encodev */
+
+ /* Note: We are casting a const pointer here, but it's okay
+ * because we believe people downstream of us are well-behaved, and the
+ * alternative is an absolute mess, performance-wise. */
+ tmp.iov_base = (void *)input;
+ tmp.iov_len = inputlen;
+
+ result = sasl_encodev(conn, &tmp, 1, output, outputlen);
+
+ RETURN(conn, result);
+}
+
+/* Internal function that doesn't do any verification */
+static int
+_sasl_encodev (sasl_conn_t *conn,
+ const struct iovec *invec,
+ unsigned numiov,
+ int * p_num_packets, /* number of packets generated so far */
+ const char **output, /* previous output, if *p_num_packets > 0 */
+ unsigned *outputlen)
+{
+ int result;
+ char * new_buf;
+
+ assert (conn->oparams.encode != NULL);
+
+ if (*p_num_packets == 1) {
+ /* This is the second call to this function,
+ so we need to allocate a new output buffer
+ and copy existing data there. */
+ conn->multipacket_encoded_data.curlen = *outputlen;
+ if (conn->multipacket_encoded_data.data == NULL) {
+ conn->multipacket_encoded_data.reallen =
+ conn->multipacket_encoded_data.curlen + SASL_ENCODEV_EXTRA;
+ conn->multipacket_encoded_data.data =
+ sasl_ALLOC(conn->multipacket_encoded_data.reallen + 1);
+
+ if (conn->multipacket_encoded_data.data == NULL) {
+ MEMERROR(conn);
+ }
+ } else {
+ /* A buffer left from a previous sasl_encodev call.
+ Make sure it is big enough. */
+ if (conn->multipacket_encoded_data.curlen >
+ conn->multipacket_encoded_data.reallen) {
+ conn->multipacket_encoded_data.reallen =
+ conn->multipacket_encoded_data.curlen + SASL_ENCODEV_EXTRA;
+
+ new_buf = sasl_REALLOC(conn->multipacket_encoded_data.data,
+ conn->multipacket_encoded_data.reallen + 1);
+ if (new_buf == NULL) {
+ MEMERROR(conn);
+ }
+ conn->multipacket_encoded_data.data = new_buf;
+ }
+ }
+
+ memcpy (conn->multipacket_encoded_data.data,
+ *output,
+ *outputlen);
+ }
+
+ result = conn->oparams.encode(conn->context,
+ invec,
+ numiov,
+ output,
+ outputlen);
+
+ if (*p_num_packets > 0 && result == SASL_OK) {
+ /* Is the allocated buffer big enough? If not, grow it. */
+ if ((conn->multipacket_encoded_data.curlen + *outputlen) >
+ conn->multipacket_encoded_data.reallen) {
+ conn->multipacket_encoded_data.reallen =
+ conn->multipacket_encoded_data.curlen + *outputlen;
+ new_buf = sasl_REALLOC(conn->multipacket_encoded_data.data,
+ conn->multipacket_encoded_data.reallen + 1);
+ if (new_buf == NULL) {
+ MEMERROR(conn);
+ }
+ conn->multipacket_encoded_data.data = new_buf;
+ }
+
+ /* Append new data to the end of the buffer */
+ memcpy (conn->multipacket_encoded_data.data +
+ conn->multipacket_encoded_data.curlen,
+ *output,
+ *outputlen);
+ conn->multipacket_encoded_data.curlen += *outputlen;
+
+ *output = conn->multipacket_encoded_data.data;
+ *outputlen = (unsigned)conn->multipacket_encoded_data.curlen;
+ }
+
+ (*p_num_packets)++;
+
+ RETURN(conn, result);
+}
+
+/* security-encode an iovec */
+/* output is only valid until the next call to sasl_encode or sasl_encodev */
+int sasl_encodev(sasl_conn_t *conn,
+ const struct iovec *invec,
+ unsigned numiov,
+ const char **output,
+ unsigned *outputlen)
+{
+ int result = SASL_OK;
+ unsigned i;
+ unsigned j;
+ size_t total_size = 0;
+ struct iovec *cur_invec = NULL;
+ struct iovec last_invec;
+ unsigned cur_numiov;
+ char * next_buf = NULL;
+ size_t remainder_len;
+ unsigned index_offset;
+ unsigned allocated = 0;
+ /* Number of generated SASL packets */
+ int num_packets = 0;
+
+ if (!conn) return SASL_BADPARAM;
+ if (! invec || ! output || ! outputlen || numiov < 1) {
+ PARAMERROR(conn);
+ }
+
+ if (!conn->props.maxbufsize) {
+ sasl_seterror(conn, 0,
+ "called sasl_encode[v] with application that does not support security layers");
+ return SASL_TOOWEAK;
+ }
+
+ /* If oparams.encode is NULL, this means there is no SASL security
+ layer in effect, so no SASL framing is needed. */
+ if (conn->oparams.encode == NULL) {
+ result = _iovec_to_buf(invec, numiov, &conn->encode_buf);
+ if (result != SASL_OK) INTERROR(conn, result);
+
+ *output = conn->encode_buf->data;
+ *outputlen = (unsigned) conn->encode_buf->curlen;
+
+ RETURN(conn, result);
+ }
+
+ /* This might be better to check on a per-plugin basis, but I think
+ * it's cleaner and more effective here. It also encourages plugins
+ * to be honest about what they accept */
+
+ last_invec.iov_base = NULL;
+ remainder_len = 0;
+ next_buf = NULL;
+ i = 0;
+ while (i < numiov) {
+ if ((total_size + invec[i].iov_len) > conn->oparams.maxoutbuf) {
+
+ /* CLAIM: total_size < conn->oparams.maxoutbuf */
+
+ /* Fit as many bytes in last_invec, so that we have conn->oparams.maxoutbuf
+ bytes in total. */
+ last_invec.iov_len = conn->oparams.maxoutbuf - total_size;
+ /* Point to the first byte of the current record. */
+ last_invec.iov_base = invec[i].iov_base;
+
+ /* Note that total_size < conn->oparams.maxoutbuf */
+ /* The total size of the iov is bigger then the other end can accept.
+ So we allocate a new iov that contains just enough. */
+
+ /* +1 --- for the tail record */
+ cur_numiov = i + 1;
+
+ /* +1 --- just in case we need the head record */
+ if ((cur_numiov + 1) > allocated) {
+ struct iovec *new_invec;
+
+ allocated = cur_numiov + 1;
+ new_invec = sasl_REALLOC (cur_invec, sizeof(struct iovec) * allocated);
+ if (new_invec == NULL) {
+ if (cur_invec != NULL) {
+ sasl_FREE(cur_invec);
+ }
+ MEMERROR(conn);
+ }
+ cur_invec = new_invec;
+ }
+
+ if (next_buf != NULL) {
+ cur_invec[0].iov_base = next_buf;
+ cur_invec[0].iov_len = (long)remainder_len;
+ cur_numiov++;
+ index_offset = 1;
+ } else {
+ index_offset = 0;
+ }
+
+ if (i > 0) {
+ /* Copy all previous chunks */
+ /* NOTE - The starting index in invec is always 0 */
+ for (j = 0; j < i; j++) {
+ cur_invec[j + index_offset] = invec[j];
+ }
+ }
+
+ /* Initialize the last record */
+ cur_invec[i + index_offset] = last_invec;
+
+ result = _sasl_encodev (conn,
+ cur_invec,
+ cur_numiov,
+ &num_packets,
+ output,
+ outputlen);
+
+ if (result != SASL_OK) {
+ goto cleanup;
+ }
+
+ /* Point to the first byte that wouldn't fit into
+ the conn->oparams.maxoutbuf buffer. */
+ /* Note, if next_buf points to the very end of the IOV record,
+ it will be reset to NULL below */
+ /* Note, that some platforms define iov_base as "void *",
+ thus the typecase below */
+ next_buf = (char *) last_invec.iov_base + last_invec.iov_len;
+ /* Note - remainder_len is how many bytes left to be encoded in
+ the current IOV slot. */
+ remainder_len = (total_size + invec[i].iov_len) - conn->oparams.maxoutbuf;
+
+ /* Skip all consumed IOV records */
+ invec += i + 1;
+ numiov = numiov - (i + 1);
+ i = 0;
+
+ while (remainder_len > conn->oparams.maxoutbuf) {
+ last_invec.iov_base = next_buf;
+ last_invec.iov_len = conn->oparams.maxoutbuf;
+
+ /* Note, if next_buf points to the very end of the IOV record,
+ it will be reset to NULL below */
+ /* Note, that some platforms define iov_base as "void *",
+ thus the typecase below */
+ next_buf = (char *) last_invec.iov_base + last_invec.iov_len;
+ remainder_len = remainder_len - conn->oparams.maxoutbuf;
+
+ result = _sasl_encodev (conn,
+ &last_invec,
+ 1,
+ &num_packets,
+ output,
+ outputlen);
+ if (result != SASL_OK) {
+ goto cleanup;
+ }
+ }
+
+ total_size = remainder_len;
+
+ if (remainder_len == 0) {
+ /* Just clear next_buf */
+ next_buf = NULL;
+ }
+ } else {
+ total_size += invec[i].iov_len;
+ i++;
+ }
+ }
+
+ /* CLAIM - The remaining data is shorter then conn->oparams.maxoutbuf. */
+
+ /* Force encoding of any partial buffer. Might not be optimal on the wire. */
+ if (next_buf != NULL) {
+ last_invec.iov_base = next_buf;
+ last_invec.iov_len = (long)remainder_len;
+
+ result = _sasl_encodev (conn,
+ &last_invec,
+ 1,
+ &num_packets,
+ output,
+ outputlen);
+
+ if (result != SASL_OK) {
+ goto cleanup;
+ }
+ }
+
+ if (numiov > 0) {
+ result = _sasl_encodev (conn,
+ invec,
+ numiov,
+ &num_packets,
+ output,
+ outputlen);
+ }
+
+cleanup:
+ if (cur_invec != NULL) {
+ sasl_FREE(cur_invec);
+ }
+
+ RETURN(conn, result);
+}
+
+/* output is only valid until next call to sasl_decode */
+int sasl_decode(sasl_conn_t *conn,
+ const char *input, unsigned inputlen,
+ const char **output, unsigned *outputlen)
+{
+ int result;
+
+ if(!conn) return SASL_BADPARAM;
+ if(!input || !output || !outputlen)
+ PARAMERROR(conn);
+
+ if(!conn->props.maxbufsize) {
+ sasl_seterror(conn, 0,
+ "called sasl_decode with application that does not support security layers");
+ RETURN(conn, SASL_TOOWEAK);
+ }
+
+ if(conn->oparams.decode == NULL)
+ {
+ /* Since we know how long the output is maximally, we can
+ * just allocate it to begin with, and never need another
+ * allocation! */
+
+ /* However, if they pass us more than they actually can take,
+ * we cannot help them... */
+ if(inputlen > conn->props.maxbufsize) {
+ sasl_seterror(conn, 0,
+ "input too large for default sasl_decode");
+ RETURN(conn,SASL_BUFOVER);
+ }
+
+ if(!conn->decode_buf)
+ conn->decode_buf = sasl_ALLOC(conn->props.maxbufsize + 1);
+ if(!conn->decode_buf)
+ MEMERROR(conn);
+
+ memcpy(conn->decode_buf, input, inputlen);
+ conn->decode_buf[inputlen] = '\0';
+ *output = conn->decode_buf;
+ *outputlen = inputlen;
+
+ return SASL_OK;
+ } else {
+ result = conn->oparams.decode(conn->context, input, inputlen,
+ output, outputlen);
+
+ /* NULL an empty buffer (for misbehaved applications) */
+ if (*outputlen == 0) *output = NULL;
+
+ RETURN(conn, result);
+ }
+
+ INTERROR(conn, SASL_FAIL);
+}
+
+
+void
+sasl_set_alloc(sasl_malloc_t *m,
+ sasl_calloc_t *c,
+ sasl_realloc_t *r,
+ sasl_free_t *f)
+{
+ if (_sasl_allocation_locked++) return;
+
+ _sasl_allocation_utils.malloc=m;
+ _sasl_allocation_utils.calloc=c;
+ _sasl_allocation_utils.realloc=r;
+ _sasl_allocation_utils.free=f;
+}
+
+void sasl_common_done(void)
+{
+ /* NOTE - the caller will need to reinitialize the values,
+ if it is going to call sasl_client_init/sasl_server_init again. */
+ if (default_plugin_path != NULL) {
+ sasl_FREE (default_plugin_path);
+ default_plugin_path = NULL;
+ }
+ if (default_conf_path != NULL) {
+ sasl_FREE (default_conf_path);
+ default_conf_path = NULL;
+ }
+
+ _sasl_canonuser_free();
+ _sasl_done_with_plugins();
+
+ sasl_MUTEX_FREE(free_mutex);
+ free_mutex = NULL;
+
+ _sasl_free_utils(&sasl_global_utils);
+
+ if (global_mech_list) {
+ sasl_FREE(global_mech_list);
+ global_mech_list = NULL;
+ }
+}
+
+/* This function is for backward compatibility */
+void sasl_done(void)
+{
+ if (_sasl_server_cleanup_hook && _sasl_server_cleanup_hook() == SASL_OK) {
+ _sasl_server_idle_hook = NULL;
+ _sasl_server_cleanup_hook = NULL;
+ }
+
+ if (_sasl_client_cleanup_hook && _sasl_client_cleanup_hook() == SASL_OK) {
+ _sasl_client_idle_hook = NULL;
+ _sasl_client_cleanup_hook = NULL;
+ }
+
+ if (_sasl_server_cleanup_hook || _sasl_client_cleanup_hook) {
+ return;
+ }
+
+ sasl_common_done();
+}
+
+/* fills in the base sasl_conn_t info */
+int _sasl_conn_init(sasl_conn_t *conn,
+ const char *service,
+ unsigned int flags,
+ enum Sasl_conn_type type,
+ int (*idle_hook)(sasl_conn_t *conn),
+ const char *serverFQDN,
+ const char *iplocalport,
+ const char *ipremoteport,
+ const sasl_callback_t *callbacks,
+ const sasl_global_callbacks_t *global_callbacks) {
+ int result = SASL_OK;
+
+ conn->type = type;
+
+ result = _sasl_strdup(service, &conn->service, NULL);
+ if (result != SASL_OK)
+ MEMERROR(conn);
+
+ memset(&conn->oparams, 0, sizeof(sasl_out_params_t));
+ memset(&conn->external, 0, sizeof(_sasl_external_properties_t));
+
+ conn->flags = flags;
+
+ result = sasl_setprop(conn, SASL_IPLOCALPORT, iplocalport);
+ if(result != SASL_OK)
+ RETURN(conn, result);
+
+ result = sasl_setprop(conn, SASL_IPREMOTEPORT, ipremoteport);
+ if(result != SASL_OK)
+ RETURN(conn, result);
+
+ conn->encode_buf = NULL;
+ conn->context = NULL;
+ conn->secret = NULL;
+ conn->idle_hook = idle_hook;
+ conn->callbacks = callbacks;
+ conn->global_callbacks = global_callbacks;
+
+ memset(&conn->props, 0, sizeof(conn->props));
+
+ /* Start this buffer out as an empty string */
+ conn->error_code = SASL_OK;
+ conn->errdetail_buf = conn->error_buf = NULL;
+ conn->errdetail_buf_len = conn->error_buf_len = 150;
+
+ result = _buf_alloc(&conn->error_buf, &conn->error_buf_len, 150);
+ if(result != SASL_OK) MEMERROR(conn);
+ result = _buf_alloc(&conn->errdetail_buf, &conn->errdetail_buf_len, 150);
+ if(result != SASL_OK) MEMERROR(conn);
+
+ conn->error_buf[0] = '\0';
+ conn->errdetail_buf[0] = '\0';
+
+ conn->decode_buf = NULL;
+
+ if(serverFQDN) {
+ result = _sasl_strdup(serverFQDN, &conn->serverFQDN, NULL);
+ sasl_strlower (conn->serverFQDN);
+ } else if (conn->type == SASL_CONN_SERVER) {
+ /* We can fake it because we *are* the server */
+ char name[MAXFQDNLEN];
+ memset(name, 0, sizeof(name));
+ if (get_fqhostname (name, MAXFQDNLEN, 0) != 0) {
+ return (SASL_FAIL);
+ }
+
+ result = _sasl_strdup(name, &conn->serverFQDN, NULL);
+ } else {
+ conn->serverFQDN = NULL;
+ }
+
+
+ if(result != SASL_OK) MEMERROR( conn );
+
+ RETURN(conn, SASL_OK);
+}
+
+int _sasl_common_init(sasl_global_callbacks_t *global_callbacks)
+{
+ int result;
+
+ /* The last specified global callback always wins */
+ if (sasl_global_utils != NULL) {
+ sasl_utils_t * global_utils = (sasl_utils_t *)sasl_global_utils;
+ global_utils->getopt = &_sasl_global_getopt;
+ global_utils->getopt_context = global_callbacks;
+ }
+
+ /* Do nothing if we are already initialized */
+ if (free_mutex) {
+ return SASL_OK;
+ }
+
+ /* Setup the global utilities */
+ if(!sasl_global_utils) {
+ sasl_global_utils = _sasl_alloc_utils(NULL, global_callbacks);
+ if(sasl_global_utils == NULL) return SASL_NOMEM;
+ }
+
+ /* Init the canon_user plugin */
+ result = sasl_canonuser_add_plugin("INTERNAL", internal_canonuser_init);
+ if(result != SASL_OK) return result;
+
+ if (!free_mutex) {
+ free_mutex = sasl_MUTEX_ALLOC();
+ }
+ if (!free_mutex) return SASL_FAIL;
+
+ return SASL_OK;
+}
+
+/* dispose connection state, sets it to NULL
+ * checks for pointer to NULL
+ */
+void sasl_dispose(sasl_conn_t **pconn)
+{
+ int result;
+
+ if (! pconn) return;
+ if (! *pconn) return;
+
+ /* serialize disposes. this is necessary because we can't
+ dispose of conn->mutex if someone else is locked on it */
+ if (!free_mutex) {
+ free_mutex = sasl_MUTEX_ALLOC();
+ if (!free_mutex) return;
+ }
+
+ result = sasl_MUTEX_LOCK(free_mutex);
+ if (result!=SASL_OK) return;
+
+ /* *pconn might have become NULL by now */
+ if (*pconn) {
+ (*pconn)->destroy_conn(*pconn);
+ sasl_FREE(*pconn);
+ *pconn=NULL;
+ }
+
+ sasl_MUTEX_UNLOCK(free_mutex);
+}
+
+void _sasl_conn_dispose(sasl_conn_t *conn) {
+ if (conn->serverFQDN)
+ sasl_FREE(conn->serverFQDN);
+
+ if (conn->external.auth_id)
+ sasl_FREE(conn->external.auth_id);
+
+ if(conn->encode_buf) {
+ if(conn->encode_buf->data) sasl_FREE(conn->encode_buf->data);
+ sasl_FREE(conn->encode_buf);
+ }
+
+ if(conn->error_buf)
+ sasl_FREE(conn->error_buf);
+
+ if(conn->errdetail_buf)
+ sasl_FREE(conn->errdetail_buf);
+
+ if(conn->decode_buf)
+ sasl_FREE(conn->decode_buf);
+
+ if(conn->mechlist_buf)
+ sasl_FREE(conn->mechlist_buf);
+
+ if(conn->service)
+ sasl_FREE(conn->service);
+
+ if (conn->multipacket_encoded_data.data) {
+ sasl_FREE(conn->multipacket_encoded_data.data);
+ }
+
+ /* oparams sub-members should be freed by the plugin, in so much
+ * as they were allocated by the plugin */
+}
+
+
+/* get property from SASL connection state
+ * propnum -- property number
+ * pvalue -- pointer to value
+ * returns:
+ * SASL_OK -- no error
+ * SASL_NOTDONE -- property not available yet
+ * SASL_BADPARAM -- bad property number or SASL context is NULL
+ */
+int sasl_getprop(sasl_conn_t *conn, int propnum, const void **pvalue)
+{
+ int result = SASL_OK;
+ sasl_getopt_t *getopt;
+ void *context;
+
+ if (! conn) return SASL_BADPARAM;
+ if (! pvalue) PARAMERROR(conn);
+
+ switch(propnum)
+ {
+ case SASL_SSF:
+ *(sasl_ssf_t **)pvalue= &conn->oparams.mech_ssf;
+ break;
+ case SASL_MAXOUTBUF:
+ *(unsigned **)pvalue = &conn->oparams.maxoutbuf;
+ break;
+ case SASL_GETOPTCTX:
+ result = _sasl_getcallback(conn, SASL_CB_GETOPT, (sasl_callback_ft *)&getopt, &context);
+ if(result != SASL_OK) break;
+
+ *(void **)pvalue = context;
+ break;
+ case SASL_CALLBACK:
+ *(const sasl_callback_t **)pvalue = conn->callbacks;
+ break;
+ case SASL_IPLOCALPORT:
+ if(conn->got_ip_local)
+ *(const char **)pvalue = conn->iplocalport;
+ else {
+ *(const char **)pvalue = NULL;
+ result = SASL_NOTDONE;
+ }
+ break;
+ case SASL_IPREMOTEPORT:
+ if(conn->got_ip_remote)
+ *(const char **)pvalue = conn->ipremoteport;
+ else {
+ *(const char **)pvalue = NULL;
+ result = SASL_NOTDONE;
+ }
+ break;
+ case SASL_USERNAME:
+ if(! conn->oparams.user)
+ result = SASL_NOTDONE;
+ else
+ *((const char **)pvalue) = conn->oparams.user;
+ break;
+ case SASL_AUTHUSER:
+ if(! conn->oparams.authid)
+ result = SASL_NOTDONE;
+ else
+ *((const char **)pvalue) = conn->oparams.authid;
+ break;
+ case SASL_APPNAME:
+ /* Currently we only support server side contexts, but we should
+ be able to extend this to support client side contexts as well */
+ if(conn->type != SASL_CONN_SERVER) result = SASL_BADPROT;
+ else
+ *((const char **)pvalue) = ((sasl_server_conn_t *)conn)->sparams->appname;
+ break;
+ case SASL_SERVERFQDN:
+ *((const char **)pvalue) = conn->serverFQDN;
+ break;
+ case SASL_DEFUSERREALM:
+ if(conn->type != SASL_CONN_SERVER) result = SASL_BADPROT;
+ else
+ *((const char **)pvalue) = ((sasl_server_conn_t *)conn)->user_realm;
+ break;
+ case SASL_SERVICE:
+ *((const char **)pvalue) = conn->service;
+ break;
+ case SASL_AUTHSOURCE: /* name of plugin (not name of mech) */
+ if(conn->type == SASL_CONN_CLIENT) {
+ if(!((sasl_client_conn_t *)conn)->mech) {
+ result = SASL_NOTDONE;
+ break;
+ }
+ *((const char **)pvalue) =
+ ((sasl_client_conn_t *)conn)->mech->m.plugname;
+ } else if (conn->type == SASL_CONN_SERVER) {
+ if(!((sasl_server_conn_t *)conn)->mech) {
+ result = SASL_NOTDONE;
+ break;
+ }
+ *((const char **)pvalue) =
+ ((sasl_server_conn_t *)conn)->mech->m.plugname;
+ } else {
+ result = SASL_BADPARAM;
+ }
+ break;
+ case SASL_MECHNAME: /* name of mech */
+ if(conn->type == SASL_CONN_CLIENT) {
+ if(!((sasl_client_conn_t *)conn)->mech) {
+ result = SASL_NOTDONE;
+ break;
+ }
+ *((const char **)pvalue) =
+ ((sasl_client_conn_t *)conn)->mech->m.plug->mech_name;
+ } else if (conn->type == SASL_CONN_SERVER) {
+ if(!((sasl_server_conn_t *)conn)->mech) {
+ result = SASL_NOTDONE;
+ break;
+ }
+ *((const char **)pvalue) =
+ ((sasl_server_conn_t *)conn)->mech->m.plug->mech_name;
+ } else {
+ result = SASL_BADPARAM;
+ }
+
+ if(!(*pvalue) && result == SASL_OK) result = SASL_NOTDONE;
+ break;
+ case SASL_PLUGERR:
+ *((const char **)pvalue) = conn->error_buf;
+ break;
+ case SASL_DELEGATEDCREDS:
+ /* We can't really distinguish between "no delegated credentials"
+ and "authentication not finished" */
+ if(! conn->oparams.client_creds)
+ result = SASL_NOTDONE;
+ else
+ *((const char **)pvalue) = conn->oparams.client_creds;
+ break;
+ case SASL_GSS_PEER_NAME:
+ if(! conn->oparams.gss_peer_name)
+ result = SASL_NOTDONE;
+ else
+ *((const char **)pvalue) = conn->oparams.gss_peer_name;
+ break;
+ case SASL_GSS_LOCAL_NAME:
+ if(! conn->oparams.gss_local_name)
+ result = SASL_NOTDONE;
+ else
+ *((const char **)pvalue) = conn->oparams.gss_local_name;
+ break;
+ case SASL_SSF_EXTERNAL:
+ *((const sasl_ssf_t **)pvalue) = &conn->external.ssf;
+ break;
+ case SASL_AUTH_EXTERNAL:
+ *((const char **)pvalue) = conn->external.auth_id;
+ break;
+ case SASL_SEC_PROPS:
+ *((const sasl_security_properties_t **)pvalue) = &conn->props;
+ break;
+ case SASL_GSS_CREDS:
+ if(conn->type == SASL_CONN_CLIENT)
+ *(const void **)pvalue =
+ ((sasl_client_conn_t *)conn)->cparams->gss_creds;
+ else
+ *(const void **)pvalue =
+ ((sasl_server_conn_t *)conn)->sparams->gss_creds;
+ break;
+ case SASL_HTTP_REQUEST: {
+ if (conn->type == SASL_CONN_SERVER)
+ *(const sasl_http_request_t **)pvalue =
+ ((sasl_server_conn_t *)conn)->sparams->http_request;
+ else
+ *(const sasl_http_request_t **)pvalue =
+ ((sasl_client_conn_t *)conn)->cparams->http_request;
+ break;
+ }
+ default:
+ result = SASL_BADPARAM;
+ }
+
+ if(result == SASL_BADPARAM) {
+ PARAMERROR(conn);
+ } else if(result == SASL_NOTDONE) {
+ sasl_seterror(conn, SASL_NOLOG,
+ "Information that was requested is not yet available.");
+ RETURN(conn, result);
+ } else if(result != SASL_OK) {
+ INTERROR(conn, result);
+ } else
+ RETURN(conn, result);
+}
+
+/* set property in SASL connection state
+ * returns:
+ * SASL_OK -- value set
+ * SASL_BADPARAM -- invalid property or value
+ */
+int sasl_setprop(sasl_conn_t *conn, int propnum, const void *value)
+{
+ int result = SASL_OK;
+ char *str;
+
+ /* make sure the sasl context is valid */
+ if (!conn)
+ return SASL_BADPARAM;
+
+ switch(propnum)
+ {
+ case SASL_SSF_EXTERNAL:
+ conn->external.ssf = *((sasl_ssf_t *)value);
+ if(conn->type == SASL_CONN_SERVER) {
+ ((sasl_server_conn_t*)conn)->sparams->external_ssf =
+ conn->external.ssf;
+ } else {
+ ((sasl_client_conn_t*)conn)->cparams->external_ssf =
+ conn->external.ssf;
+ }
+ break;
+
+ case SASL_AUTH_EXTERNAL:
+ if(value && strlen(value)) {
+ result = _sasl_strdup(value, &str, NULL);
+ if(result != SASL_OK) MEMERROR(conn);
+ } else {
+ str = NULL;
+ }
+
+ if(conn->external.auth_id)
+ sasl_FREE(conn->external.auth_id);
+
+ conn->external.auth_id = str;
+
+ break;
+
+ case SASL_DEFUSERREALM:
+ if(conn->type != SASL_CONN_SERVER) {
+ sasl_seterror(conn, 0, "Tried to set realm on non-server connection");
+ result = SASL_BADPROT;
+ break;
+ }
+
+ if(value && strlen(value)) {
+ result = _sasl_strdup(value, &str, NULL);
+ if(result != SASL_OK) MEMERROR(conn);
+ } else {
+ PARAMERROR(conn);
+ }
+
+ if(((sasl_server_conn_t *)conn)->user_realm)
+ sasl_FREE(((sasl_server_conn_t *)conn)->user_realm);
+
+ ((sasl_server_conn_t *)conn)->user_realm = str;
+ ((sasl_server_conn_t *)conn)->sparams->user_realm = str;
+
+ break;
+
+ case SASL_SEC_PROPS:
+ {
+ sasl_security_properties_t *props = (sasl_security_properties_t *)value;
+
+ if(props->maxbufsize == 0 && props->min_ssf != 0) {
+ sasl_seterror(conn, 0,
+ "Attempt to disable security layers (maxoutbuf == 0) with min_ssf > 0");
+ RETURN(conn, SASL_TOOWEAK);
+ }
+
+ conn->props = *props;
+
+ if(conn->type == SASL_CONN_SERVER) {
+ ((sasl_server_conn_t*)conn)->sparams->props = *props;
+ } else {
+ ((sasl_client_conn_t*)conn)->cparams->props = *props;
+ }
+
+ break;
+ }
+
+ case SASL_IPREMOTEPORT:
+ {
+ const char *ipremoteport = (const char *)value;
+ if(!value) {
+ conn->got_ip_remote = 0;
+ } else if (_sasl_ipfromstring(ipremoteport, NULL, 0)
+ != SASL_OK) {
+ sasl_seterror(conn, 0, "Bad IPREMOTEPORT value");
+ RETURN(conn, SASL_BADPARAM);
+ } else {
+ strcpy(conn->ipremoteport, ipremoteport);
+ conn->got_ip_remote = 1;
+ }
+
+ if(conn->got_ip_remote) {
+ if(conn->type == SASL_CONN_CLIENT) {
+ ((sasl_client_conn_t *)conn)->cparams->ipremoteport
+ = conn->ipremoteport;
+ ((sasl_client_conn_t *)conn)->cparams->ipremlen =
+ (unsigned) strlen(conn->ipremoteport);
+ } else if (conn->type == SASL_CONN_SERVER) {
+ ((sasl_server_conn_t *)conn)->sparams->ipremoteport
+ = conn->ipremoteport;
+ ((sasl_server_conn_t *)conn)->sparams->ipremlen =
+ (unsigned) strlen(conn->ipremoteport);
+ }
+ } else {
+ if(conn->type == SASL_CONN_CLIENT) {
+ ((sasl_client_conn_t *)conn)->cparams->ipremoteport
+ = NULL;
+ ((sasl_client_conn_t *)conn)->cparams->ipremlen = 0;
+ } else if (conn->type == SASL_CONN_SERVER) {
+ ((sasl_server_conn_t *)conn)->sparams->ipremoteport
+ = NULL;
+ ((sasl_server_conn_t *)conn)->sparams->ipremlen = 0;
+ }
+ }
+
+ break;
+ }
+
+ case SASL_IPLOCALPORT:
+ {
+ const char *iplocalport = (const char *)value;
+ if(!value) {
+ conn->got_ip_local = 0;
+ } else if (_sasl_ipfromstring(iplocalport, NULL, 0)
+ != SASL_OK) {
+ sasl_seterror(conn, 0, "Bad IPLOCALPORT value");
+ RETURN(conn, SASL_BADPARAM);
+ } else {
+ strcpy(conn->iplocalport, iplocalport);
+ conn->got_ip_local = 1;
+ }
+
+ if(conn->got_ip_local) {
+ if(conn->type == SASL_CONN_CLIENT) {
+ ((sasl_client_conn_t *)conn)->cparams->iplocalport
+ = conn->iplocalport;
+ ((sasl_client_conn_t *)conn)->cparams->iploclen
+ = (unsigned) strlen(conn->iplocalport);
+ } else if (conn->type == SASL_CONN_SERVER) {
+ ((sasl_server_conn_t *)conn)->sparams->iplocalport
+ = conn->iplocalport;
+ ((sasl_server_conn_t *)conn)->sparams->iploclen
+ = (unsigned) strlen(conn->iplocalport);
+ }
+ } else {
+ if(conn->type == SASL_CONN_CLIENT) {
+ ((sasl_client_conn_t *)conn)->cparams->iplocalport
+ = NULL;
+ ((sasl_client_conn_t *)conn)->cparams->iploclen = 0;
+ } else if (conn->type == SASL_CONN_SERVER) {
+ ((sasl_server_conn_t *)conn)->sparams->iplocalport
+ = NULL;
+ ((sasl_server_conn_t *)conn)->sparams->iploclen = 0;
+ }
+ }
+ break;
+ }
+
+ case SASL_APPNAME:
+ /* Currently we only support server side contexts, but we should
+ be able to extend this to support client side contexts as well */
+ if(conn->type != SASL_CONN_SERVER) {
+ sasl_seterror(conn, 0, "Tried to set application name on non-server connection");
+ result = SASL_BADPROT;
+ break;
+ }
+
+ if(((sasl_server_conn_t *)conn)->appname) {
+ sasl_FREE(((sasl_server_conn_t *)conn)->appname);
+ ((sasl_server_conn_t *)conn)->appname = NULL;
+ }
+
+ if(value && strlen(value)) {
+ result = _sasl_strdup(value,
+ &(((sasl_server_conn_t *)conn)->appname),
+ NULL);
+ if(result != SASL_OK) MEMERROR(conn);
+ ((sasl_server_conn_t *)conn)->sparams->appname =
+ ((sasl_server_conn_t *)conn)->appname;
+ ((sasl_server_conn_t *)conn)->sparams->applen =
+ (unsigned) strlen(((sasl_server_conn_t *)conn)->appname);
+ } else {
+ ((sasl_server_conn_t *)conn)->sparams->appname = NULL;
+ ((sasl_server_conn_t *)conn)->sparams->applen = 0;
+ }
+ break;
+
+ case SASL_GSS_CREDS:
+ if(conn->type == SASL_CONN_CLIENT)
+ ((sasl_client_conn_t *)conn)->cparams->gss_creds = value;
+ else
+ ((sasl_server_conn_t *)conn)->sparams->gss_creds = value;
+ break;
+
+ case SASL_CHANNEL_BINDING: {
+ const struct sasl_channel_binding *cb = (const struct sasl_channel_binding *)value;
+
+ if (conn->type == SASL_CONN_SERVER)
+ ((sasl_server_conn_t *)conn)->sparams->cbinding = cb;
+ else
+ ((sasl_client_conn_t *)conn)->cparams->cbinding = cb;
+ break;
+ }
+
+ case SASL_HTTP_REQUEST: {
+ const sasl_http_request_t *req = (const sasl_http_request_t *)value;
+
+ if (conn->type == SASL_CONN_SERVER)
+ ((sasl_server_conn_t *)conn)->sparams->http_request = req;
+ else
+ ((sasl_client_conn_t *)conn)->cparams->http_request = req;
+ break;
+ }
+
+ default:
+ sasl_seterror(conn, 0, "Unknown parameter type");
+ result = SASL_BADPARAM;
+ }
+
+ RETURN(conn, result);
+}
+
+/* this is apparently no longer a user function */
+static int sasl_usererr(int saslerr)
+{
+ /* Hide the difference in a username failure and a password failure */
+ if (saslerr == SASL_NOUSER)
+ return SASL_BADAUTH;
+
+ /* otherwise return the error given; no transform necessary */
+ return saslerr;
+}
+
+const char *sasl_errstring(int saslerr,
+ const char *langlist __attribute__((unused)),
+ const char **outlang)
+{
+ if (outlang) *outlang="en-us";
+
+ switch(saslerr)
+ {
+ case SASL_CONTINUE: return "another step is needed in authentication";
+ case SASL_OK: return "successful result";
+ case SASL_FAIL: return "generic failure";
+ case SASL_NOMEM: return "no memory available";
+ case SASL_BUFOVER: return "overflowed buffer";
+ case SASL_NOMECH: return "no mechanism available";
+ case SASL_BADPROT: return "bad protocol / cancel";
+ case SASL_NOTDONE: return "can't request information until later in exchange";
+ case SASL_BADPARAM: return "invalid parameter supplied";
+ case SASL_TRYAGAIN: return "transient failure (e.g., weak key)";
+ case SASL_BADMAC: return "integrity check failed";
+ case SASL_NOTINIT: return "SASL library is not initialized";
+ /* -- client only codes -- */
+ case SASL_INTERACT: return "needs user interaction";
+ case SASL_BADSERV: return "server failed mutual authentication step";
+ case SASL_WRONGMECH: return "mechanism doesn't support requested feature";
+ /* -- server only codes -- */
+ case SASL_BADAUTH: return "authentication failure";
+ case SASL_NOAUTHZ: return "authorization failure";
+ case SASL_TOOWEAK: return "mechanism too weak for this user";
+ case SASL_ENCRYPT: return "encryption needed to use mechanism";
+ case SASL_TRANS: return "One time use of a plaintext password will enable requested mechanism for user";
+ case SASL_EXPIRED: return "passphrase expired, has to be reset";
+ case SASL_DISABLED: return "account disabled";
+ case SASL_NOUSER: return "user not found";
+ case SASL_BADVERS: return "version mismatch with plug-in";
+ case SASL_UNAVAIL: return "remote authentication server unavailable";
+ case SASL_NOVERIFY: return "user exists, but no verifier for user";
+ case SASL_PWLOCK: return "passphrase locked";
+ case SASL_NOCHANGE: return "requested change was not needed";
+ case SASL_WEAKPASS: return "passphrase is too weak for security policy";
+ case SASL_NOUSERPASS: return "user supplied passwords are not permitted";
+ case SASL_NEED_OLD_PASSWD: return "sasl_setpass needs old password in order "
+ "to perform password change";
+ case SASL_CONSTRAINT_VIOLAT: return "sasl_setpass can't store a property because "
+ "of a constraint violation";
+ case SASL_BADBINDING: return "channel binding failure";
+ case SASL_CONFIGERR: return "error when parsing configuration file";
+
+ default: return "undefined error!";
+ }
+
+}
+
+/* Return the sanitized error detail about the last error that occured for
+ * a connection */
+const char *sasl_errdetail(sasl_conn_t *conn)
+{
+ unsigned need_len;
+ const char *errstr;
+ char leader[128];
+
+ if(!conn) return NULL;
+
+ errstr = sasl_errstring(conn->error_code, NULL, NULL);
+ snprintf(leader,128,"SASL(%d): %s: ",
+ sasl_usererr(conn->error_code), errstr);
+
+ need_len = (unsigned) (strlen(leader) + strlen(conn->error_buf) + 12);
+ if (_buf_alloc(&conn->errdetail_buf, &conn->errdetail_buf_len, need_len) != SASL_OK) {
+ return NULL;
+ }
+
+ snprintf(conn->errdetail_buf, need_len, "%s%s", leader, conn->error_buf);
+
+ return conn->errdetail_buf;
+}
+
+
+/* Note that this needs the global callbacks, so if you don't give getcallbacks
+ * a sasl_conn_t, you're going to need to pass it yourself (or else we couldn't
+ * have client and server at the same time */
+static int _sasl_global_getopt(void *context,
+ const char *plugin_name,
+ const char *option,
+ const char ** result,
+ unsigned *len)
+{
+ const sasl_global_callbacks_t * global_callbacks;
+ const sasl_callback_t *callback;
+
+ global_callbacks = (const sasl_global_callbacks_t *) context;
+
+ if (global_callbacks && global_callbacks->callbacks) {
+ for (callback = global_callbacks->callbacks;
+ callback->id != SASL_CB_LIST_END;
+ callback++) {
+ if (callback->id == SASL_CB_GETOPT) {
+ if (!callback->proc) return SASL_FAIL;
+ if (((sasl_getopt_t *)(callback->proc))(callback->context,
+ plugin_name,
+ option,
+ result,
+ len)
+ == SASL_OK)
+ return SASL_OK;
+ }
+ }
+ }
+
+ /* look it up in our configuration file */
+ *result = sasl_config_getstring(option, NULL);
+ if (*result != NULL) {
+ if (len) { *len = (unsigned) strlen(*result); }
+ return SASL_OK;
+ }
+
+ return SASL_FAIL;
+}
+
+static int
+_sasl_conn_getopt(void *context,
+ const char *plugin_name,
+ const char *option,
+ const char ** result,
+ unsigned *len)
+{
+ sasl_conn_t * conn;
+ const sasl_callback_t *callback;
+
+ if (! context)
+ return SASL_BADPARAM;
+
+ conn = (sasl_conn_t *) context;
+
+ if (conn->callbacks)
+ for (callback = conn->callbacks;
+ callback->id != SASL_CB_LIST_END;
+ callback++)
+ if (callback->id == SASL_CB_GETOPT
+ && (((sasl_getopt_t *)(callback->proc))(callback->context,
+ plugin_name,
+ option,
+ result,
+ len)
+ == SASL_OK))
+ return SASL_OK;
+
+ /* If we made it here, we didn't find an appropriate callback
+ * in the connection's callback list, or the callback we did
+ * find didn't return SASL_OK. So we attempt to use the
+ * global callback for this connection... */
+ return _sasl_global_getopt((void *)conn->global_callbacks,
+ plugin_name,
+ option,
+ result,
+ len);
+}
+
+#ifdef HAVE_SYSLOG
+/* this is the default logging */
+static int _sasl_syslog(void *context,
+ int priority,
+ const char *message)
+{
+ int syslog_priority;
+ sasl_server_conn_t *sconn;
+
+ if (context) {
+ if (((sasl_conn_t *)context)->type == SASL_CONN_SERVER) {
+ sconn = (sasl_server_conn_t *)context;
+ if (sconn->sparams->log_level < priority)
+ return SASL_OK;
+ }
+ }
+
+ /* set syslog priority */
+ switch(priority) {
+ case SASL_LOG_NONE:
+ return SASL_OK;
+ break;
+ case SASL_LOG_ERR:
+ syslog_priority = LOG_ERR;
+ break;
+ case SASL_LOG_WARN:
+ syslog_priority = LOG_WARNING;
+ break;
+ case SASL_LOG_NOTE:
+ case SASL_LOG_FAIL:
+ syslog_priority = LOG_NOTICE;
+ break;
+ case SASL_LOG_PASS:
+ case SASL_LOG_TRACE:
+ case SASL_LOG_DEBUG:
+ default:
+ syslog_priority = LOG_DEBUG;
+ break;
+ }
+
+ /* do the syslog call. Do not need to call openlog? */
+ syslog(syslog_priority | LOG_AUTH, "%s", message);
+
+ return SASL_OK;
+}
+#endif /* HAVE_SYSLOG */
+
+static int
+_sasl_getsimple(void *context,
+ int id,
+ const char ** result,
+ size_t *len)
+{
+ const char *userid;
+
+ if (! context || ! result) return SASL_BADPARAM;
+
+ switch(id) {
+ case SASL_CB_AUTHNAME:
+ userid = getenv("USER");
+ if (userid != NULL) {
+ *result = userid;
+ if (len) *len = strlen(userid);
+ return SASL_OK;
+ }
+ userid = getenv("USERNAME");
+ if (userid != NULL) {
+ *result = userid;
+ if (len) *len = strlen(userid);
+ return SASL_OK;
+ }
+#ifdef WIN32
+ /* for win32, try using the GetUserName standard call */
+ {
+ DWORD i;
+ BOOL rval;
+ static char sender[128];
+
+ TCHAR tsender[128];
+ i = sizeof(tsender) / sizeof(tsender[0]);
+ rval = GetUserName(tsender, &i);
+ if ( rval) { /* got a userid */
+ WideCharToMultiByte(CP_UTF8, 0, tsender, -1, sender, sizeof(sender), NULL, NULL); /* -1 ensures null-terminated utf8 */
+ *result = sender;
+ if (len) *len = strlen(sender);
+ return SASL_OK;
+ }
+ }
+#endif /* WIN32 */
+ return SASL_FAIL;
+ default:
+ return SASL_BADPARAM;
+ }
+}
+
+static int
+_sasl_getpath(void *context __attribute__((unused)),
+ const char ** path_dest)
+{
+#if !defined(WIN32)
+ char *path;
+#endif
+ int res = SASL_OK;
+
+ if (! path_dest) {
+ return SASL_BADPARAM;
+ }
+
+ /* Only calculate the path once. */
+ if (default_plugin_path == NULL) {
+
+#if defined(WIN32)
+ /* NB: On Windows platforms this value is always allocated */
+ default_plugin_path = _sasl_get_default_win_path(context,
+ SASL_PLUGIN_PATH_ATTR,
+ PLUGINDIR);
+#else
+ /* NB: On Unix platforms this value is never allocated */
+ path = _sasl_get_default_unix_path(context,
+ SASL_PATH_ENV_VAR,
+ PLUGINDIR);
+
+ res = _sasl_strdup(path, &default_plugin_path, NULL);
+#endif
+ }
+
+ if (res == SASL_OK) {
+ *path_dest = default_plugin_path;
+ }
+
+ return res;
+}
+
+static int
+_sasl_getpath_simple(void *context __attribute__((unused)),
+ const char **path)
+{
+ if (! path) {
+ return SASL_BADPARAM;
+ }
+
+ if (default_plugin_path == NULL) {
+ return SASL_FAIL;
+ }
+
+ *path = default_plugin_path;
+
+ return SASL_OK;
+}
+
+static int
+_sasl_getconfpath(void *context __attribute__((unused)),
+ char ** path_dest)
+{
+#if !defined(WIN32)
+ char *path;
+#endif
+ int res = SASL_OK;
+
+ if (! path_dest) {
+ return SASL_BADPARAM;
+ }
+
+ /* Only calculate the path once. */
+ if (default_conf_path == NULL) {
+
+#if defined(WIN32)
+ /* NB: On Windows platforms this value is always allocated */
+ default_conf_path = _sasl_get_default_win_path(context,
+ SASL_CONF_PATH_ATTR,
+ CONFIGDIR);
+#else
+ /* NB: On Unix platforms this value is never allocated */
+ path = _sasl_get_default_unix_path(context,
+ SASL_CONF_PATH_ENV_VAR,
+ CONFIGDIR);
+
+ res = _sasl_strdup(path, &default_conf_path, NULL);
+#endif
+ }
+
+ if (res == SASL_OK) {
+ *path_dest = default_conf_path;
+ }
+
+ return res;
+}
+
+static int
+_sasl_getconfpath_simple(void *context __attribute__((unused)),
+ const char **path)
+{
+ if (! path) {
+ return SASL_BADPARAM;
+ }
+
+ if (default_conf_path == NULL) {
+ return SASL_FAIL;
+ }
+
+ *path = default_conf_path;
+
+ return SASL_OK;
+}
+
+
+static int
+_sasl_verifyfile(void *context __attribute__((unused)),
+ char *file __attribute__((unused)),
+ int type __attribute__((unused)))
+{
+ /* always say ok */
+ return SASL_OK;
+}
+
+
+static int
+_sasl_proxy_policy(sasl_conn_t *conn,
+ void *context __attribute__((unused)),
+ const char *requested_user, unsigned rlen,
+ const char *auth_identity, unsigned alen,
+ const char *def_realm __attribute__((unused)),
+ unsigned urlen __attribute__((unused)),
+ struct propctx *propctx __attribute__((unused)))
+{
+ if (!conn)
+ return SASL_BADPARAM;
+
+ if (!requested_user || *requested_user == '\0')
+ return SASL_OK;
+
+ if (!auth_identity || !requested_user || rlen != alen ||
+ (memcmp(auth_identity, requested_user, rlen) != 0)) {
+ sasl_seterror(conn, 0,
+ "Requested identity not authenticated identity");
+ RETURN(conn, SASL_BADAUTH);
+ }
+
+ return SASL_OK;
+}
+
+int _sasl_getcallback(sasl_conn_t * conn,
+ unsigned long callbackid,
+ sasl_callback_ft *pproc,
+ void **pcontext)
+{
+ const sasl_callback_t *callback;
+
+ if (!pproc || !pcontext)
+ PARAMERROR(conn);
+
+ /* Some callbacks are always provided by the library */
+ switch (callbackid) {
+ case SASL_CB_LIST_END:
+ /* Nothing ever gets to provide this */
+ INTERROR(conn, SASL_FAIL);
+ case SASL_CB_GETOPT:
+ if (conn) {
+ *pproc = (sasl_callback_ft)&_sasl_conn_getopt;
+ *pcontext = conn;
+ } else {
+ *pproc = (sasl_callback_ft)&_sasl_global_getopt;
+ *pcontext = NULL;
+ }
+ return SASL_OK;
+ }
+
+ /* If it's not always provided by the library, see if there's
+ * a version provided by the application for this connection... */
+ if (conn && conn->callbacks) {
+ for (callback = conn->callbacks; callback->id != SASL_CB_LIST_END;
+ callback++) {
+ if (callback->id == callbackid) {
+ *pproc = callback->proc;
+ *pcontext = callback->context;
+ if (callback->proc) {
+ return SASL_OK;
+ } else {
+ return SASL_INTERACT;
+ }
+ }
+ }
+ }
+
+ /* And, if not for this connection, see if there's one
+ * for all {server,client} connections... */
+ if (conn && conn->global_callbacks && conn->global_callbacks->callbacks) {
+ for (callback = conn->global_callbacks->callbacks;
+ callback->id != SASL_CB_LIST_END;
+ callback++) {
+ if (callback->id == callbackid) {
+ *pproc = callback->proc;
+ *pcontext = callback->context;
+ if (callback->proc) {
+ return SASL_OK;
+ } else {
+ return SASL_INTERACT;
+ }
+ }
+ }
+ }
+
+ /* Otherwise, see if the library provides a default callback. */
+ switch (callbackid) {
+#ifdef HAVE_SYSLOG
+ case SASL_CB_LOG:
+ *pproc = (sasl_callback_ft)&_sasl_syslog;
+ *pcontext = conn;
+ return SASL_OK;
+#endif /* HAVE_SYSLOG */
+ case SASL_CB_GETPATH:
+ *pproc = default_getpath_cb.proc;
+ *pcontext = default_getpath_cb.context;
+ return SASL_OK;
+ case SASL_CB_GETCONFPATH:
+ *pproc = default_getconfpath_cb.proc;
+ *pcontext = default_getconfpath_cb.context;
+ return SASL_OK;
+ case SASL_CB_AUTHNAME:
+ *pproc = (sasl_callback_ft)&_sasl_getsimple;
+ *pcontext = conn;
+ return SASL_OK;
+ case SASL_CB_VERIFYFILE:
+ *pproc = (sasl_callback_ft)&_sasl_verifyfile;
+ *pcontext = NULL;
+ return SASL_OK;
+ case SASL_CB_PROXY_POLICY:
+ *pproc = (sasl_callback_ft)&_sasl_proxy_policy;
+ *pcontext = NULL;
+ return SASL_OK;
+ }
+
+ /* Unable to find a callback... */
+ *pproc = NULL;
+ *pcontext = NULL;
+ sasl_seterror(conn, SASL_NOLOG, "Unable to find a callback: %d", callbackid);
+ RETURN(conn,SASL_FAIL);
+}
+
+
+/*
+ * This function is typically called from a plugin.
+ * It creates a string from the formatting and varargs given
+ * and calls the logging callback (syslog by default)
+ *
+ * %m will parse the value in the next argument as an errno string
+ * %z will parse the next argument as a SASL error code.
+ */
+
+void
+_sasl_log (sasl_conn_t *conn,
+ int level,
+ const char *fmt,
+ ...)
+{
+ char *out = NULL;
+ size_t alloclen=100; /* current allocated length */
+ size_t outlen=0; /* current length of output buffer */
+ size_t formatlen;
+ size_t pos=0; /* current position in format string */
+ int result;
+ sasl_log_t *log_cb;
+ void *log_ctx;
+
+ int ival;
+ unsigned int uval;
+ char *cval;
+ va_list ap; /* varargs thing */
+
+ if(!fmt) return;
+
+ out = (char *) sasl_ALLOC(250);
+ if(!out) return;
+
+ formatlen = strlen(fmt);
+
+ /* See if we have a logging callback... */
+ result = _sasl_getcallback(conn, SASL_CB_LOG, (sasl_callback_ft *)&log_cb, &log_ctx);
+ if (result == SASL_OK && ! log_cb)
+ result = SASL_FAIL;
+ if (result != SASL_OK) goto done;
+
+ va_start(ap, fmt); /* start varargs */
+
+ while(pos<formatlen)
+ {
+ if (fmt[pos]!='%') /* regular character */
+ {
+ result = _buf_alloc(&out, &alloclen, outlen+1);
+ if (result != SASL_OK) goto done;
+ out[outlen]=fmt[pos];
+ outlen++;
+ pos++;
+
+ } else { /* formating thing */
+ int done=0;
+ char frmt[10];
+ int frmtpos=1;
+ char tempbuf[21];
+ frmt[0]='%';
+ pos++;
+
+ while (done==0)
+ {
+ switch(fmt[pos])
+ {
+ case 's': /* need to handle this */
+ cval = va_arg(ap, char *); /* get the next arg */
+ result = _sasl_add_string(&out, &alloclen,
+ &outlen, cval);
+
+ if (result != SASL_OK) /* add the string */
+ goto done;
+
+ done=1;
+ break;
+
+ case '%': /* double % output the '%' character */
+ result = _buf_alloc(&out,&alloclen,outlen+1);
+ if (result != SASL_OK)
+ goto done;
+
+ out[outlen]='%';
+ outlen++;
+ done=1;
+ break;
+
+ case 'm': /* insert the errno string */
+ result = _sasl_add_string(&out, &alloclen, &outlen,
+ strerror(va_arg(ap, int)));
+ if (result != SASL_OK)
+ goto done;
+
+ done=1;
+ break;
+
+ case 'z': /* insert the sasl error string */
+ result = _sasl_add_string(&out, &alloclen, &outlen,
+ (char *) sasl_errstring(va_arg(ap, int),NULL,NULL));
+ if (result != SASL_OK)
+ goto done;
+
+ done=1;
+ break;
+
+ case 'c':
+ frmt[frmtpos++]=fmt[pos];
+ frmt[frmtpos]=0;
+ tempbuf[0] = (char) va_arg(ap, int); /* get the next arg */
+ tempbuf[1]='\0';
+
+ /* now add the character */
+ result = _sasl_add_string(&out, &alloclen, &outlen, tempbuf);
+ if (result != SASL_OK)
+ goto done;
+
+ done=1;
+ break;
+
+ case 'd':
+ case 'i':
+ frmt[frmtpos++]=fmt[pos];
+ frmt[frmtpos]=0;
+ ival = va_arg(ap, int); /* get the next arg */
+
+ snprintf(tempbuf,20,frmt,ival); /* have snprintf do the work */
+ /* now add the string */
+ result = _sasl_add_string(&out, &alloclen, &outlen, tempbuf);
+ if (result != SASL_OK)
+ goto done;
+
+ done=1;
+ break;
+
+ case 'o':
+ case 'u':
+ case 'x':
+ case 'X':
+ frmt[frmtpos++]=fmt[pos];
+ frmt[frmtpos]=0;
+ uval = va_arg(ap, unsigned int); /* get the next arg */
+
+ snprintf(tempbuf,20,frmt,uval); /* have snprintf do the work */
+ /* now add the string */
+ result = _sasl_add_string(&out, &alloclen, &outlen, tempbuf);
+ if (result != SASL_OK)
+ goto done;
+
+ done=1;
+ break;
+
+ default:
+ frmt[frmtpos++]=fmt[pos]; /* add to the formating */
+ frmt[frmtpos]=0;
+ if (frmtpos>9)
+ done=1;
+ }
+ pos++;
+ if (pos>formatlen)
+ done=1;
+ }
+
+ }
+ }
+
+ /* put 0 at end */
+ result = _buf_alloc(&out, &alloclen, outlen+1);
+ if (result != SASL_OK) goto done;
+ out[outlen]=0;
+
+ /* send log message */
+ result = log_cb(log_ctx, level, out);
+
+ done:
+ va_end(ap);
+ if(out) sasl_FREE(out);
+}
+
+
+
+/* Allocate and Init a sasl_utils_t structure */
+sasl_utils_t *
+_sasl_alloc_utils(sasl_conn_t *conn,
+ sasl_global_callbacks_t *global_callbacks)
+{
+ sasl_utils_t *utils;
+ /* set util functions - need to do rest*/
+ utils=sasl_ALLOC(sizeof(sasl_utils_t));
+ if (utils==NULL)
+ return NULL;
+
+ utils->conn = conn;
+
+ sasl_randcreate(&utils->rpool);
+
+ if (conn) {
+ utils->getopt = &_sasl_conn_getopt;
+ utils->getopt_context = conn;
+ } else {
+ utils->getopt = &_sasl_global_getopt;
+ utils->getopt_context = global_callbacks;
+ }
+
+ utils->malloc=_sasl_allocation_utils.malloc;
+ utils->calloc=_sasl_allocation_utils.calloc;
+ utils->realloc=_sasl_allocation_utils.realloc;
+ utils->free=_sasl_allocation_utils.free;
+
+ utils->mutex_alloc = _sasl_mutex_utils.alloc;
+ utils->mutex_lock = _sasl_mutex_utils.lock;
+ utils->mutex_unlock = _sasl_mutex_utils.unlock;
+ utils->mutex_free = _sasl_mutex_utils.free;
+
+ utils->MD5Init = &_sasl_MD5Init;
+ utils->MD5Update= &_sasl_MD5Update;
+ utils->MD5Final = &_sasl_MD5Final;
+ utils->hmac_md5 = &_sasl_hmac_md5;
+ utils->hmac_md5_init = &_sasl_hmac_md5_init;
+ utils->hmac_md5_final = &_sasl_hmac_md5_final;
+ utils->hmac_md5_precalc = &_sasl_hmac_md5_precalc;
+ utils->hmac_md5_import = &_sasl_hmac_md5_import;
+ utils->mkchal = &sasl_mkchal;
+ utils->utf8verify = &sasl_utf8verify;
+ utils->rand=&sasl_rand;
+ utils->churn=&sasl_churn;
+ utils->checkpass=NULL;
+
+ utils->encode64=&sasl_encode64;
+ utils->decode64=&sasl_decode64;
+
+ utils->erasebuffer=&sasl_erasebuffer;
+
+ utils->getprop=&sasl_getprop;
+ utils->setprop=&sasl_setprop;
+
+ utils->getcallback=&_sasl_getcallback;
+
+ utils->log=&_sasl_log;
+
+ utils->seterror=&sasl_seterror;
+
+#ifndef macintosh
+ /* Aux Property Utilities */
+ utils->prop_new=&prop_new;
+ utils->prop_dup=&prop_dup;
+ utils->prop_request=&prop_request;
+ utils->prop_get=&prop_get;
+ utils->prop_getnames=&prop_getnames;
+ utils->prop_clear=&prop_clear;
+ utils->prop_dispose=&prop_dispose;
+ utils->prop_format=&prop_format;
+ utils->prop_set=&prop_set;
+ utils->prop_setvals=&prop_setvals;
+ utils->prop_erase=&prop_erase;
+ utils->auxprop_store=&sasl_auxprop_store;
+#endif
+
+ /* Spares */
+ utils->spare_fptr = NULL;
+ utils->spare_fptr1 = utils->spare_fptr2 = NULL;
+
+ return utils;
+}
+
+int
+_sasl_free_utils(const sasl_utils_t ** utils)
+{
+ sasl_utils_t *nonconst;
+
+ if(!utils) return SASL_BADPARAM;
+ if(!*utils) return SASL_OK;
+
+ /* I wish we could avoid this cast, it's pretty gratuitous but it
+ * does make life easier to have it const everywhere else. */
+ nonconst = (sasl_utils_t *)(*utils);
+
+ sasl_randfree(&(nonconst->rpool));
+ sasl_FREE(nonconst);
+
+ *utils = NULL;
+ return SASL_OK;
+}
+
+int sasl_idle(sasl_conn_t *conn)
+{
+ if (! conn) {
+ if (_sasl_server_idle_hook
+ && _sasl_server_idle_hook(NULL))
+ return 1;
+ if (_sasl_client_idle_hook
+ && _sasl_client_idle_hook(NULL))
+ return 1;
+ return 0;
+ }
+
+ if (conn->idle_hook)
+ return conn->idle_hook(conn);
+
+ return 0;
+}
+
+static const sasl_callback_t *
+_sasl_find_callback_by_type (const sasl_callback_t *callbacks,
+ unsigned long id)
+{
+ if (callbacks) {
+ while (callbacks->id != SASL_CB_LIST_END) {
+ if (callbacks->id == id) {
+ return callbacks;
+ } else {
+ ++callbacks;
+ }
+ }
+ }
+ return NULL;
+}
+
+const sasl_callback_t *
+_sasl_find_getpath_callback(const sasl_callback_t *callbacks)
+{
+ callbacks = _sasl_find_callback_by_type (callbacks, SASL_CB_GETPATH);
+ if (callbacks != NULL) {
+ return callbacks;
+ } else {
+ return &default_getpath_cb;
+ }
+}
+
+const sasl_callback_t *
+_sasl_find_getconfpath_callback(const sasl_callback_t *callbacks)
+{
+ callbacks = _sasl_find_callback_by_type (callbacks, SASL_CB_GETCONFPATH);
+ if (callbacks != NULL) {
+ return callbacks;
+ } else {
+ return &default_getconfpath_cb;
+ }
+}
+
+const sasl_callback_t *
+_sasl_find_verifyfile_callback(const sasl_callback_t *callbacks)
+{
+ static const sasl_callback_t default_verifyfile_cb = {
+ SASL_CB_VERIFYFILE,
+ (sasl_callback_ft)&_sasl_verifyfile,
+ NULL
+ };
+
+ callbacks = _sasl_find_callback_by_type (callbacks, SASL_CB_VERIFYFILE);
+ if (callbacks != NULL) {
+ return callbacks;
+ } else {
+ return &default_verifyfile_cb;
+ }
+}
+
+/* Basically a conditional call to realloc(), if we need more */
+int _buf_alloc(char **rwbuf, size_t *curlen, size_t newlen)
+{
+ if(!(*rwbuf)) {
+ *rwbuf = sasl_ALLOC((unsigned)newlen);
+ if (*rwbuf == NULL) {
+ *curlen = 0;
+ return SASL_NOMEM;
+ }
+ *curlen = newlen;
+ } else if(*rwbuf && *curlen < newlen) {
+ size_t needed = 2*(*curlen);
+
+ while(needed < newlen)
+ needed *= 2;
+
+ /* WARN - We will leak the old buffer on failure */
+ *rwbuf = sasl_REALLOC(*rwbuf, (unsigned)needed);
+
+ if (*rwbuf == NULL) {
+ *curlen = 0;
+ return SASL_NOMEM;
+ }
+ *curlen = needed;
+ }
+
+ return SASL_OK;
+}
+
+/* for the mac os x cfm glue: this lets the calling function
+ get pointers to the error buffer without having to touch the sasl_conn_t struct */
+void _sasl_get_errorbuf(sasl_conn_t *conn, char ***bufhdl, size_t **lenhdl)
+{
+ *bufhdl = &conn->error_buf;
+ *lenhdl = &conn->error_buf_len;
+}
+
+/* convert an iovec to a single buffer */
+int _iovec_to_buf(const struct iovec *vec,
+ unsigned numiov, buffer_info_t **output)
+{
+ unsigned i;
+ int ret;
+ buffer_info_t *out;
+ char *pos;
+
+ if (!vec || !output) return SASL_BADPARAM;
+
+ if (!(*output)) {
+ *output = sasl_ALLOC(sizeof(buffer_info_t));
+ if (!*output) return SASL_NOMEM;
+ memset(*output,0,sizeof(buffer_info_t));
+ }
+
+ out = *output;
+
+ out->curlen = 0;
+ for (i = 0; i < numiov; i++) {
+ out->curlen += vec[i].iov_len;
+ }
+
+ ret = _buf_alloc(&out->data, &out->reallen, out->curlen);
+
+ if (ret != SASL_OK) return SASL_NOMEM;
+
+ memset(out->data, 0, out->reallen);
+ pos = out->data;
+
+ for (i = 0; i < numiov; i++) {
+ memcpy(pos, vec[i].iov_base, vec[i].iov_len);
+ pos += vec[i].iov_len;
+ }
+
+ return SASL_OK;
+}
+
+/* This code might be useful in the future, but it isn't now, so.... */
+#if 0
+int _sasl_iptostring(const struct sockaddr *addr, socklen_t addrlen,
+ char *out, unsigned outlen) {
+ char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
+ int niflags;
+
+ if(!addr || !out) return SASL_BADPARAM;
+
+ niflags = (NI_NUMERICHOST | NI_NUMERICSERV);
+#ifdef NI_WITHSCOPEID
+ if (addr->sa_family == AF_INET6)
+ niflags |= NI_WITHSCOPEID;
+#endif
+ if (getnameinfo(addr, addrlen, hbuf, sizeof(hbuf), pbuf, sizeof(pbuf),
+ niflags) != 0)
+ return SASL_BADPARAM;
+
+ if(outlen < strlen(hbuf) + strlen(pbuf) + 2)
+ return SASL_BUFOVER;
+
+ snprintf(out, outlen, "%s;%s", hbuf, pbuf);
+
+ return SASL_OK;
+}
+#endif
+
+int _sasl_ipfromstring(const char *addr,
+ struct sockaddr *out, socklen_t outlen)
+{
+ int i, j;
+ struct addrinfo hints, *ai = NULL;
+ char hbuf[NI_MAXHOST];
+
+ /* A NULL out pointer just implies we don't do a copy, just verify it */
+
+ if(!addr) return SASL_BADPARAM;
+
+ /* Parse the address */
+ for (i = 0; addr[i] != '\0' && addr[i] != ';'; i++) {
+ if (i >= NI_MAXHOST)
+ return SASL_BADPARAM;
+ hbuf[i] = addr[i];
+ }
+ hbuf[i] = '\0';
+
+ if (addr[i] == ';')
+ i++;
+ /* XXX: Do we need this check? */
+ for (j = i; addr[j] != '\0'; j++)
+ if (!isdigit((int)(addr[j])))
+ return SASL_BADPARAM;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
+ if (getaddrinfo(hbuf, &addr[i], &hints, &ai) != 0)
+ return SASL_BADPARAM;
+
+ if (out) {
+ if (outlen < (socklen_t)ai->ai_addrlen) {
+ freeaddrinfo(ai);
+ return SASL_BUFOVER;
+ }
+ memcpy(out, ai->ai_addr, ai->ai_addrlen);
+ }
+
+ freeaddrinfo(ai);
+
+ return SASL_OK;
+}
+
+int _sasl_build_mechlist(void)
+{
+ int count = 0;
+ sasl_string_list_t *clist = NULL, *slist = NULL, *olist = NULL;
+ sasl_string_list_t *p, *q, **last, *p_next;
+
+ clist = _sasl_client_mechs();
+ slist = _sasl_server_mechs();
+
+ if(!clist) {
+ olist = slist;
+ } else {
+ int flag;
+
+ /* append slist to clist, and set olist to clist */
+ for(p = slist; p; p = p_next) {
+ flag = 0;
+ p_next = p->next;
+
+ last = &clist;
+ for(q = clist; q; q = q->next) {
+ if(!strcmp(q->d, p->d)) {
+ /* They match, set the flag */
+ flag = 1;
+ break;
+ }
+ last = &(q->next);
+ }
+
+ if(!flag) {
+ *last = p;
+ p->next = NULL;
+ } else {
+ sasl_FREE(p);
+ }
+ }
+
+ olist = clist;
+ }
+
+ if(!olist) {
+ /* This is not going to be very useful */
+ printf ("no olist");
+ return SASL_FAIL;
+ }
+
+ for (p = olist; p; p = p->next) count++;
+
+ if(global_mech_list) {
+ sasl_FREE(global_mech_list);
+ global_mech_list = NULL;
+ }
+
+ global_mech_list = sasl_ALLOC((count + 1) * sizeof(char *));
+ if(!global_mech_list) return SASL_NOMEM;
+
+ memset(global_mech_list, 0, (count + 1) * sizeof(char *));
+
+ count = 0;
+ for (p = olist; p; p = p_next) {
+ p_next = p->next;
+
+ global_mech_list[count++] = (char *) p->d;
+
+ sasl_FREE(p);
+ }
+
+ return SASL_OK;
+}
+
+const char ** sasl_global_listmech(void)
+{
+ return (const char **)global_mech_list;
+}
+
+int sasl_listmech(sasl_conn_t *conn,
+ const char *user,
+ const char *prefix,
+ const char *sep,
+ const char *suffix,
+ const char **result,
+ unsigned *plen,
+ int *pcount)
+{
+ if(!conn) {
+ return SASL_BADPARAM;
+ } else if(conn->type == SASL_CONN_SERVER) {
+ RETURN(conn, _sasl_server_listmech(conn, user, prefix, sep, suffix,
+ result, plen, pcount));
+ } else if (conn->type == SASL_CONN_CLIENT) {
+ RETURN(conn, _sasl_client_listmech(conn, prefix, sep, suffix,
+ result, plen, pcount));
+ }
+
+ PARAMERROR(conn);
+}
+
+int _sasl_is_equal_mech(const char *req_mech,
+ const char *plug_mech,
+ size_t req_mech_len,
+ int *plus)
+{
+ size_t n;
+
+ if (req_mech_len > 5 &&
+ strcasecmp(&req_mech[req_mech_len - 5], "-PLUS") == 0) {
+ n = req_mech_len - 5;
+ *plus = 1;
+ } else {
+ n = req_mech_len;
+ *plus = 0;
+ }
+
+ if (n < strlen(plug_mech)) {
+ /* Don't allow arbitrary prefix match */
+ return 0;
+ }
+
+ return (strncasecmp(req_mech, plug_mech, n) == 0);
+}
+
+#ifndef WIN32
+static char *
+_sasl_get_default_unix_path(void *context __attribute__((unused)),
+ char * env_var_name,
+ char * default_value)
+{
+ char *path = NULL;
+
+ /* Honor external variable only in a safe environment */
+ if (getuid() == geteuid() && getgid() == getegid()) {
+ path = getenv(env_var_name);
+ }
+ if (! path) {
+ path = default_value;
+ }
+
+ return path;
+}
+
+#else /*WIN32*/
+/* Return NULL on failure */
+static char *
+_sasl_get_default_win_path(void *context __attribute__((unused)),
+ TCHAR * reg_attr_name,
+ char * default_value)
+{
+ /* Open registry entry, and find all registered SASL libraries.
+ *
+ * Registry location:
+ *
+ * SOFTWARE\\Carnegie Mellon\\Project Cyrus\\SASL Library
+ *
+ * Key - value:
+ *
+ * "SearchPath" - value: PATH like (';' delimited) list
+ * of directories where to search for plugins
+ * The list may contain references to environment
+ * variables (e.g. %PATH%).
+ *
+ */
+ HKEY hKey;
+ DWORD ret;
+ DWORD ValueType; /* value type */
+ DWORD cbData; /* value size in bytes and later number of wchars */
+ TCHAR * ValueData; /* value */
+ DWORD cbExpandedData; /* "expanded" value size in wchars */
+ TCHAR * ExpandedValueData; /* "expanded" value */
+ TCHAR * return_value; /* function return value */
+ TCHAR * tmp;
+
+ /* Initialization */
+ ExpandedValueData = NULL;
+ ValueData = NULL;
+ return_value = NULL;
+
+ /* Open the registry */
+ ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ SASL_ROOT_KEY,
+ 0,
+ KEY_READ,
+ &hKey);
+
+ if (ret != ERROR_SUCCESS) {
+ /* no registry entry */
+ char *ret;
+ (void) _sasl_strdup (default_value, &ret, NULL);
+ return ret;
+ }
+
+ /* figure out value type and required buffer size */
+ /* the size will include space for terminating NUL if required */
+ RegQueryValueEx (hKey,
+ reg_attr_name,
+ NULL, /* reserved */
+ &ValueType,
+ NULL,
+ &cbData);
+
+ /* Only accept string related types */
+ if (ValueType != REG_EXPAND_SZ &&
+ ValueType != REG_MULTI_SZ &&
+ ValueType != REG_SZ) {
+ return_value = NULL;
+ goto CLEANUP;
+ }
+
+ /* Any high water mark? */
+ ValueData = sasl_ALLOC(cbData + 2 * sizeof(TCHAR)); /* extra bytes to insert null-terminator if it's missed */
+ if (ValueData == NULL) {
+ return_value = NULL;
+ goto CLEANUP;
+ };
+
+ if (RegQueryValueEx(hKey,
+ reg_attr_name,
+ NULL, /* reserved */
+ &ValueType,
+ (LPBYTE)ValueData,
+ &cbData) != ERROR_SUCCESS) {
+ return_value = NULL;
+ goto CLEANUP;
+ }
+ cbData /= sizeof(TCHAR); /* covert to number of symbols */
+ ValueData[cbData] = '\0'; /* MS docs say we have to to that */
+ ValueData[cbData + 1] = '\0'; /* for MULTI */
+
+ switch (ValueType) {
+ case REG_EXPAND_SZ:
+ /* : A random starting guess */
+ cbExpandedData = cbData + 1024;
+ ExpandedValueData = (TCHAR*)sasl_ALLOC(cbExpandedData * sizeof(TCHAR));
+ if (ExpandedValueData == NULL) {
+ return_value = NULL;
+ goto CLEANUP;
+ };
+
+
+ cbExpandedData = ExpandEnvironmentStrings(
+ ValueData,
+ ExpandedValueData,
+ cbExpandedData);
+
+ if (cbExpandedData == 0) {
+ /* : GetLastError() contains the reason for failure */
+ return_value = NULL;
+ goto CLEANUP;
+ }
+
+ /* : Must retry expansion with the bigger buffer */
+ if (cbExpandedData > cbData + 1024) {
+ /* : Memory leak here if can't realloc */
+ ExpandedValueData = sasl_REALLOC(ExpandedValueData, cbExpandedData * sizeof(TCHAR));
+ if (ExpandedValueData == NULL) {
+ return_value = NULL;
+ goto CLEANUP;
+ };
+
+ cbExpandedData = ExpandEnvironmentStrings(
+ ValueData,
+ ExpandedValueData,
+ cbExpandedData);
+
+ /* : This should not happen */
+ if (cbExpandedData == 0) {
+ /* : GetLastError() contains the reason for failure */
+ return_value = NULL;
+ goto CLEANUP;
+ }
+ }
+
+ sasl_FREE(ValueData);
+ ValueData = ExpandedValueData;
+ /* : This is to prevent automatical freeing of this block on cleanup */
+ ExpandedValueData = NULL;
+
+ break;
+
+ case REG_MULTI_SZ:
+ tmp = ValueData;
+
+ /* : We shouldn't overflow here, as the buffer is guarantied
+ : to contain at least two consequent NULs */
+ while (1) {
+ if (tmp[0] == '\0') {
+ /* : Stop the process if we found the end of the string (two consequent NULs) */
+ if (tmp[1] == '\0') {
+ break;
+ }
+
+ /* : Replace delimiting NUL with our delimiter characted */
+ tmp[0] = PATHS_DELIMITER;
+ }
+ tmp += (_tcslen(tmp));
+ }
+ break;
+
+ case REG_SZ:
+ /* Do nothing, it is good as is */
+ break;
+
+ default:
+ return_value = NULL;
+ goto CLEANUP;
+ }
+
+ return_value = ValueData; /* just to flag we have a result */
+
+CLEANUP:
+ RegCloseKey(hKey);
+ if (ExpandedValueData != NULL) sasl_FREE(ExpandedValueData);
+ if (return_value == NULL) {
+ if (ValueData != NULL) sasl_FREE(ValueData);
+ return NULL;
+ }
+ if (sizeof(TCHAR) == sizeof(char)) {
+ return (char*)return_value;
+ }
+
+ /* convert to utf-8 for compatibility with other OS' */
+ {
+ char *tmp = _sasl_wchar_to_utf8(return_value);
+ sasl_FREE(return_value);
+ return tmp;
+ }
+}
+
+char* _sasl_wchar_to_utf8(WCHAR *str)
+{
+ size_t bufLen = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL);
+ char *buf = sasl_ALLOC(bufLen);
+ if (buf) {
+ if (WideCharToMultiByte(CP_UTF8, 0, str, -1, buf, bufLen, NULL, NULL) == 0) { /* -1 ensures null-terminated utf8 */
+ sasl_FREE(buf);
+ buf = NULL;
+ }
+ }
+ return buf;
+}
+
+WCHAR* _sasl_utf8_to_wchar(const char *str)
+{
+ size_t bufLen = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
+ WCHAR *buf = sasl_ALLOC(bufLen * sizeof(WCHAR));
+ if (buf) {
+ if (MultiByteToWideChar(CP_UTF8, 0, str, -1, buf, bufLen) == 0) { /* -1 ensures null-terminated utf8 */
+ sasl_FREE(buf);
+ buf = NULL;
+ }
+ }
+ return buf;
+}
+
+#endif /*WIN32*/
diff --git a/contrib/libs/sasl/lib/config.c b/contrib/libs/sasl/lib/config.c
new file mode 100644
index 0000000000..d1a5b973de
--- /dev/null
+++ b/contrib/libs/sasl/lib/config.c
@@ -0,0 +1,168 @@
+/* SASL Config file API
+ * Rob Siemborski
+ * Tim Martin (originally in Cyrus distribution)
+ */
+/*
+ * Copyright (c) 1998-2016 Carnegie Mellon University. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For permission or any other legal
+ * details, please contact
+ * Carnegie Mellon University
+ * Center for Technology Transfer and Enterprise Creation
+ * 4615 Forbes Avenue
+ * Suite 302
+ * Pittsburgh, PA 15213
+ * (412) 268-7393, fax: (412) 268-7395
+ * innovation@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Computing Services
+ * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "sasl.h"
+#include "saslint.h"
+
+struct configlist {
+ char *key;
+ char *value;
+};
+
+static struct configlist *configlist = NULL;
+static int nconfiglist = 0;
+
+#define CONFIGLISTGROWSIZE 100
+
+int sasl_config_init(const char *filename)
+{
+ FILE *infile;
+ int lineno = 0;
+ int alloced = 0;
+ char buf[4096];
+ char *p, *key;
+ char *tail;
+ int result;
+
+ nconfiglist=0;
+
+ infile = fopen(filename, "r");
+ if (!infile) {
+ return SASL_CONTINUE;
+ }
+
+ while (fgets(buf, sizeof(buf), infile)) {
+ lineno++;
+
+ if (buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = '\0';
+ for (p = buf; *p && isspace((int) *p); p++);
+ if (!*p || *p == '#') continue;
+
+ key = p;
+ while (*p && (isalnum((int) *p) || *p == '-' || *p == '_')) {
+ if (isupper((int) *p)) *p = (char) tolower(*p);
+ p++;
+ }
+ if (*p != ':') {
+ fclose(infile);
+ return SASL_CONFIGERR;
+ }
+ *p++ = '\0';
+
+ while (*p && isspace((int) *p)) p++;
+
+ if (!*p) {
+ fclose(infile);
+ return SASL_CONFIGERR;
+ }
+
+ /* Now strip trailing spaces, if any */
+ tail = p + strlen(p) - 1;
+ while (tail > p && isspace((int) *tail)) {
+ *tail = '\0';
+ tail--;
+ }
+
+ if (nconfiglist == alloced) {
+ alloced += CONFIGLISTGROWSIZE;
+ configlist=sasl_REALLOC((char *)configlist,
+ alloced * sizeof(struct configlist));
+ if (configlist == NULL) {
+ fclose(infile);
+ return SASL_NOMEM;
+ }
+ }
+
+ result = _sasl_strdup(key,
+ &(configlist[nconfiglist].key),
+ NULL);
+ if (result != SASL_OK) {
+ fclose(infile);
+ return result;
+ }
+ result = _sasl_strdup(p,
+ &(configlist[nconfiglist].value),
+ NULL);
+ if (result != SASL_OK) {
+ fclose(infile);
+ return result;
+ }
+
+ nconfiglist++;
+ }
+ fclose(infile);
+
+ return SASL_OK;
+}
+
+const char *sasl_config_getstring(const char *key,const char *def)
+{
+ int opt;
+
+ for (opt = 0; opt < nconfiglist; opt++) {
+ if (*key == configlist[opt].key[0] &&
+ !strcmp(key, configlist[opt].key))
+ return configlist[opt].value;
+ }
+ return def;
+}
+
+void sasl_config_done(void)
+{
+ int opt;
+
+ for (opt = 0; opt < nconfiglist; opt++) {
+ if (configlist[opt].key) sasl_FREE(configlist[opt].key);
+ if (configlist[opt].value) sasl_FREE(configlist[opt].value);
+ }
+
+ sasl_FREE(configlist);
+ configlist = NULL;
+ nconfiglist = 0;
+}
diff --git a/contrib/libs/sasl/lib/dlopen.c b/contrib/libs/sasl/lib/dlopen.c
new file mode 100644
index 0000000000..8284cd8700
--- /dev/null
+++ b/contrib/libs/sasl/lib/dlopen.c
@@ -0,0 +1,569 @@
+/* dlopen.c--Unix dlopen() dynamic loader interface
+ * Rob Siemborski
+ * Rob Earhart
+ */
+/*
+ * Copyright (c) 1998-2016 Carnegie Mellon University. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For permission or any other legal
+ * details, please contact
+ * Carnegie Mellon University
+ * Center for Technology Transfer and Enterprise Creation
+ * 4615 Forbes Avenue
+ * Suite 302
+ * Pittsburgh, PA 15213
+ * (412) 268-7393, fax: (412) 268-7395
+ * innovation@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Computing Services
+ * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+#ifdef HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdlib.h>
+#include <errno.h>
+#include <stdio.h>
+#include <limits.h>
+
+#include <sasl.h>
+#include "saslint.h"
+
+#ifndef PIC
+#include <saslplug.h>
+#include "staticopen.h"
+#endif
+
+#ifdef DO_DLOPEN
+#if HAVE_DIRENT_H
+# include <dirent.h>
+# define NAMLEN(dirent) strlen((dirent)->d_name)
+#else /* HAVE_DIRENT_H */
+# define dirent direct
+# define NAMLEN(dirent) (dirent)->d_namlen
+# if HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# if HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# if HAVE_NDIR_H
+# include <ndir.h>
+# endif
+#endif /* ! HAVE_DIRENT_H */
+
+#ifndef NAME_MAX
+# ifdef _POSIX_NAME_MAX
+# define NAME_MAX _POSIX_NAME_MAX
+# else
+# define NAME_MAX 16
+# endif
+#endif
+
+#if NAME_MAX < 8
+# define NAME_MAX 8
+#endif
+
+#ifdef __hpux
+#ifndef HAVE_DLFCN_H
+#include <dl.h>
+
+typedef shl_t * dll_handle;
+typedef void * dll_func;
+
+dll_handle
+dlopen(char *fname, int mode)
+{
+ shl_t h = shl_load(fname, BIND_DEFERRED, 0L);
+ shl_t *hp = NULL;
+
+ if (h) {
+ hp = (shl_t *)malloc(sizeof (shl_t));
+ if (!hp) {
+ shl_unload(h);
+ } else {
+ *hp = h;
+ }
+ }
+
+ return (dll_handle)hp;
+}
+
+int
+dlclose(dll_handle hp)
+{
+ shl_t h;
+
+ if (hp != NULL) {
+ h = *((shl_t *)hp);
+ free(hp);
+ return shl_unload(h);
+ } else {
+ /* Return error */
+ return -1;
+ }
+}
+
+dll_func
+dlsym(dll_handle h, char *n)
+{
+ dll_func handle;
+
+ if (shl_findsym ((shl_t *)h, n, TYPE_PROCEDURE, &handle))
+ return NULL;
+
+ return (dll_func)handle;
+}
+
+char *dlerror()
+{
+ if (errno != 0) {
+ return strerror(errno);
+ }
+ return "Generic shared library error";
+}
+
+#endif /* HAVE_DLFCN_H */
+
+#ifdef __ia64
+#define SO_SUFFIX ".so"
+#else
+#define SO_SUFFIX ".sl"
+#endif /* __ia64 */
+
+#else /* __hpux */
+#define SO_SUFFIX ".so"
+#endif
+
+#define LA_SUFFIX ".la"
+
+typedef struct lib_list
+{
+ struct lib_list *next;
+ void *library;
+} lib_list_t;
+
+static lib_list_t *lib_list_head = NULL;
+
+#endif /* DO_DLOPEN */
+
+int _sasl_locate_entry(void *library, const char *entryname,
+ void **entry_point)
+{
+#ifdef DO_DLOPEN
+/* note that we still check for known problem systems in
+ * case we are cross-compiling */
+#if defined(DLSYM_NEEDS_UNDERSCORE) || (defined(__OpenBSD__) && !defined(__ELF__))
+ char adj_entryname[1024];
+#else
+#define adj_entryname entryname
+#endif
+
+ if(!entryname) {
+ _sasl_log(NULL, SASL_LOG_ERR,
+ "no entryname in _sasl_locate_entry");
+ return SASL_BADPARAM;
+ }
+
+ if(!library) {
+ _sasl_log(NULL, SASL_LOG_ERR,
+ "no library in _sasl_locate_entry");
+ return SASL_BADPARAM;
+ }
+
+ if(!entry_point) {
+ _sasl_log(NULL, SASL_LOG_ERR,
+ "no entrypoint output pointer in _sasl_locate_entry");
+ return SASL_BADPARAM;
+ }
+
+#if defined(DLSYM_NEEDS_UNDERSCORE) || (defined(__OpenBSD__) && !defined(__ELF__))
+ snprintf(adj_entryname, sizeof adj_entryname, "_%s", entryname);
+#endif
+
+ *entry_point = NULL;
+ *entry_point = dlsym(library, adj_entryname);
+ if (*entry_point == NULL) {
+#if 0 /* This message appears to confuse people */
+ _sasl_log(NULL, SASL_LOG_DEBUG,
+ "unable to get entry point %s: %s", adj_entryname,
+ dlerror());
+#endif
+ return SASL_FAIL;
+ }
+
+ return SASL_OK;
+#else
+ return SASL_FAIL;
+#endif /* DO_DLOPEN */
+}
+
+#ifdef DO_DLOPEN
+
+static int _sasl_plugin_load(char *plugin, void *library,
+ const char *entryname,
+ int (*add_plugin)(const char *, void *))
+{
+ void *entry_point;
+ int result;
+
+ result = _sasl_locate_entry(library, entryname, &entry_point);
+ if(result == SASL_OK) {
+ result = add_plugin(plugin, entry_point);
+ if(result != SASL_OK)
+ _sasl_log(NULL, SASL_LOG_DEBUG,
+ "_sasl_plugin_load failed on %s for plugin: %s\n",
+ entryname, plugin);
+ }
+
+ return result;
+}
+
+/* this returns the file to actually open.
+ * out should be a buffer of size PATH_MAX
+ * and may be the same as in. */
+
+/* We'll use a static buffer for speed unless someone complains */
+#define MAX_LINE 2048
+
+static int _parse_la(const char *prefix, const char *in, char *out)
+{
+ FILE *file;
+ size_t length;
+ char line[MAX_LINE];
+ char *ntmp = NULL;
+
+ if(!in || !out || !prefix || out == in) return SASL_BADPARAM;
+
+ /* Set this so we can detect failure */
+ *out = '\0';
+
+ length = strlen(in);
+
+ if (strcmp(in + (length - strlen(LA_SUFFIX)), LA_SUFFIX)) {
+ if(!strcmp(in + (length - strlen(SO_SUFFIX)),SO_SUFFIX)) {
+ /* check for a .la file */
+ if (strlen(prefix) + strlen(in) + strlen(LA_SUFFIX) + 1 >= MAX_LINE)
+ return SASL_BADPARAM;
+ strcpy(line, prefix);
+ strcat(line, in);
+ length = strlen(line);
+ *(line + (length - strlen(SO_SUFFIX))) = '\0';
+ strcat(line, LA_SUFFIX);
+ file = fopen(line, "r");
+ if(file) {
+ /* We'll get it on the .la open */
+ fclose(file);
+ return SASL_FAIL;
+ }
+ }
+ if (strlen(prefix) + strlen(in) + 1 >= PATH_MAX)
+ return SASL_BADPARAM;
+ strcpy(out, prefix);
+ strcat(out, in);
+ return SASL_OK;
+ }
+
+ if (strlen(prefix) + strlen(in) + 1 >= MAX_LINE)
+ return SASL_BADPARAM;
+ strcpy(line, prefix);
+ strcat(line, in);
+
+ file = fopen(line, "r");
+ if(!file) {
+ _sasl_log(NULL, SASL_LOG_WARN,
+ "unable to open LA file: %s", line);
+ return SASL_FAIL;
+ }
+
+ while(!feof(file)) {
+ if(!fgets(line, MAX_LINE, file)) break;
+ if(line[strlen(line) - 1] != '\n') {
+ _sasl_log(NULL, SASL_LOG_WARN,
+ "LA file has too long of a line: %s", in);
+ fclose(file);
+ return SASL_BUFOVER;
+ }
+ if(line[0] == '\n' || line[0] == '#') continue;
+ if(!strncmp(line, "dlname=", sizeof("dlname=") - 1)) {
+ /* We found the line with the name in it */
+ char *end;
+ char *start;
+ size_t len;
+ end = strrchr(line, '\'');
+ if(!end) continue;
+ start = &line[sizeof("dlname=")-1];
+ len = strlen(start);
+ if(len > 3 && start[0] == '\'') {
+ ntmp=&start[1];
+ *end='\0';
+ /* Do we have dlname="" ? */
+ if(ntmp == end) {
+ _sasl_log(NULL, SASL_LOG_DEBUG,
+ "dlname is empty in .la file: %s", in);
+ fclose(file);
+ return SASL_FAIL;
+ }
+ strcpy(out, prefix);
+ strcat(out, ntmp);
+ }
+ break;
+ }
+ }
+ if(ferror(file) || feof(file)) {
+ _sasl_log(NULL, SASL_LOG_WARN,
+ "Error reading .la: %s\n", in);
+ fclose(file);
+ return SASL_FAIL;
+ }
+ fclose(file);
+
+ if(!(*out)) {
+ _sasl_log(NULL, SASL_LOG_WARN,
+ "Could not find a dlname line in .la file: %s", in);
+ return SASL_FAIL;
+ }
+
+ return SASL_OK;
+}
+#endif /* DO_DLOPEN */
+
+/* loads a plugin library */
+int _sasl_get_plugin(const char *file,
+ const sasl_callback_t *verifyfile_cb,
+ void **libraryptr)
+{
+#ifdef DO_DLOPEN
+ int r = 0;
+ int flag;
+ void *library;
+ lib_list_t *newhead;
+
+ r = ((sasl_verifyfile_t *)(verifyfile_cb->proc))
+ (verifyfile_cb->context, file, SASL_VRFY_PLUGIN);
+ if (r != SASL_OK) return r;
+
+#ifdef RTLD_NOW
+ flag = RTLD_NOW;
+#else
+ flag = 0;
+#endif
+
+ newhead = sasl_ALLOC(sizeof(lib_list_t));
+ if(!newhead) return SASL_NOMEM;
+
+ if (!(library = dlopen(file, flag))) {
+ _sasl_log(NULL, SASL_LOG_ERR,
+ "unable to dlopen %s: %s", file, dlerror());
+ sasl_FREE(newhead);
+ return SASL_FAIL;
+ }
+
+ newhead->library = library;
+ newhead->next = lib_list_head;
+ lib_list_head = newhead;
+
+ *libraryptr = library;
+ return SASL_OK;
+#else
+ return SASL_FAIL;
+#endif /* DO_DLOPEN */
+}
+
+/* gets the list of mechanisms */
+int _sasl_load_plugins(const add_plugin_list_t *entrypoints,
+ const sasl_callback_t *getpath_cb,
+ const sasl_callback_t *verifyfile_cb)
+{
+ int result;
+ const add_plugin_list_t *cur_ep;
+#ifdef DO_DLOPEN
+ char str[PATH_MAX], tmp[PATH_MAX+2], prefix[PATH_MAX+2];
+ /* 1 for '/' 1 for trailing '\0' */
+ char c;
+ int pos;
+ const char *path=NULL;
+ int position;
+ DIR *dp;
+ struct dirent *dir;
+#endif
+#ifndef PIC
+ add_plugin_t *add_plugin;
+ _sasl_plug_type type;
+ _sasl_plug_rec *p;
+#endif
+
+ if (! entrypoints
+ || ! getpath_cb
+ || getpath_cb->id != SASL_CB_GETPATH
+ || ! getpath_cb->proc
+ || ! verifyfile_cb
+ || verifyfile_cb->id != SASL_CB_VERIFYFILE
+ || ! verifyfile_cb->proc)
+ return SASL_BADPARAM;
+
+#ifndef PIC
+ /* do all the static plugins first */
+
+ for(cur_ep = entrypoints; cur_ep->entryname; cur_ep++) {
+
+ /* What type of plugin are we looking for? */
+ if(!strcmp(cur_ep->entryname, "sasl_server_plug_init")) {
+ type = SERVER;
+ add_plugin = (add_plugin_t *)sasl_server_add_plugin;
+ } else if (!strcmp(cur_ep->entryname, "sasl_client_plug_init")) {
+ type = CLIENT;
+ add_plugin = (add_plugin_t *)sasl_client_add_plugin;
+ } else if (!strcmp(cur_ep->entryname, "sasl_auxprop_plug_init")) {
+ type = AUXPROP;
+ add_plugin = (add_plugin_t *)sasl_auxprop_add_plugin;
+ } else if (!strcmp(cur_ep->entryname, "sasl_canonuser_init")) {
+ type = CANONUSER;
+ add_plugin = (add_plugin_t *)sasl_canonuser_add_plugin;
+ } else {
+ /* What are we looking for then? */
+ return SASL_FAIL;
+ }
+ for (p=_sasl_static_plugins; p->type; p++) {
+ if(type == p->type)
+ result = add_plugin(p->name, p->plug);
+ }
+ }
+#endif /* !PIC */
+
+/* only do the following if:
+ *
+ * we support dlopen()
+ * AND we are not staticly compiled
+ * OR we are staticly compiled and TRY_DLOPEN_WHEN_STATIC is defined
+ */
+#if defined(DO_DLOPEN) && (defined(PIC) || (!defined(PIC) && defined(TRY_DLOPEN_WHEN_STATIC)))
+ /* get the path to the plugins */
+ result = ((sasl_getpath_t *)(getpath_cb->proc))(getpath_cb->context,
+ &path);
+ if (result != SASL_OK) return result;
+ if (! path) return SASL_FAIL;
+
+ if (strlen(path) >= PATH_MAX) { /* no you can't buffer overrun */
+ return SASL_FAIL;
+ }
+
+ position=0;
+ do {
+ pos=0;
+ do {
+ c=path[position];
+ position++;
+ str[pos]=c;
+ pos++;
+ } while ((c!=':') && (c!='=') && (c!=0));
+ str[pos-1]='\0';
+
+ strcpy(prefix,str);
+ strcat(prefix,"/");
+
+ if ((dp=opendir(str)) !=NULL) /* ignore errors */
+ {
+ while ((dir=readdir(dp)) != NULL)
+ {
+ size_t length;
+ void *library;
+ char *c;
+ char plugname[PATH_MAX];
+ char name[PATH_MAX];
+
+ length = NAMLEN(dir);
+ if (length < 4)
+ continue; /* can not possibly be what we're looking for */
+
+ if (length + pos>=PATH_MAX) continue; /* too big */
+
+ if (strcmp(dir->d_name + (length - strlen(SO_SUFFIX)),
+ SO_SUFFIX)
+ && strcmp(dir->d_name + (length - strlen(LA_SUFFIX)),
+ LA_SUFFIX))
+ continue;
+
+ memcpy(name,dir->d_name,length);
+ name[length]='\0';
+
+ result = _parse_la(prefix, name, tmp);
+ if(result != SASL_OK)
+ continue;
+
+ /* skip "lib" and cut off suffix --
+ this only need be approximate */
+ strcpy(plugname, name + 3);
+ c = strchr(plugname, (int)'.');
+ if(c) *c = '\0';
+
+ result = _sasl_get_plugin(tmp, verifyfile_cb, &library);
+
+ if(result != SASL_OK)
+ continue;
+
+ for(cur_ep = entrypoints; cur_ep->entryname; cur_ep++) {
+ _sasl_plugin_load(plugname, library, cur_ep->entryname,
+ cur_ep->add_plugin);
+ /* If this fails, it's not the end of the world */
+ }
+ }
+
+ closedir(dp);
+ } else {
+ _sasl_log(NULL, SASL_LOG_DEBUG,
+ "looking for plugins in '%s', failed to open directory, error: %s",
+ str,
+ strerror(errno));
+ }
+
+ } while ((c!='=') && (c!=0));
+#endif /* defined(DO_DLOPEN) && (!defined(PIC) || (defined(PIC) && defined(TRY_DLOPEN_WHEN_STATIC))) */
+
+ return SASL_OK;
+}
+
+int
+_sasl_done_with_plugins(void)
+{
+#ifdef DO_DLOPEN
+ lib_list_t *libptr, *libptr_next;
+
+ for(libptr = lib_list_head; libptr; libptr = libptr_next) {
+ libptr_next = libptr->next;
+ if(libptr->library)
+ dlclose(libptr->library);
+ sasl_FREE(libptr);
+ }
+
+ lib_list_head = NULL;
+#endif /* DO_DLOPEN */
+ return SASL_OK;
+}
diff --git a/contrib/libs/sasl/lib/external.c b/contrib/libs/sasl/lib/external.c
new file mode 100644
index 0000000000..4650838bf2
--- /dev/null
+++ b/contrib/libs/sasl/lib/external.c
@@ -0,0 +1,407 @@
+/* SASL server API implementation
+ * Rob Siemborski
+ * Tim Martin
+ */
+/*
+ * Copyright (c) 1998-2016 Carnegie Mellon University. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For permission or any other legal
+ * details, please contact
+ * Carnegie Mellon University
+ * Center for Technology Transfer and Enterprise Creation
+ * 4615 Forbes Avenue
+ * Suite 302
+ * Pittsburgh, PA 15213
+ * (412) 268-7393, fax: (412) 268-7395
+ * innovation@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Computing Services
+ * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <ctype.h>
+#include <string.h>
+#include <sasl.h>
+#include <saslplug.h>
+#include "saslint.h"
+
+#include "../common/plugin_common.h"
+
+/***************************** Common Section *****************************/
+
+/***************************** Server Section *****************************/
+
+static int
+external_server_mech_new(void *glob_context __attribute__((unused)),
+ sasl_server_params_t *sparams,
+ const char *challenge __attribute__((unused)),
+ unsigned challen __attribute__((unused)),
+ void **conn_context)
+{
+ if (!conn_context
+ || !sparams
+ || !sparams->utils
+ || !sparams->utils->conn)
+ return SASL_BADPARAM;
+
+ if (!sparams->utils->conn->external.auth_id)
+ return SASL_NOMECH;
+
+ *conn_context = NULL;
+
+ return SASL_OK;
+}
+
+static int
+external_server_mech_step(void *conn_context __attribute__((unused)),
+ sasl_server_params_t *sparams,
+ const char *clientin,
+ unsigned clientinlen,
+ const char **serverout,
+ unsigned *serveroutlen,
+ sasl_out_params_t *oparams)
+{
+ int result;
+
+ if (!sparams
+ || !sparams->utils
+ || !sparams->utils->conn
+ || !sparams->utils->getcallback
+ || !serverout
+ || !serveroutlen
+ || !oparams)
+ return SASL_BADPARAM;
+
+ if (!sparams->utils->conn->external.auth_id)
+ return SASL_BADPROT;
+
+ /* xxx arbitrary limit here */
+ if (clientinlen > 16384) return SASL_BADPROT;
+
+ if ((sparams->props.security_flags & SASL_SEC_NOANONYMOUS) &&
+ (!strcmp(sparams->utils->conn->external.auth_id, "anonymous"))) {
+ sasl_seterror(sparams->utils->conn,0,"anonymous login not allowed");
+ return SASL_NOAUTHZ;
+ }
+
+ *serverout = NULL;
+ *serveroutlen = 0;
+
+ if (!clientin) {
+ /* No initial data; we're in a protocol which doesn't support it.
+ * So we let the server app know that we need some... */
+ return SASL_CONTINUE;
+ }
+
+ if (clientinlen) { /* if we have a non-zero authorization id */
+ /* The user's trying to authorize as someone they didn't
+ * authenticate as */
+ result = sparams->canon_user(sparams->utils->conn,
+ clientin, clientinlen,
+ SASL_CU_AUTHZID, oparams);
+ if(result != SASL_OK) return result;
+
+ result = sparams->canon_user(sparams->utils->conn,
+ sparams->utils->conn->external.auth_id, 0,
+ SASL_CU_AUTHID | SASL_CU_EXTERNALLY_VERIFIED, oparams);
+ } else {
+ result = sparams->canon_user(sparams->utils->conn,
+ sparams->utils->conn->external.auth_id, 0,
+ SASL_CU_AUTHID | SASL_CU_EXTERNALLY_VERIFIED | SASL_CU_AUTHZID, oparams);
+ }
+
+ if (result != SASL_OK) return result;
+
+ /* set oparams */
+ oparams->doneflag = 1;
+ oparams->mech_ssf = 0;
+ oparams->maxoutbuf = 0;
+ oparams->encode_context = NULL;
+ oparams->encode = NULL;
+ oparams->decode_context = NULL;
+ oparams->decode = NULL;
+ oparams->param_version = 0;
+
+ return SASL_OK;
+}
+
+static int
+external_server_mech_avail(void *glob_context __attribute__((unused)),
+ sasl_server_params_t *sparams,
+ void **conn_context __attribute__((unused)))
+{
+ if (!sparams->utils->conn->external.auth_id) {
+ /* Return Temporary Failure */
+ return SASL_NOTDONE;
+ }
+
+ return SASL_OK;
+}
+
+static sasl_server_plug_t external_server_plugins[] =
+{
+ {
+ "EXTERNAL", /* mech_name */
+ 0, /* max_ssf */
+ SASL_SEC_NOPLAINTEXT
+ | SASL_SEC_NOANONYMOUS
+ | SASL_SEC_NODICTIONARY, /* security_flags */
+ SASL_FEAT_WANT_CLIENT_FIRST
+ | SASL_FEAT_ALLOWS_PROXY, /* features */
+ NULL, /* glob_context */
+ &external_server_mech_new, /* mech_new */
+ &external_server_mech_step, /* mech_step */
+ NULL, /* mech_dispose */
+ NULL, /* mech_free */
+ NULL, /* setpass */
+ NULL, /* user_query */
+ NULL, /* idle */
+ &external_server_mech_avail, /* mech_avail */
+ NULL /* spare */
+ }
+};
+
+int external_server_plug_init(const sasl_utils_t *utils,
+ int max_version,
+ int *out_version,
+ sasl_server_plug_t **pluglist,
+ int *plugcount)
+{
+ if (!out_version || !pluglist || !plugcount)
+ return SASL_BADPARAM;
+
+ if (max_version != SASL_SERVER_PLUG_VERSION) {
+ SETERROR( utils, "EXTERNAL version mismatch" );
+ return SASL_BADVERS;
+ }
+
+ *out_version = SASL_SERVER_PLUG_VERSION;
+ *pluglist = external_server_plugins;
+ *plugcount = 1;
+ return SASL_OK;
+}
+
+/***************************** Client Section *****************************/
+
+typedef struct client_context
+{
+ char *out_buf;
+ size_t out_buf_len;
+} client_context_t;
+
+static int external_client_mech_new(void *glob_context __attribute__((unused)),
+ sasl_client_params_t *params,
+ void **conn_context)
+{
+ client_context_t *text;
+
+ if (!params
+ || !params->utils
+ || !params->utils->conn
+ || !conn_context)
+ return SASL_BADPARAM;
+
+ if (!params->utils->conn->external.auth_id)
+ return SASL_NOMECH;
+
+ text = sasl_ALLOC(sizeof(client_context_t));
+ if(!text) return SASL_NOMEM;
+
+ memset(text, 0, sizeof(client_context_t));
+
+ *conn_context = text;
+
+ return SASL_OK;
+}
+
+static int
+external_client_mech_step(void *conn_context,
+ sasl_client_params_t *params,
+ const char *serverin __attribute__((unused)),
+ unsigned serverinlen,
+ sasl_interact_t **prompt_need,
+ const char **clientout,
+ unsigned *clientoutlen,
+ sasl_out_params_t *oparams)
+{
+ client_context_t *text = (client_context_t *)conn_context;
+ const char *user = NULL;
+ int user_result = SASL_OK;
+ int result;
+
+ if (!params
+ || !params->utils
+ || !params->utils->conn
+ || !params->utils->getcallback
+ || !clientout
+ || !clientoutlen
+ || !oparams)
+ return SASL_BADPARAM;
+
+ if (!params->utils->conn->external.auth_id)
+ return SASL_BADPROT;
+
+ if (serverinlen != 0)
+ return SASL_BADPROT;
+
+ *clientout = NULL;
+ *clientoutlen = 0;
+
+ /* try to get the userid */
+ if (user == NULL) {
+ user_result = _plug_get_userid(params->utils, &user, prompt_need);
+
+ if ((user_result != SASL_OK) && (user_result != SASL_INTERACT))
+ return user_result;
+ }
+
+ /* free prompts we got */
+ if (prompt_need && *prompt_need) {
+ params->utils->free(*prompt_need);
+ *prompt_need = NULL;
+ }
+
+ /* if there are prompts not filled in */
+ if (user_result == SASL_INTERACT) {
+ /* make the prompt list */
+ int result =
+ _plug_make_prompts(params->utils, prompt_need,
+ "Please enter your authorization name",
+ "",
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL);
+ if (result != SASL_OK) return result;
+
+ return SASL_INTERACT;
+ }
+
+ *clientoutlen = user ? (unsigned) strlen(user) : 0;
+
+ result = _buf_alloc(&text->out_buf, &text->out_buf_len, *clientoutlen + 1);
+
+ if (result != SASL_OK) return result;
+
+ if (user && *user) {
+ result = params->canon_user(params->utils->conn,
+ user, 0, SASL_CU_AUTHZID, oparams);
+ if (result != SASL_OK) return result;
+
+ result = params->canon_user(params->utils->conn,
+ params->utils->conn->external.auth_id, 0,
+ SASL_CU_AUTHID, oparams);
+ if (result != SASL_OK) return result;
+
+ memcpy(text->out_buf, user, *clientoutlen);
+ } else {
+ result = params->canon_user(params->utils->conn,
+ params->utils->conn->external.auth_id, 0,
+ SASL_CU_AUTHID | SASL_CU_AUTHZID, oparams);
+ if (result != SASL_OK) return result;
+ }
+
+ text->out_buf[*clientoutlen] = '\0';
+
+ *clientout = text->out_buf;
+
+ /* set oparams */
+ oparams->doneflag = 1;
+ oparams->mech_ssf = 0;
+ oparams->maxoutbuf = 0;
+ oparams->encode_context = NULL;
+ oparams->encode = NULL;
+ oparams->decode_context = NULL;
+ oparams->decode = NULL;
+ oparams->param_version = 0;
+
+ return SASL_OK;
+}
+
+static void
+external_client_mech_dispose(void *conn_context,
+ const sasl_utils_t *utils __attribute__((unused)))
+{
+ client_context_t *text = (client_context_t *) conn_context;
+
+ if (!text) return;
+
+ if(text->out_buf) sasl_FREE(text->out_buf);
+
+ sasl_FREE(text);
+}
+
+static const unsigned long external_required_prompts[] = {
+ SASL_CB_LIST_END
+};
+
+static sasl_client_plug_t external_client_plugins[] =
+{
+ {
+ "EXTERNAL", /* mech_name */
+ 0, /* max_ssf */
+ SASL_SEC_NOPLAINTEXT
+ | SASL_SEC_NOANONYMOUS
+ | SASL_SEC_NODICTIONARY, /* security_flags */
+ SASL_FEAT_WANT_CLIENT_FIRST
+ | SASL_FEAT_ALLOWS_PROXY, /* features */
+ external_required_prompts, /* required_prompts */
+ NULL, /* glob_context */
+ &external_client_mech_new, /* mech_new */
+ &external_client_mech_step, /* mech_step */
+ &external_client_mech_dispose, /* mech_dispose */
+ NULL, /* mech_free */
+ NULL, /* idle */
+ NULL, /* spare */
+ NULL /* spare */
+ }
+};
+
+int external_client_plug_init(const sasl_utils_t *utils,
+ int max_version,
+ int *out_version,
+ sasl_client_plug_t **pluglist,
+ int *plugcount)
+{
+ if (!utils || !out_version || !pluglist || !plugcount)
+ return SASL_BADPARAM;
+
+ if (max_version != SASL_CLIENT_PLUG_VERSION) {
+ SETERROR( utils, "EXTERNAL version mismatch" );
+ return SASL_BADVERS;
+ }
+
+ *out_version = SASL_CLIENT_PLUG_VERSION;
+ *pluglist = external_client_plugins;
+ *plugcount = 1;
+
+ return SASL_OK;
+}
diff --git a/contrib/libs/sasl/lib/md5.c b/contrib/libs/sasl/lib/md5.c
new file mode 100644
index 0000000000..c79f4f7d77
--- /dev/null
+++ b/contrib/libs/sasl/lib/md5.c
@@ -0,0 +1,527 @@
+/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+ */
+
+/* Function names changed to avoid namespace collisions: Rob Siemborski */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+*/
+
+#include <config.h>
+#include "md5global.h"
+#include "md5.h"
+#include "hmac-md5.h"
+
+#ifndef WIN32
+# include <arpa/inet.h>
+#endif
+
+/* Constants for MD5Transform routine.
+*/
+
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+static void MD5Transform PROTO_LIST ((SASL_UINT4 [4], const unsigned char [64]));
+static void Encode PROTO_LIST
+ ((unsigned char *, SASL_UINT4 *, unsigned int));
+static void Decode PROTO_LIST
+ ((SASL_UINT4 *, const unsigned char *, unsigned int));
+static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int));
+static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int));
+
+static unsigned char PADDING[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* F, G, H and I are basic MD5 functions.
+
+ */
+#ifdef I
+/* This might be defined via NANA */
+#undef I
+#endif
+
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits.
+
+ */
+
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+Rotation is separate from addition to prevent recomputation.
+*/
+
+#define FF(a, b, c, d, x, s, ac) { (a) += F ((b), (c), (d)) + (x) + (SASL_UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }
+#define GG(a, b, c, d, x, s, ac) { (a) += G ((b), (c), (d)) + (x) + (SASL_UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }
+#define HH(a, b, c, d, x, s, ac) { (a) += H ((b), (c), (d)) + (x) + (SASL_UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }
+#define II(a, b, c, d, x, s, ac) { (a) += I ((b), (c), (d)) + (x) + (SASL_UINT4)(ac); (a) = ROTATE_LEFT ((a), (s)); (a) += (b); }
+
+/* MD5 initialization. Begins an MD5 operation, writing a new context.
+*/
+
+void _sasl_MD5Init (context)
+MD5_CTX *context; /* context */
+{
+ context->count[0] = context->count[1] = 0;
+
+ /* Load magic initialization constants. */
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xefcdab89;
+ context->state[2] = 0x98badcfe;
+ context->state[3] = 0x10325476;
+}
+
+/* MD5 block update operation. Continues an MD5 message-digest
+ operation, processing another message block, and updating the context.
+*/
+
+void _sasl_MD5Update (context, input, inputLen)
+MD5_CTX *context; /* context */
+const unsigned char *input; /* input block */
+unsigned int inputLen; /* length of input block */
+{
+ unsigned int i, index, partLen;
+
+ /* Compute number of bytes mod 64 */
+ index = (unsigned int)((context->count[0] >> 3) & 0x3F);
+
+ /* Update number of bits */
+ if ((context->count[0] += ((SASL_UINT4)inputLen << 3))
+ < ((SASL_UINT4)inputLen << 3))
+ context->count[1]++;
+ context->count[1] += ((SASL_UINT4)inputLen >> 29);
+
+ partLen = 64 - index;
+
+ /* Transform as many times as possible.
+
+*/
+ if (inputLen >= partLen) {
+ MD5_memcpy
+ ((POINTER)&context->buffer[index], (POINTER)input, partLen); MD5Transform
+ (context->state, context->buffer);
+
+ for (i = partLen; i + 63 < inputLen; i += 64)
+ MD5Transform (context->state, &input[i]);
+
+ index = 0;
+ }
+ else
+ i = 0;
+
+ /* Buffer remaining input */
+ MD5_memcpy
+ ((POINTER)&context->buffer[index], (POINTER)&input[i],
+ inputLen-i);
+
+}
+
+/* MD5 finalization. Ends an MD5 message-digest operation, writing the
+ the message digest and zeroizing the context.
+*/
+
+void _sasl_MD5Final (digest, context)
+unsigned char digest[16]; /* message digest */
+MD5_CTX *context; /* context */
+{
+ unsigned char bits[8];
+ unsigned int index, padLen;
+
+ /* Save number of bits */
+ Encode (bits, context->count, 8);
+
+ /* Pad out to 56 mod 64. */
+ index = (unsigned int)((context->count[0] >> 3) & 0x3f);
+ padLen = (index < 56) ? (56 - index) : (120 - index);
+ _sasl_MD5Update (context, PADDING, padLen);
+
+ /* Append length (before padding) */
+ _sasl_MD5Update (context, bits, 8);
+
+ /* Store state in digest */
+ Encode (digest, context->state, 16);
+
+ /* Zeroize sensitive information. */
+ MD5_memset ((POINTER)context, 0, sizeof (*context));
+}
+
+/* MD5 basic transformation. Transforms state based on block. */
+
+static void MD5Transform (state, block)
+SASL_UINT4 state[4];
+const unsigned char block[64];
+{
+ SASL_UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+ Decode (x, block, 64);
+
+ /* Round 1 */
+ FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+ FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+ FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+ FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+ FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+ FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+ FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+ FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+ FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+ FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+ FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+ FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+ FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+ FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+ FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+ FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+ GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+ GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+ GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+ GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+ GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+ GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
+ GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+ GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+ GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+ GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+ GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+ GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+ GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+ GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+ GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+ GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+ /* Round 3 */
+ HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+ HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+ HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+ HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+ HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+ HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+ HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+ HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+ HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+ HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+ HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+ HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
+ HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+ HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+ HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+ HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+ /* Round 4 */
+ II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+ II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+ II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+ II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+ II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+ II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+ II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+ II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+ II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+ II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+ II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+ II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+ II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+ II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+ II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+ II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+
+ /* Zeroize sensitive information.
+ */
+ MD5_memset ((POINTER)x, 0, sizeof (x));
+}
+
+/* Encodes input (SASL_UINT4) into output (unsigned char). Assumes len is
+ a multiple of 4.
+
+ */
+
+static void Encode (output, input, len)
+unsigned char *output;
+SASL_UINT4 *input;
+unsigned int len;
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4) {
+ output[j] = (unsigned char)(input[i] & 0xff);
+ output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
+ output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
+ output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
+ }
+}
+
+/* Decodes input (unsigned char) into output (SASL_UINT4). Assumes len is
+ a multiple of 4.
+
+ */
+
+static void Decode (output, input, len)
+SASL_UINT4 *output;
+const unsigned char *input;
+unsigned int len;
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4)
+ output[i] = ((SASL_UINT4)input[j]) | (((SASL_UINT4)input[j+1]) << 8) | (((SASL_UINT4)input[j+2]) << 16)
+ | (((SASL_UINT4)input[j+3]) << 24);
+}
+
+/* Note: Replace "for loop" with standard memcpy if possible.
+
+ */
+
+static void MD5_memcpy (output, input, len)
+POINTER output;
+POINTER input;
+unsigned int len;
+{
+ unsigned int i;
+
+ for (i = 0; i < len; i++)
+ output[i] = input[i];
+}
+
+/* Note: Replace "for loop" with standard memset if possible.
+*/
+
+static void MD5_memset (output, value, len)
+POINTER output;
+int value;
+unsigned int len;
+{
+ unsigned int i;
+
+ for (i = 0; i < len; i++)
+ ((char *)output)[i] = (char)value;
+}
+
+void _sasl_hmac_md5_init(HMAC_MD5_CTX *hmac,
+ const unsigned char *key,
+ int key_len)
+{
+ unsigned char k_ipad[65]; /* inner padding -
+ * key XORd with ipad
+ */
+ unsigned char k_opad[65]; /* outer padding -
+ * key XORd with opad
+ */
+ unsigned char tk[16];
+ int i;
+ /* if key is longer than 64 bytes reset it to key=MD5(key) */
+ if (key_len > 64) {
+
+ MD5_CTX tctx;
+
+ _sasl_MD5Init(&tctx);
+ _sasl_MD5Update(&tctx, key, key_len);
+ _sasl_MD5Final(tk, &tctx);
+
+ key = tk;
+ key_len = 16;
+ }
+
+ /*
+ * the HMAC_MD5 transform looks like:
+ *
+ * MD5(K XOR opad, MD5(K XOR ipad, text))
+ *
+ * where K is an n byte key
+ * ipad is the byte 0x36 repeated 64 times
+ * opad is the byte 0x5c repeated 64 times
+ * and text is the data being protected
+ */
+
+ /* start out by storing key in pads */
+ MD5_memset((POINTER)k_ipad, '\0', sizeof k_ipad);
+ MD5_memset((POINTER)k_opad, '\0', sizeof k_opad);
+ MD5_memcpy( k_ipad, (POINTER)key, key_len);
+ MD5_memcpy( k_opad, (POINTER)key, key_len);
+
+ /* XOR key with ipad and opad values */
+ for (i=0; i<64; i++) {
+ k_ipad[i] ^= 0x36;
+ k_opad[i] ^= 0x5c;
+ }
+
+ _sasl_MD5Init(&hmac->ictx); /* init inner context */
+ _sasl_MD5Update(&hmac->ictx, k_ipad, 64); /* apply inner pad */
+
+ _sasl_MD5Init(&hmac->octx); /* init outer context */
+ _sasl_MD5Update(&hmac->octx, k_opad, 64); /* apply outer pad */
+
+ /* scrub the pads and key context (if used) */
+ MD5_memset((POINTER)&k_ipad, 0, sizeof(k_ipad));
+ MD5_memset((POINTER)&k_opad, 0, sizeof(k_opad));
+ MD5_memset((POINTER)&tk, 0, sizeof(tk));
+
+ /* and we're done. */
+}
+
+/* The precalc and import routines here rely on the fact that we pad
+ * the key out to 64 bytes and use that to initialize the md5
+ * contexts, and that updating an md5 context with 64 bytes of data
+ * leaves nothing left over; all of the interesting state is contained
+ * in the state field, and none of it is left over in the count and
+ * buffer fields. So all we have to do is save the state field; we
+ * can zero the others when we reload it. Which is why the decision
+ * was made to pad the key out to 64 bytes in the first place. */
+void _sasl_hmac_md5_precalc(HMAC_MD5_STATE *state,
+ const unsigned char *key,
+ int key_len)
+{
+ HMAC_MD5_CTX hmac;
+ unsigned lupe;
+
+ _sasl_hmac_md5_init(&hmac, key, key_len);
+ for (lupe = 0; lupe < 4; lupe++) {
+ state->istate[lupe] = htonl(hmac.ictx.state[lupe]);
+ state->ostate[lupe] = htonl(hmac.octx.state[lupe]);
+ }
+ MD5_memset((POINTER)&hmac, 0, sizeof(hmac));
+}
+
+
+void _sasl_hmac_md5_import(HMAC_MD5_CTX *hmac,
+ HMAC_MD5_STATE *state)
+{
+ unsigned lupe;
+ MD5_memset((POINTER)hmac, 0, sizeof(HMAC_MD5_CTX));
+ for (lupe = 0; lupe < 4; lupe++) {
+ hmac->ictx.state[lupe] = ntohl(state->istate[lupe]);
+ hmac->octx.state[lupe] = ntohl(state->ostate[lupe]);
+ }
+ /* Init the counts to account for our having applied
+ * 64 bytes of key; this works out to 0x200 (64 << 3; see
+ * MD5Update above...) */
+ hmac->ictx.count[0] = hmac->octx.count[0] = 0x200;
+}
+
+void _sasl_hmac_md5_final(unsigned char digest[HMAC_MD5_SIZE],
+ HMAC_MD5_CTX *hmac)
+{
+ _sasl_MD5Final(digest, &hmac->ictx); /* Finalize inner md5 */
+ _sasl_MD5Update(&hmac->octx, digest, 16); /* Update outer ctx */
+ _sasl_MD5Final(digest, &hmac->octx); /* Finalize outer md5 */
+}
+
+
+void _sasl_hmac_md5(text, text_len, key, key_len, digest)
+const unsigned char* text; /* pointer to data stream */
+int text_len; /* length of data stream */
+const unsigned char* key; /* pointer to authentication key */
+int key_len; /* length of authentication key */
+unsigned char *digest; /* caller digest to be filled in */
+{
+ MD5_CTX context;
+
+ unsigned char k_ipad[65]; /* inner padding -
+ * key XORd with ipad
+ */
+ unsigned char k_opad[65]; /* outer padding -
+ * key XORd with opad
+ */
+ unsigned char tk[16];
+ int i;
+ /* if key is longer than 64 bytes reset it to key=MD5(key) */
+ if (key_len > 64) {
+
+ MD5_CTX tctx;
+
+ _sasl_MD5Init(&tctx);
+ _sasl_MD5Update(&tctx, key, key_len);
+ _sasl_MD5Final(tk, &tctx);
+
+ key = tk;
+ key_len = 16;
+ }
+
+ /*
+ * the HMAC_MD5 transform looks like:
+ *
+ * MD5(K XOR opad, MD5(K XOR ipad, text))
+ *
+ * where K is an n byte key
+ * ipad is the byte 0x36 repeated 64 times
+ * opad is the byte 0x5c repeated 64 times
+ * and text is the data being protected
+ */
+
+ /* start out by storing key in pads */
+ MD5_memset(k_ipad, '\0', sizeof k_ipad);
+ MD5_memset(k_opad, '\0', sizeof k_opad);
+ MD5_memcpy( k_ipad, (POINTER)key, key_len);
+ MD5_memcpy( k_opad, (POINTER)key, key_len);
+
+ /* XOR key with ipad and opad values */
+ for (i=0; i<64; i++) {
+ k_ipad[i] ^= 0x36;
+ k_opad[i] ^= 0x5c;
+ }
+ /*
+ * perform inner MD5
+ */
+
+ _sasl_MD5Init(&context); /* init context for 1st
+ * pass */
+ _sasl_MD5Update(&context, k_ipad, 64); /* start with inner pad */
+ _sasl_MD5Update(&context, text, text_len); /* then text of datagram */
+ _sasl_MD5Final(digest, &context); /* finish up 1st pass */
+
+ /*
+ * perform outer MD5
+ */
+ _sasl_MD5Init(&context); /* init context for 2nd
+ * pass */
+ _sasl_MD5Update(&context, k_opad, 64); /* start with outer pad */
+ _sasl_MD5Update(&context, digest, 16); /* then results of 1st
+ * hash */
+ _sasl_MD5Final(digest, &context); /* finish up 2nd pass */
+
+}
diff --git a/contrib/libs/sasl/lib/saslint.h b/contrib/libs/sasl/lib/saslint.h
new file mode 100644
index 0000000000..ebade78f3a
--- /dev/null
+++ b/contrib/libs/sasl/lib/saslint.h
@@ -0,0 +1,544 @@
+/* saslint.h - internal SASL library definitions
+ * Rob Siemborski
+ * Tim Martin
+ */
+/*
+ * Copyright (c) 1998-2016 Carnegie Mellon University. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For permission or any other legal
+ * details, please contact
+ * Carnegie Mellon University
+ * Center for Technology Transfer and Enterprise Creation
+ * 4615 Forbes Avenue
+ * Suite 302
+ * Pittsburgh, PA 15213
+ * (412) 268-7393, fax: (412) 268-7395
+ * innovation@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Computing Services
+ * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef SASLINT_H
+#define SASLINT_H
+
+#include <config.h>
+#include "sasl.h"
+#include "saslplug.h"
+#include "saslutil.h"
+#include "prop.h"
+
+#ifndef INLINE
+#if defined (WIN32)
+/* Visual Studio: "inline" keyword is not available in C, only in C++ */
+#define INLINE __inline
+#else
+#define INLINE inline
+#endif
+#endif
+
+/* #define'd constants */
+#define CANON_BUF_SIZE 1024
+
+/* Error Handling Foo */
+/* Helpful Hints:
+ * -Error strings are set as soon as possible (first function in stack trace
+ * with a pointer to the sasl_conn_t.
+ * -Error codes are set as late as possible (only in the sasl api functions),
+ * though "as often as possible" also comes to mind to ensure correctness
+ * -Errors from calls to _buf_alloc, _sasl_strdup, etc are assumed to be
+ * memory errors.
+ * -Only errors (error codes < SASL_OK) should be remembered
+ */
+#define RETURN(conn, val) { if(conn && (val) < SASL_OK) \
+ (conn)->error_code = (val); \
+ return (val); }
+#define MEMERROR(conn) {\
+ if(conn) sasl_seterror( (conn), 0, \
+ "Out of Memory in " __FILE__ " near line %d", __LINE__ ); \
+ RETURN(conn, SASL_NOMEM) }
+#define PARAMERROR(conn) {\
+ if(conn) sasl_seterror( (conn), SASL_NOLOG, \
+ "Parameter error in " __FILE__ " near line %d", __LINE__ ); \
+ RETURN(conn, SASL_BADPARAM) }
+#define INTERROR(conn, val) {\
+ if(conn) sasl_seterror( (conn), 0, \
+ "Internal Error %d in " __FILE__ " near line %d", (val),\
+ __LINE__ ); \
+ RETURN(conn, (val)) }
+
+#ifndef PATH_MAX
+# ifdef WIN32
+# define PATH_MAX MAX_PATH
+# else
+# ifdef _POSIX_PATH_MAX
+# define PATH_MAX _POSIX_PATH_MAX
+# else
+# define PATH_MAX 1024 /* arbitrary; probably big enough.
+ * will probably only be 256+64 on
+ * pre-posix machines */
+# endif /* _POSIX_PATH_MAX */
+# endif /* WIN32 */
+#endif
+
+/* : Define directory delimiter in SASL_PATH/SASL_CONF_PATH variables */
+#ifdef WIN32
+#define PATHS_DELIMITER ';'
+#else
+#define PATHS_DELIMITER ':'
+#endif
+
+/* A FQDN max len is 255 per RFC 1035,
+ * this means 253 chars max, we add one more for zero terminator */
+#define MAXFQDNLEN 254
+
+/* Datatype Definitions */
+typedef struct {
+ const sasl_callback_t *callbacks;
+ const char *appname;
+} sasl_global_callbacks_t;
+
+typedef struct _sasl_external_properties
+{
+ sasl_ssf_t ssf;
+ char *auth_id;
+} _sasl_external_properties_t;
+
+typedef struct sasl_string_list
+{
+ const char *d;
+ struct sasl_string_list *next;
+} sasl_string_list_t;
+
+typedef struct buffer_info
+{
+ char *data;
+ size_t curlen;
+ size_t reallen;
+} buffer_info_t;
+
+typedef int add_plugin_t(const char *, void *);
+
+typedef struct add_plugin_list
+{
+ const char *entryname;
+ add_plugin_t *add_plugin;
+} add_plugin_list_t;
+
+enum Sasl_conn_type { SASL_CONN_UNKNOWN = 0,
+ SASL_CONN_SERVER = 1,
+ SASL_CONN_CLIENT = 2 };
+
+struct sasl_conn {
+ enum Sasl_conn_type type;
+
+ void (*destroy_conn)(sasl_conn_t *); /* destroy function */
+
+ char *service;
+
+ unsigned int flags; /* flags passed to sasl_*_new */
+
+ /* IP information. A buffer of size 52 is adequate for this in its
+ longest format (see sasl.h) */
+ int got_ip_local, got_ip_remote;
+ char iplocalport[NI_MAXHOST + NI_MAXSERV];
+ char ipremoteport[NI_MAXHOST + NI_MAXSERV];
+
+ void *context;
+ sasl_out_params_t oparams;
+
+ sasl_security_properties_t props;
+ _sasl_external_properties_t external;
+
+ sasl_secret_t *secret;
+
+ int (*idle_hook)(sasl_conn_t *conn);
+ const sasl_callback_t *callbacks;
+ const sasl_global_callbacks_t *global_callbacks; /* global callbacks
+ * connection */
+ char *serverFQDN;
+
+ /* Pointers to memory that we are responsible for */
+ buffer_info_t *encode_buf;
+
+ int error_code;
+ char *error_buf, *errdetail_buf;
+ size_t error_buf_len, errdetail_buf_len;
+ char *mechlist_buf;
+ size_t mechlist_buf_len;
+
+ char *decode_buf;
+
+ char user_buf[CANON_BUF_SIZE+1], authid_buf[CANON_BUF_SIZE+1];
+
+ /* Allocated by sasl_encodev if the output contains multiple SASL packet. */
+ buffer_info_t multipacket_encoded_data;
+};
+
+/* Server Conn Type Information */
+
+typedef struct mechanism
+{
+ server_sasl_mechanism_t m;
+ struct mechanism *next;
+} mechanism_t;
+
+typedef struct mech_list {
+ const sasl_utils_t *utils; /* gotten from plug_init */
+
+ void *mutex; /* mutex for this data */
+ mechanism_t *mech_list; /* list of loaded mechanisms */
+ int mech_length; /* number of loaded mechanisms */
+} mech_list_t;
+
+typedef struct context_list
+{
+ mechanism_t *mech;
+ void *context; /* if NULL, this mech is disabled for this connection
+ * otherwise, use this context instead of a call
+ * to mech_new */
+ struct context_list *next;
+} context_list_t;
+
+typedef struct sasl_server_conn {
+ sasl_conn_t base; /* parts common to server + client */
+
+ char *appname; /* application name buffer (for sparams) */
+ char *user_realm; /* domain the user authenticating is in */
+ int sent_last; /* Have we already done the last send? */
+ int authenticated;
+ mechanism_t *mech; /* mechanism trying to use */
+ sasl_server_params_t *sparams;
+ context_list_t *mech_contexts;
+ mechanism_t *mech_list; /* list of available mechanisms */
+ int mech_length; /* number of available mechanisms */
+} sasl_server_conn_t;
+
+/* Client Conn Type Information */
+
+typedef struct cmechanism
+{
+ client_sasl_mechanism_t m;
+ struct cmechanism *next;
+} cmechanism_t;
+
+typedef struct cmech_list {
+ const sasl_utils_t *utils;
+
+ void *mutex; /* mutex for this data */
+ cmechanism_t *mech_list; /* list of mechanisms */
+ int mech_length; /* number of mechanisms */
+
+} cmech_list_t;
+
+typedef struct sasl_client_conn {
+ sasl_conn_t base; /* parts common to server + client */
+
+ cmechanism_t *mech;
+ sasl_client_params_t *cparams;
+
+ char *clientFQDN;
+
+ cmechanism_t *mech_list; /* list of available mechanisms */
+ int mech_length; /* number of available mechanisms */
+} sasl_client_conn_t;
+
+typedef struct sasl_allocation_utils {
+ sasl_malloc_t *malloc;
+ sasl_calloc_t *calloc;
+ sasl_realloc_t *realloc;
+ sasl_free_t *free;
+} sasl_allocation_utils_t;
+
+typedef struct sasl_mutex_utils {
+ sasl_mutex_alloc_t *alloc;
+ sasl_mutex_lock_t *lock;
+ sasl_mutex_unlock_t *unlock;
+ sasl_mutex_free_t *free;
+} sasl_mutex_utils_t;
+
+typedef struct sasl_log_utils_s {
+ sasl_log_t *log;
+} sasl_log_utils_t;
+
+typedef int sasl_plaintext_verifier(sasl_conn_t *conn,
+ const char *userid,
+ const char *passwd,
+ const char *service,
+ const char *user_realm);
+
+struct sasl_verify_password_s {
+ char *name;
+ sasl_plaintext_verifier *verify;
+};
+
+/*
+ * globals & constants
+ */
+/*
+ * common.c
+ */
+LIBSASL_API const sasl_utils_t *sasl_global_utils;
+
+extern int (*_sasl_client_idle_hook)(sasl_conn_t *conn);
+extern int (*_sasl_server_idle_hook)(sasl_conn_t *conn);
+
+/* These return SASL_OK if we've actually finished cleanup,
+ * SASL_NOTINIT if that part of the library isn't initialized, and
+ * SASL_CONTINUE if we need to call them again */
+extern int (*_sasl_client_cleanup_hook)(void);
+extern int (*_sasl_server_cleanup_hook)(void);
+
+extern sasl_allocation_utils_t _sasl_allocation_utils;
+extern sasl_mutex_utils_t _sasl_mutex_utils;
+extern int _sasl_allocation_locked;
+
+void sasl_common_done(void);
+
+extern int _sasl_is_equal_mech(const char *req_mech,
+ const char *plug_mech,
+ size_t req_mech_len,
+ int *plus);
+
+/*
+ * checkpw.c
+ */
+extern struct sasl_verify_password_s _sasl_verify_password[];
+
+/*
+ * server.c
+ */
+/* (this is a function call to ensure this is read-only to the outside) */
+extern int _is_sasl_server_active(void);
+
+/*
+ * Allocation and Mutex utility macros
+ */
+#define sasl_ALLOC(__size__) (_sasl_allocation_utils.malloc((__size__)))
+#define sasl_CALLOC(__nelem__, __size__) \
+ (_sasl_allocation_utils.calloc((__nelem__), (__size__)))
+#define sasl_REALLOC(__ptr__, __size__) \
+ (_sasl_allocation_utils.realloc((__ptr__), (__size__)))
+#define sasl_FREE(__ptr__) (_sasl_allocation_utils.free((__ptr__)))
+
+#define sasl_MUTEX_ALLOC() (_sasl_mutex_utils.alloc())
+#define sasl_MUTEX_LOCK(__mutex__) (_sasl_mutex_utils.lock((__mutex__)))
+#define sasl_MUTEX_UNLOCK(__mutex__) (_sasl_mutex_utils.unlock((__mutex__)))
+#define sasl_MUTEX_FREE(__mutex__) \
+ (_sasl_mutex_utils.free((__mutex__)))
+
+/* function prototypes */
+/*
+ * dlopen.c and staticopen.c
+ */
+/*
+ * The differences here are:
+ * _sasl_load_plugins loads all plugins from all files
+ * _sasl_get_plugin loads the LIBRARY for an individual file
+ * _sasl_done_with_plugins frees the LIBRARIES loaded by the above 2
+ * _sasl_locate_entry locates an entrypoint in a given library
+ */
+extern int _sasl_load_plugins(const add_plugin_list_t *entrypoints,
+ const sasl_callback_t *getpath_callback,
+ const sasl_callback_t *verifyfile_callback);
+extern int _sasl_get_plugin(const char *file,
+ const sasl_callback_t *verifyfile_cb,
+ void **libraryptr);
+extern int _sasl_locate_entry(void *library, const char *entryname,
+ void **entry_point);
+extern int _sasl_done_with_plugins();
+
+/*
+ * common.c
+ */
+extern const sasl_callback_t *
+_sasl_find_getpath_callback(const sasl_callback_t *callbacks);
+
+extern const sasl_callback_t *
+_sasl_find_getconfpath_callback(const sasl_callback_t *callbacks);
+
+extern const sasl_callback_t *
+_sasl_find_verifyfile_callback(const sasl_callback_t *callbacks);
+
+extern int _sasl_common_init(sasl_global_callbacks_t *global_callbacks);
+
+extern int _sasl_conn_init(sasl_conn_t *conn,
+ const char *service,
+ unsigned int flags,
+ enum Sasl_conn_type type,
+ int (*idle_hook)(sasl_conn_t *conn),
+ const char *serverFQDN,
+ const char *iplocalport,
+ const char *ipremoteport,
+ const sasl_callback_t *callbacks,
+ const sasl_global_callbacks_t *global_callbacks);
+extern void _sasl_conn_dispose(sasl_conn_t *conn);
+
+extern sasl_utils_t *
+_sasl_alloc_utils(sasl_conn_t *conn,
+ sasl_global_callbacks_t *global_callbacks);
+extern int _sasl_free_utils(const sasl_utils_t ** utils);
+
+extern int
+_sasl_getcallback(sasl_conn_t * conn,
+ unsigned long callbackid,
+ sasl_callback_ft * pproc,
+ void **pcontext);
+
+extern void
+_sasl_log(sasl_conn_t *conn,
+ int level,
+ const char *fmt,
+ ...);
+
+void _sasl_get_errorbuf(sasl_conn_t *conn, char ***bufhdl, size_t **lenhdl);
+int _sasl_add_string(char **out, size_t *alloclen,
+ size_t *outlen, const char *add);
+
+/* More Generic Utilities in common.c */
+extern int _sasl_strdup(const char *in, char **out, size_t *outlen);
+
+/* Basically a conditional call to realloc(), if we need more */
+int _buf_alloc(char **rwbuf, size_t *curlen, size_t newlen);
+
+/* convert an iovec to a single buffer */
+int _iovec_to_buf(const struct iovec *vec,
+ unsigned numiov, buffer_info_t **output);
+
+/* Convert between string formats and sockaddr formats */
+int _sasl_iptostring(const struct sockaddr *addr, socklen_t addrlen,
+ char *out, unsigned outlen);
+int _sasl_ipfromstring(const char *addr, struct sockaddr *out,
+ socklen_t outlen);
+
+/*
+ * external plugin (external.c)
+ */
+int external_client_plug_init(const sasl_utils_t *utils,
+ int max_version,
+ int *out_version,
+ sasl_client_plug_t **pluglist,
+ int *plugcount);
+int external_server_plug_init(const sasl_utils_t *utils,
+ int max_version,
+ int *out_version,
+ sasl_server_plug_t **pluglist,
+ int *plugcount);
+
+/* Mech Listing Functions */
+int _sasl_build_mechlist(void);
+int _sasl_server_listmech(sasl_conn_t *conn,
+ const char *user,
+ const char *prefix,
+ const char *sep,
+ const char *suffix,
+ const char **result,
+ unsigned *plen,
+ int *pcount);
+int _sasl_client_listmech(sasl_conn_t *conn,
+ const char *prefix,
+ const char *sep,
+ const char *suffix,
+ const char **result,
+ unsigned *plen,
+ int *pcount);
+/* Just create a straight list of them */
+sasl_string_list_t *_sasl_client_mechs(void);
+sasl_string_list_t *_sasl_server_mechs(void);
+
+/*
+ * config file declarations (config.c)
+ */
+extern const char *sasl_config_getstring(const char *key,const char *def);
+
+/* checkpw.c */
+#ifdef DO_SASL_CHECKAPOP
+extern int _sasl_auxprop_verify_apop(sasl_conn_t *conn,
+ const char *userstr,
+ const char *challenge,
+ const char *response,
+ const char *user_realm);
+#endif /* DO_SASL_CHECKAPOP */
+
+/* Auxprop Plugin (sasldb.c) */
+extern int sasldb_auxprop_plug_init(const sasl_utils_t *utils,
+ int max_version,
+ int *out_version,
+ sasl_auxprop_plug_t **plug,
+ const char *plugname);
+
+/*
+ * auxprop.c
+ */
+extern int _sasl_auxprop_add_plugin(void *p, void *library);
+extern void _sasl_auxprop_free(void);
+extern int _sasl_auxprop_lookup(sasl_server_params_t *sparams,
+ unsigned flags,
+ const char *user, unsigned ulen);
+
+/*
+ * canonusr.c
+ */
+void _sasl_canonuser_free();
+extern int internal_canonuser_init(const sasl_utils_t *utils,
+ int max_version,
+ int *out_version,
+ sasl_canonuser_plug_t **plug,
+ const char *plugname);
+extern int _sasl_canon_user(sasl_conn_t *conn,
+ const char *user,
+ unsigned ulen,
+ unsigned flags,
+ sasl_out_params_t *oparams);
+int _sasl_canon_user_lookup (sasl_conn_t *conn,
+ const char *user,
+ unsigned ulen,
+ unsigned flags,
+ sasl_out_params_t *oparams);
+
+/*
+ * saslutil.c
+ */
+int get_fqhostname(
+ char *name,
+ int namelen,
+ int abort_if_no_fqdn
+ );
+
+#ifndef HAVE_GETHOSTNAME
+#ifdef sun
+/* gotta define gethostname ourselves on suns */
+extern int gethostname(char *, int);
+#endif
+#endif /* HAVE_GETHOSTNAME */
+
+#ifdef WIN32
+char* _sasl_wchar_to_utf8(WCHAR *str);
+WCHAR* _sasl_utf8_to_wchar(const char *str);
+#endif
+
+#endif /* SASLINT_H */
diff --git a/contrib/libs/sasl/lib/saslutil.c b/contrib/libs/sasl/lib/saslutil.c
new file mode 100644
index 0000000000..46c628c7f5
--- /dev/null
+++ b/contrib/libs/sasl/lib/saslutil.c
@@ -0,0 +1,790 @@
+/* saslutil.c
+ * Rob Siemborski
+ * Tim Martin
+ */
+/*
+ * Copyright (c) 1998-2016 Carnegie Mellon University. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For permission or any other legal
+ * details, please contact
+ * Carnegie Mellon University
+ * Center for Technology Transfer and Enterprise Creation
+ * 4615 Forbes Avenue
+ * Suite 302
+ * Pittsburgh, PA 15213
+ * (412) 268-7393, fax: (412) 268-7395
+ * innovation@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Computing Services
+ * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if defined(WIN32)
+#define _CRT_RAND_S
+#endif
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+#include "saslint.h"
+#include <saslutil.h>
+
+/* Contains:
+ *
+ * sasl_decode64
+ * sasl_encode64
+ * sasl_mkchal
+ * sasl_utf8verify
+ * sasl_randcreate
+ * sasl_randfree
+ * sasl_randseed
+ * sasl_rand
+ * sasl_churn
+ * sasl_erasebuffer
+ */
+
+char *encode_table;
+char *decode_table;
+
+#define RPOOL_SIZE 3
+struct sasl_rand_s {
+ unsigned short pool[RPOOL_SIZE];
+ /* since the init time might be really bad let's make this lazy */
+ int initialized;
+};
+
+#define CHAR64(c) (((c) < 0 || (c) > 127) ? -1 : index_64[(c)])
+
+static char basis_64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????";
+
+static signed char index_64[128] = {
+ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
+ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
+ 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1,
+ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
+ 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
+ -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
+ 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
+};
+
+/* base64 encode
+ * in -- input data
+ * inlen -- input data length
+ * out -- output buffer (will be NUL terminated)
+ * outmax -- max size of output buffer
+ * result:
+ * outlen -- gets actual length of output buffer (optional)
+ *
+ * Returns SASL_OK on success, SASL_BUFOVER if result won't fit
+ */
+
+int sasl_encode64(const char *_in,
+ unsigned inlen,
+ char *_out,
+ unsigned outmax,
+ unsigned *outlen)
+{
+ const unsigned char *in = (const unsigned char *)_in;
+ unsigned char *out = (unsigned char *)_out;
+ unsigned char oval;
+ unsigned olen;
+
+ /* check params */
+ if ((inlen > 0) && (in == NULL)) return SASL_BADPARAM;
+
+ /* Will it fit? */
+ olen = (inlen + 2) / 3 * 4;
+ if (outlen) {
+ *outlen = olen;
+ }
+ if (outmax <= olen) {
+ return SASL_BUFOVER;
+ }
+
+ /* Do the work... */
+ while (inlen >= 3) {
+ /* user provided max buffer size; make sure we don't go over it */
+ *out++ = basis_64[in[0] >> 2];
+ *out++ = basis_64[((in[0] << 4) & 0x30) | (in[1] >> 4)];
+ *out++ = basis_64[((in[1] << 2) & 0x3c) | (in[2] >> 6)];
+ *out++ = basis_64[in[2] & 0x3f];
+ in += 3;
+ inlen -= 3;
+ }
+ if (inlen > 0) {
+ /* user provided max buffer size; make sure we don't go over it */
+ *out++ = basis_64[in[0] >> 2];
+ oval = (in[0] << 4) & 0x30;
+ if (inlen > 1) oval |= in[1] >> 4;
+ *out++ = basis_64[oval];
+ *out++ = (inlen < 2) ? '=' : basis_64[(in[1] << 2) & 0x3c];
+ *out++ = '=';
+ }
+
+ *out = '\0';
+
+ return SASL_OK;
+}
+
+/* base64 decode
+ * in -- input data
+ * inlen -- length of input data
+ * out -- output data (may be same as in, must have enough space)
+ * outmax -- max size of output buffer
+ * result:
+ * outlen -- actual output length
+ *
+ * returns:
+ * SASL_BADPROT on bad base64,
+ * SASL_BUFOVER if result won't fit,
+ * SASL_CONTINUE on a partial block,
+ * SASL_OK on success
+ */
+
+int sasl_decode64(const char *in,
+ unsigned inlen,
+ char *out,
+ unsigned outmax, /* size of the buffer, not counting the NUL */
+ unsigned *outlen)
+{
+ unsigned len = 0;
+ unsigned j;
+ int c[4];
+ int saw_equal = 0;
+
+ /* check parameters */
+ if (out == NULL) return SASL_FAIL;
+
+ if (inlen > 0 && *in == '\r') return SASL_FAIL;
+
+ while (inlen > 3) {
+ /* No data is valid after an '=' character */
+ if (saw_equal) {
+ return SASL_BADPROT;
+ }
+
+ for (j = 0; j < 4; j++) {
+ c[j] = in[0];
+ in++;
+ inlen--;
+ }
+
+ if (CHAR64(c[0]) == -1 || CHAR64(c[1]) == -1) return SASL_BADPROT;
+ if (c[2] != '=' && CHAR64(c[2]) == -1) return SASL_BADPROT;
+ if (c[3] != '=' && CHAR64(c[3]) == -1) return SASL_BADPROT;
+ /* No data is valid after a '=' character, unless it is another '=' */
+ if (c[2] == '=' && c[3] != '=') return SASL_BADPROT;
+ if (c[2] == '=' || c[3] == '=') {
+ saw_equal = 1;
+ }
+
+ *out++ = (CHAR64(c[0]) << 2) | (CHAR64(c[1]) >> 4);
+ if (++len >= outmax) return SASL_BUFOVER;
+ if (c[2] != '=') {
+ *out++ = ((CHAR64(c[1]) << 4) & 0xf0) | (CHAR64(c[2]) >> 2);
+ if (++len >= outmax) return SASL_BUFOVER;
+ if (c[3] != '=') {
+ *out++ = ((CHAR64(c[2]) << 6) & 0xc0) | CHAR64(c[3]);
+ if (++len >= outmax) return SASL_BUFOVER;
+ }
+ }
+ }
+
+ *out = '\0'; /* NUL terminate the output string */
+
+ if (outlen) *outlen = len;
+
+ if (inlen != 0) {
+ if (saw_equal) {
+ /* Unless there is CRLF at the end? */
+ return SASL_BADPROT;
+ } else {
+ return (SASL_CONTINUE);
+ }
+ }
+
+ return SASL_OK;
+}
+
+/* make a challenge string (NUL terminated)
+ * buf -- buffer for result
+ * maxlen -- max length of result
+ * hostflag -- 0 = don't include hostname, 1 = include hostname
+ * returns final length or 0 if not enough space
+ */
+
+int sasl_mkchal(sasl_conn_t *conn,
+ char *buf,
+ unsigned maxlen,
+ unsigned hostflag)
+{
+ sasl_rand_t *pool = NULL;
+ unsigned long randnum;
+ int ret;
+ time_t now;
+ unsigned len;
+
+ len = 4 /* <.>\0 */
+ + (2 * 20); /* 2 numbers, 20 => max size of 64bit
+ * ulong in base 10 */
+ if (hostflag && conn->serverFQDN)
+ len += (unsigned) strlen(conn->serverFQDN) + 1 /* for the @ */;
+
+ if (maxlen < len)
+ return 0;
+
+ ret = sasl_randcreate(&pool);
+ if(ret != SASL_OK) return 0; /* xxx sasl return code? */
+
+ sasl_rand(pool, (char *)&randnum, sizeof(randnum));
+ sasl_randfree(&pool);
+
+ time(&now);
+
+ if (hostflag && conn->serverFQDN)
+ snprintf(buf,maxlen, "<%lu.%lu@%s>", randnum, (unsigned long)now, conn->serverFQDN); /* don't care much about time 32bit overlap */
+ else
+ snprintf(buf,maxlen, "<%lu.%lu>", randnum, (unsigned long)now);
+
+ return (int) strlen(buf);
+}
+
+ /* borrowed from larry. probably works :)
+ * probably is also in acap server somewhere
+ */
+int sasl_utf8verify(const char *str, unsigned len)
+{
+ unsigned i;
+ for (i = 0; i < len; i++) {
+ /* how many octets? */
+ int seqlen = 0;
+ while (str[i] & (0x80 >> seqlen)) ++seqlen;
+ if (seqlen == 0) continue; /* this is a valid US-ASCII char */
+ if (seqlen == 1) return SASL_BADPROT; /* this shouldn't happen here */
+ if (seqlen > 6) return SASL_BADPROT; /* illegal */
+ while (--seqlen)
+ if ((str[++i] & 0xC0) != 0x80) return SASL_BADPROT; /* needed a 10 octet */
+ }
+ return SASL_OK;
+}
+
+/*
+ * To see why this is really bad see RFC 1750
+ *
+ * unfortunatly there currently is no way to make
+ * cryptographically secure pseudo random numbers
+ * without specialized hardware etc...
+ * thus, this is for nonce use only
+ */
+void getranddata(unsigned short ret[RPOOL_SIZE])
+{
+ long curtime;
+
+ memset(ret, 0, RPOOL_SIZE*sizeof(unsigned short));
+
+#ifdef DEV_RANDOM
+ {
+ int fd;
+
+ fd = open(DEV_RANDOM, O_RDONLY);
+ if(fd != -1) {
+ unsigned char *buf = (unsigned char *)ret;
+ ssize_t bytesread = 0;
+ size_t bytesleft = RPOOL_SIZE*sizeof(unsigned short);
+
+ do {
+ bytesread = read(fd, buf, bytesleft);
+ if(bytesread == -1 && errno == EINTR) continue;
+ else if(bytesread <= 0) break;
+ bytesleft -= bytesread;
+ buf += bytesread;
+ } while(bytesleft != 0);
+
+ close(fd);
+ }
+ }
+#endif
+
+#ifdef HAVE_GETPID
+ ret[0] ^= (unsigned short) getpid();
+#endif
+
+#ifdef HAVE_GETTIMEOFDAY
+ {
+ struct timeval tv;
+
+ /* xxx autoconf macro */
+#ifdef _SVID_GETTOD
+ if (!gettimeofday(&tv))
+#else
+ if (!gettimeofday(&tv, NULL))
+#endif
+ {
+ /* longs are guaranteed to be at least 32 bits; we need
+ 16 bits in each short */
+ ret[0] ^= (unsigned short) (tv.tv_sec & 0xFFFF);
+ ret[1] ^= (unsigned short) (clock() & 0xFFFF);
+ ret[1] ^= (unsigned short) (tv.tv_usec >> 16);
+ ret[2] ^= (unsigned short) (tv.tv_usec & 0xFFFF);
+ return;
+ }
+ }
+#endif /* HAVE_GETTIMEOFDAY */
+
+ /* if all else fails just use time() */
+ curtime = (long) time(NULL); /* better be at least 32 bits */
+
+ ret[0] ^= (unsigned short) (curtime >> 16);
+ ret[1] ^= (unsigned short) (curtime & 0xFFFF);
+ ret[2] ^= (unsigned short) (clock() & 0xFFFF);
+
+ return;
+}
+
+int sasl_randcreate(sasl_rand_t **rpool)
+{
+ (*rpool)=sasl_ALLOC(sizeof(sasl_rand_t));
+ if ((*rpool) == NULL) return SASL_NOMEM;
+
+ /* init is lazy */
+ (*rpool)->initialized = 0;
+
+ return SASL_OK;
+}
+
+void sasl_randfree(sasl_rand_t **rpool)
+{
+ sasl_FREE(*rpool);
+}
+
+void sasl_randseed (sasl_rand_t *rpool, const char *seed, unsigned len)
+{
+ /* is it acceptable to just use the 1st 3 char's given??? */
+ unsigned int lup;
+
+ /* check params */
+ if (seed == NULL) return;
+ if (rpool == NULL) return;
+
+ rpool->initialized = 1;
+
+ if (len > sizeof(unsigned short)*RPOOL_SIZE)
+ len = sizeof(unsigned short)*RPOOL_SIZE;
+
+ for (lup = 0; lup < len; lup += 2)
+ rpool->pool[lup/2] = (seed[lup] << 8) + seed[lup + 1];
+}
+
+static void randinit(sasl_rand_t *rpool)
+{
+ if (!rpool) return;
+
+ if (!rpool->initialized) {
+ getranddata(rpool->pool);
+ rpool->initialized = 1;
+#if !(defined(WIN32)||defined(macintosh))
+#ifndef HAVE_JRAND48
+ {
+ /* xxx varies by platform */
+ unsigned int *foo = (unsigned int *)rpool->pool;
+ srandom(*foo);
+ }
+#endif /* HAVE_JRAND48 */
+#elif defined(WIN32)
+ {
+ unsigned int *foo = (unsigned int *)rpool->pool;
+ srand(*foo);
+ }
+#endif /* WIN32 */
+ }
+
+}
+
+void sasl_rand (sasl_rand_t *rpool, char *buf, unsigned len)
+{
+ unsigned int lup;
+#if defined(WIN32) && !defined(__MINGW32__)
+ unsigned int randomValue;
+#endif
+
+ /* check params */
+ if (!rpool || !buf) return;
+
+ /* init if necessary */
+ randinit(rpool);
+
+ for (lup = 0; lup < len; lup++) {
+#if defined(__MINGW32__)
+ buf[lup] = (char) (rand() >> 8);
+#elif defined(WIN32)
+ if (rand_s(&randomValue) != 0) {
+ randomValue = rand();
+ }
+
+ buf[lup] = (char) (randomValue >> 8);
+#elif defined(macintosh)
+ buf[lup] = (char) (rand() >> 8);
+#else /* !WIN32 && !macintosh */
+#ifdef HAVE_JRAND48
+ buf[lup] = (char) (jrand48(rpool->pool) >> 8);
+#else
+ buf[lup] = (char) (random() >> 8);
+#endif /* HAVE_JRAND48 */
+#endif /* WIN32 */
+ }
+}
+
+/* this function is just a bad idea all around, since we're not trying to
+ implement a true random number generator */
+void sasl_churn (sasl_rand_t *rpool, const char *data, unsigned len)
+{
+ unsigned int lup;
+
+ /* check params */
+ if (!rpool || !data) return;
+
+ /* init if necessary */
+ randinit(rpool);
+
+ for (lup=0; lup<len; lup++)
+ rpool->pool[lup % RPOOL_SIZE] ^= data[lup];
+}
+
+void sasl_erasebuffer(char *buf, unsigned len) {
+ memset(buf, 0, len);
+}
+
+/* Lowercase string in place */
+char *sasl_strlower (
+ char *val
+)
+{
+ int i;
+
+ if (val == NULL) {
+ return (NULL);
+ }
+
+/* don't use tolower(), as it is locale dependent */
+
+ for (i = 0; val[i] != '\0'; i++) {
+ if (val[i] >= 'A' && val[i] <= 'Z') {
+ val[i] = val[i] - 'A' + 'a';
+ }
+ }
+
+ return (val);
+}
+
+/* A version of gethostname that tries hard to return a FQDN */
+int get_fqhostname(
+ char *name,
+ int namelen,
+ int abort_if_no_fqdn
+)
+{
+ int return_value;
+ struct addrinfo hints;
+ struct addrinfo *result;
+
+ return_value = gethostname (name, namelen);
+ name[namelen-1] = '\0'; /* insure string is always 0 terminated*/
+ if (return_value != 0) {
+ return (return_value);
+ }
+
+ if (strchr (name, '.') != NULL) {
+ goto LOWERCASE;
+ }
+
+/* gethostname hasn't returned a FQDN, we have to canonify it ourselves */
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_flags = AI_CANONNAME;
+ hints.ai_socktype = SOCK_STREAM; /* TCP only */
+/* A value of zero for ai_protocol indicates the caller will accept any protocol. or IPPROTO_TCP? */
+ hints.ai_protocol = 0; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
+ hints.ai_addrlen = 0;
+ hints.ai_canonname = NULL;
+ hints.ai_addr = NULL;
+ hints.ai_next = NULL;
+
+ if (getaddrinfo(name,
+ NULL, /* don't care abour service/port */
+ &hints,
+ &result) != 0) {
+ if (abort_if_no_fqdn) {
+ /* errno on Unix, WSASetLastError on Windows are already done by the function */
+ return (-1);
+ } else {
+ goto LOWERCASE;
+ }
+ }
+
+ if (result == NULL || result->ai_canonname == NULL
+ || strchr (result->ai_canonname, '.') == NULL
+ || strlen (result->ai_canonname) > namelen -1) {
+ freeaddrinfo (result);
+ if (abort_if_no_fqdn) {
+#ifdef WIN32
+ WSASetLastError (WSANO_DATA);
+#elif defined(ENODATA)
+ errno = ENODATA;
+#elif defined(EADDRNOTAVAIL)
+ errno = EADDRNOTAVAIL;
+#endif
+ return (-1);
+ } else {
+ goto LOWERCASE;
+ }
+ }
+
+ strncpy (name, result->ai_canonname, namelen);
+ name[namelen-1] = '\0'; /* insure string is always 0 terminated*/
+ freeaddrinfo (result);
+
+LOWERCASE:
+ sasl_strlower (name);
+ return (0);
+}
+
+#if defined(WIN32) && !defined(__MINGW64_VERSION_MAJOR)
+/*****************************************************************************
+ *
+ * MODULE NAME : GETOPT.C
+ *
+ * COPYRIGHTS:
+ * This module contains code made available by IBM
+ * Corporation on an AS IS basis. Any one receiving the
+ * module is considered to be licensed under IBM copyrights
+ * to use the IBM-provided source code in any way he or she
+ * deems fit, including copying it, compiling it, modifying
+ * it, and redistributing it, with or without
+ * modifications. No license under any IBM patents or
+ * patent applications is to be implied from this copyright
+ * license.
+ *
+ * A user of the module should understand that IBM cannot
+ * provide technical support for the module and will not be
+ * responsible for any consequences of use of the program.
+ *
+ * Any notices, including this one, are not to be removed
+ * from the module without the prior written consent of
+ * IBM.
+ *
+ * AUTHOR: Original author:
+ * G. R. Blair (BOBBLAIR at AUSVM1)
+ * Internet: bobblair@bobblair.austin.ibm.com
+ *
+ * Extensively revised by:
+ * John Q. Walker II, Ph.D. (JOHHQ at RALVM6)
+ * Internet: johnq@ralvm6.vnet.ibm.com
+ *
+ *****************************************************************************/
+
+/******************************************************************************
+ * getopt()
+ *
+ * The getopt() function is a command line parser. It returns the next
+ * option character in argv that matches an option character in opstring.
+ *
+ * The argv argument points to an array of argc+1 elements containing argc
+ * pointers to character strings followed by a null pointer.
+ *
+ * The opstring argument points to a string of option characters; if an
+ * option character is followed by a colon, the option is expected to have
+ * an argument that may or may not be separated from it by white space.
+ * The external variable optarg is set to point to the start of the option
+ * argument on return from getopt().
+ *
+ * The getopt() function places in optind the argv index of the next argument
+ * to be processed. The system initializes the external variable optind to
+ * 1 before the first call to getopt().
+ *
+ * When all options have been processed (that is, up to the first nonoption
+ * argument), getopt() returns EOF. The special option "--" may be used to
+ * delimit the end of the options; EOF will be returned, and "--" will be
+ * skipped.
+ *
+ * The getopt() function returns a question mark (?) when it encounters an
+ * option character not included in opstring. This error message can be
+ * disabled by setting opterr to zero. Otherwise, it returns the option
+ * character that was detected.
+ *
+ * If the special option "--" is detected, or all options have been
+ * processed, EOF is returned.
+ *
+ * Options are marked by either a minus sign (-) or a slash (/).
+ *
+ * No errors are defined.
+ *****************************************************************************/
+
+#include <string.h> /* for strchr() */
+
+/* static (global) variables that are specified as exported by getopt() */
+__declspec(dllexport) char *optarg = NULL; /* pointer to the start of the option argument */
+__declspec(dllexport) int optind = 1; /* number of the next argv[] to be evaluated */
+__declspec(dllexport) int opterr = 1; /* non-zero if a question mark should be returned */
+
+
+/* handle possible future character set concerns by putting this in a macro */
+#define _next_char(string) (char)(*(string+1))
+
+int getopt(int argc, char *argv[], char *opstring)
+{
+ static char *pIndexPosition = NULL; /* place inside current argv string */
+ char *pArgString = NULL; /* where to start from next */
+ char *pOptString; /* the string in our program */
+
+
+ if (pIndexPosition != NULL) {
+ /* we last left off inside an argv string */
+ if (*(++pIndexPosition)) {
+ /* there is more to come in the most recent argv */
+ pArgString = pIndexPosition;
+ }
+ }
+
+ if (pArgString == NULL) {
+ /* we didn't leave off in the middle of an argv string */
+ if (optind >= argc) {
+ /* more command-line arguments than the argument count */
+ pIndexPosition = NULL; /* not in the middle of anything */
+ return EOF; /* used up all command-line arguments */
+ }
+
+ /*---------------------------------------------------------------------
+ * If the next argv[] is not an option, there can be no more options.
+ *-------------------------------------------------------------------*/
+ pArgString = argv[optind++]; /* set this to the next argument ptr */
+
+ if (('/' != *pArgString) && /* doesn't start with a slash or a dash? */
+ ('-' != *pArgString)) {
+ --optind; /* point to current arg once we're done */
+ optarg = NULL; /* no argument follows the option */
+ pIndexPosition = NULL; /* not in the middle of anything */
+ return EOF; /* used up all the command-line flags */
+ }
+
+ /* check for special end-of-flags markers */
+ if ((strcmp(pArgString, "-") == 0) ||
+ (strcmp(pArgString, "--") == 0)) {
+ optarg = NULL; /* no argument follows the option */
+ pIndexPosition = NULL; /* not in the middle of anything */
+ return EOF; /* encountered the special flag */
+ }
+
+ pArgString++; /* look past the / or - */
+ }
+
+ if (':' == *pArgString) { /* is it a colon? */
+ /*---------------------------------------------------------------------
+ * Rare case: if opterr is non-zero, return a question mark;
+ * otherwise, just return the colon we're on.
+ *-------------------------------------------------------------------*/
+ return (opterr ? (int)'?' : (int)':');
+ }
+ else if ((pOptString = strchr(opstring, *pArgString)) == 0) {
+ /*---------------------------------------------------------------------
+ * The letter on the command-line wasn't any good.
+ *-------------------------------------------------------------------*/
+ optarg = NULL; /* no argument follows the option */
+ pIndexPosition = NULL; /* not in the middle of anything */
+ return (opterr ? (int)'?' : (int)*pArgString);
+ }
+ else {
+ /*---------------------------------------------------------------------
+ * The letter on the command-line matches one we expect to see
+ *-------------------------------------------------------------------*/
+ if (':' == _next_char(pOptString)) { /* is the next letter a colon? */
+ /* It is a colon. Look for an argument string. */
+ if ('\0' != _next_char(pArgString)) { /* argument in this argv? */
+ optarg = &pArgString[1]; /* Yes, it is */
+ }
+ else {
+ /*-------------------------------------------------------------
+ * The argument string must be in the next argv.
+ * But, what if there is none (bad input from the user)?
+ * In that case, return the letter, and optarg as NULL.
+ *-----------------------------------------------------------*/
+ if (optind < argc)
+ optarg = argv[optind++];
+ else {
+ optarg = NULL;
+ return (opterr ? (int)'?' : (int)*pArgString);
+ }
+ }
+ pIndexPosition = NULL; /* not in the middle of anything */
+ }
+ else {
+ /* it's not a colon, so just return the letter */
+ optarg = NULL; /* no argument follows the option */
+ pIndexPosition = pArgString; /* point to the letter we're on */
+ }
+ return (int)*pArgString; /* return the letter that matched */
+ }
+}
+
+#ifndef PASSWORD_MAX
+# define PASSWORD_MAX 255
+#endif
+
+#include <conio.h>
+char *
+getpass(prompt)
+const char *prompt;
+{
+ register char *p;
+ register int c;
+ static char pbuf[PASSWORD_MAX];
+
+ fprintf(stderr, "%s", prompt); (void) fflush(stderr);
+ for (p=pbuf; (c = _getch())!=13 && c!=EOF;) {
+ if (p < &pbuf[sizeof(pbuf)-1])
+ *p++ = (char) c;
+ }
+ *p = '\0';
+ fprintf(stderr, "\n"); (void) fflush(stderr);
+ return(pbuf);
+}
+
+
+
+#endif /* WIN32 */
diff --git a/contrib/libs/sasl/lib/server.c b/contrib/libs/sasl/lib/server.c
new file mode 100644
index 0000000000..bff461f825
--- /dev/null
+++ b/contrib/libs/sasl/lib/server.c
@@ -0,0 +1,2406 @@
+/* SASL server API implementation
+ * Rob Siemborski
+ * Tim Martin
+ */
+/*
+ * Copyright (c) 1998-2016 Carnegie Mellon University. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For permission or any other legal
+ * details, please contact
+ * Carnegie Mellon University
+ * Center for Technology Transfer and Enterprise Creation
+ * 4615 Forbes Avenue
+ * Suite 302
+ * Pittsburgh, PA 15213
+ * (412) 268-7393, fax: (412) 268-7395
+ * innovation@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Computing Services
+ * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* local functions/structs don't start with sasl
+ */
+#include <config.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#ifndef macintosh
+#include <sys/types.h>
+#include <sys/stat.h>
+#endif
+#include <fcntl.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "sasl.h"
+#include "saslint.h"
+#include "saslplug.h"
+#include "saslutil.h"
+
+#define DEFAULT_CHECKPASS_MECH "auxprop"
+
+/* Contains functions:
+ *
+ * sasl_server_init
+ * sasl_server_new
+ * sasl_listmech
+ * sasl_server_start
+ * sasl_server_step
+ * sasl_checkpass
+ * sasl_checkapop
+ * sasl_user_exists
+ * sasl_setpass
+ */
+
+/* if we've initialized the server sucessfully */
+static int _sasl_server_active = 0;
+
+/* For access by other modules */
+int _is_sasl_server_active(void) { return _sasl_server_active; }
+
+static int _sasl_checkpass(sasl_conn_t *conn,
+ const char *user, unsigned userlen,
+ const char *pass, unsigned passlen);
+
+static mech_list_t *mechlist = NULL; /* global var which holds the list */
+
+static sasl_global_callbacks_t global_callbacks;
+
+/* set the password for a user
+ * conn -- SASL connection
+ * user -- user name
+ * pass -- plaintext password, may be NULL to remove user
+ * passlen -- length of password, 0 = strlen(pass)
+ * oldpass -- NULL will sometimes work
+ * oldpasslen -- length of password, 0 = strlen(oldpass)
+ * flags -- see flags below
+ *
+ * returns:
+ * SASL_NOCHANGE -- proper entry already exists
+ * SASL_NOMECH -- no authdb supports password setting as configured
+ * SASL_NOVERIFY -- user exists, but no settable password present
+ * SASL_DISABLED -- account disabled
+ * SASL_PWLOCK -- password locked
+ * SASL_WEAKPASS -- password too weak for security policy
+ * SASL_NOUSERPASS -- user-supplied passwords not permitted
+ * SASL_FAIL -- OS error
+ * SASL_BADPARAM -- password too long
+ * SASL_OK -- successful
+ */
+
+int sasl_setpass(sasl_conn_t *conn,
+ const char *user,
+ const char *pass,
+ unsigned passlen,
+ const char *oldpass,
+ unsigned oldpasslen,
+ unsigned flags)
+{
+ int result = SASL_OK, tmpresult;
+ sasl_server_conn_t *s_conn = (sasl_server_conn_t *) conn;
+ const char *password_request[] = { SASL_AUX_PASSWORD_PROP, NULL };
+ const char *user_delete_request[] = { SASL_AUX_PASSWORD_PROP, SASL_AUX_ALL, NULL };
+ sasl_server_userdb_setpass_t *setpass_cb = NULL;
+ void *context = NULL;
+ int tried_setpass = 0;
+ int failed = 0;
+ mechanism_t *sm;
+ server_sasl_mechanism_t *m;
+ char *current_mech;
+
+ if (!_sasl_server_active || !mechlist) return SASL_NOTINIT;
+
+ /* check params */
+ if (!conn) return SASL_BADPARAM;
+ if (conn->type != SASL_CONN_SERVER) PARAMERROR(conn);
+
+ if ((!(flags & SASL_SET_DISABLE) && passlen == 0)
+ || ((flags & SASL_SET_CREATE) && (flags & SASL_SET_DISABLE)))
+ PARAMERROR(conn);
+
+ /* Check that we have an active SASL mechanism */
+ if (sasl_getprop (conn,
+ SASL_MECHNAME,
+ (const void **) &current_mech) != SASL_OK) {
+ current_mech = NULL;
+ }
+
+ if ( (flags & SASL_SET_CURMECH_ONLY) &&
+ (current_mech == NULL) ) {
+ sasl_seterror( conn, SASL_NOLOG,
+ "No current SASL mechanism available");
+ RETURN(conn, SASL_BADPARAM);
+ }
+
+ /* Do we want to store SASL_AUX_PASSWORD_PROP (plain text)? and
+ * Do we have an auxprop backend that can store properties?
+ */
+ if ((flags & SASL_SET_DISABLE || !(flags & SASL_SET_NOPLAIN)) &&
+ sasl_auxprop_store(NULL, NULL, NULL) == SASL_OK) {
+
+ tried_setpass++;
+
+ if (flags & SASL_SET_DISABLE) {
+ pass = NULL;
+ passlen = 0;
+ result = prop_request(s_conn->sparams->propctx, user_delete_request);
+ } else {
+ result = prop_request(s_conn->sparams->propctx, password_request);
+ }
+ if (result == SASL_OK) {
+ /* NOTE: When deleting users, this will work in a backward compatible way */
+ result = prop_set(s_conn->sparams->propctx, SASL_AUX_PASSWORD_PROP,
+ pass, passlen);
+ }
+ if (result == SASL_OK && flags & SASL_SET_DISABLE) {
+ result = prop_set(s_conn->sparams->propctx, SASL_AUX_ALL,
+ NULL, 0);
+ }
+ if (result == SASL_OK) {
+ result = sasl_auxprop_store(conn, s_conn->sparams->propctx, user);
+ }
+ if (result != SASL_OK) {
+ _sasl_log(conn, SASL_LOG_ERR,
+ "setpass failed for %s: %z",
+ user, result);
+ failed++;
+ } else {
+ _sasl_log(conn, SASL_LOG_NOTE,
+ "setpass succeeded for %s", user);
+ }
+ }
+
+ /* We want to preserve the current value of result, so we use tmpresult below */
+
+ /* call userdb callback function */
+ tmpresult = _sasl_getcallback(conn, SASL_CB_SERVER_USERDB_SETPASS,
+ (sasl_callback_ft *)&setpass_cb, &context);
+ if (tmpresult == SASL_OK && setpass_cb) {
+
+ tried_setpass++;
+
+ tmpresult = setpass_cb(conn, context, user, pass, passlen,
+ s_conn->sparams->propctx, flags);
+ if(tmpresult != SASL_OK) {
+ if (tmpresult == SASL_CONSTRAINT_VIOLAT) {
+ if (result == SASL_OK) {
+ result = tmpresult;
+ }
+ } else {
+ result = tmpresult;
+ }
+ _sasl_log(conn, SASL_LOG_ERR,
+ "setpass callback failed for %s: %z",
+ user, tmpresult);
+ failed++;
+ } else {
+ _sasl_log(conn, SASL_LOG_NOTE,
+ "setpass callback succeeded for %s", user);
+ }
+ }
+
+ /* now we let the mechanisms set their secrets */
+ for (sm = s_conn->mech_list; sm; sm = sm->next) {
+ m = &sm->m;
+
+ if (!m->plug->setpass) {
+ /* can't set pass for this mech */
+ continue;
+ }
+
+ /* Invoke only one setpass for the currently selected mechanism,
+ if SASL_SET_CURMECH_ONLY is specified */
+ if ((flags & SASL_SET_CURMECH_ONLY) &&
+ (strcmp(current_mech, m->plug->mech_name) != 0)) {
+ continue;
+ }
+
+ tried_setpass++;
+
+ tmpresult = m->plug->setpass(m->plug->glob_context,
+ ((sasl_server_conn_t *)conn)->sparams,
+ user,
+ pass,
+ passlen,
+ oldpass, oldpasslen,
+ flags);
+ if (tmpresult == SASL_OK) {
+ _sasl_log(conn, SASL_LOG_NOTE,
+ "%s: set secret for %s", m->plug->mech_name, user);
+
+ m->condition = SASL_OK; /* if we previously thought the
+ mechanism didn't have any user secrets
+ we now think it does */
+
+ } else if (tmpresult == SASL_NOCHANGE) {
+ _sasl_log(conn, SASL_LOG_NOTE,
+ "%s: secret not changed for %s", m->plug->mech_name, user);
+ } else if (tmpresult == SASL_CONSTRAINT_VIOLAT) {
+ _sasl_log(conn, SASL_LOG_ERR,
+ "%s: failed to set secret for %s: constrain violation",
+ m->plug->mech_name, user);
+ if (result == SASL_OK) {
+ result = tmpresult;
+ }
+ failed++;
+ } else {
+ result = tmpresult;
+ _sasl_log(conn, SASL_LOG_ERR,
+ "%s: failed to set secret for %s: %z (%m)",
+ m->plug->mech_name, user, tmpresult,
+#ifndef WIN32
+ errno
+#else
+ GetLastError()
+#endif
+ );
+ failed++;
+ }
+ }
+
+ if (!tried_setpass) {
+ _sasl_log(conn, SASL_LOG_WARN,
+ "secret not changed for %s: "
+ "no writable auxprop plugin or setpass callback found",
+ user);
+ } else if (result == SASL_CONSTRAINT_VIOLAT) {
+ /* If not all setpass failed with SASL_CONSTRAINT_VIOLAT -
+ ignore SASL_CONSTRAINT_VIOLAT */
+ if (failed < tried_setpass) {
+ result = SASL_OK;
+ }
+ }
+
+ RETURN(conn, result);
+}
+
+/* local mechanism which disposes of server */
+static void server_dispose(sasl_conn_t *pconn)
+{
+ sasl_server_conn_t *s_conn= (sasl_server_conn_t *) pconn;
+ context_list_t *cur, *cur_next;
+
+ /* Just sanity check that sasl_server_done wasn't called yet */
+ if (_sasl_server_active != 0) {
+ if (s_conn->mech) {
+ void (*mech_dispose)(void *conn_context, const sasl_utils_t *utils);
+
+ mech_dispose = s_conn->mech->m.plug->mech_dispose;
+
+ if (mech_dispose) {
+ mech_dispose(pconn->context, s_conn->sparams->utils);
+ }
+ }
+ pconn->context = NULL;
+
+ for(cur = s_conn->mech_contexts; cur; cur=cur_next) {
+ cur_next = cur->next;
+ if (cur->context) {
+ cur->mech->m.plug->mech_dispose(cur->context, s_conn->sparams->utils);
+ }
+ sasl_FREE(cur);
+ }
+ s_conn->mech_contexts = NULL;
+ }
+
+ _sasl_free_utils(&s_conn->sparams->utils);
+
+ if (s_conn->sparams->propctx) {
+ prop_dispose(&s_conn->sparams->propctx);
+ }
+
+ if (s_conn->appname) {
+ sasl_FREE(s_conn->appname);
+ }
+
+ if (s_conn->user_realm) {
+ sasl_FREE(s_conn->user_realm);
+ }
+
+ if (s_conn->sparams) {
+ sasl_FREE(s_conn->sparams);
+ }
+
+ if (s_conn->mech_list != mechlist->mech_list) {
+ /* free connection-specific mech_list */
+ mechanism_t *m, *prevm;
+
+ m = s_conn->mech_list; /* m point to beginning of the list */
+
+ while (m) {
+ prevm = m;
+ m = m->next;
+ sasl_FREE(prevm);
+ }
+ }
+
+ _sasl_conn_dispose(pconn);
+}
+
+static int init_mechlist(void)
+{
+ sasl_utils_t *newutils = NULL;
+
+ /* set util functions - need to do rest */
+ newutils = _sasl_alloc_utils(NULL, &global_callbacks);
+ if (newutils == NULL)
+ return SASL_NOMEM;
+
+ newutils->checkpass = &_sasl_checkpass;
+
+ mechlist->utils = newutils;
+ mechlist->mech_list = NULL;
+ mechlist->mech_length = 0;
+
+ return SASL_OK;
+}
+
+static int mech_compare(const sasl_server_plug_t *a,
+ const sasl_server_plug_t *b)
+{
+ unsigned sec_diff;
+ unsigned features_diff;
+
+ /* XXX the following is fairly arbitrary, but its independent
+ of the order in which the plugins are loaded
+ */
+ sec_diff = a->security_flags ^ b->security_flags;
+ if (sec_diff & a->security_flags & SASL_SEC_NOANONYMOUS) return 1;
+ if (sec_diff & b->security_flags & SASL_SEC_NOANONYMOUS) return -1;
+ if (sec_diff & a->security_flags & SASL_SEC_NOPLAINTEXT) return 1;
+ if (sec_diff & b->security_flags & SASL_SEC_NOPLAINTEXT) return -1;
+ if (sec_diff & a->security_flags & SASL_SEC_MUTUAL_AUTH) return 1;
+ if (sec_diff & b->security_flags & SASL_SEC_MUTUAL_AUTH) return -1;
+ if (sec_diff & a->security_flags & SASL_SEC_NOACTIVE) return 1;
+ if (sec_diff & b->security_flags & SASL_SEC_NOACTIVE) return -1;
+ if (sec_diff & a->security_flags & SASL_SEC_NODICTIONARY) return 1;
+ if (sec_diff & b->security_flags & SASL_SEC_NODICTIONARY) return -1;
+ if (sec_diff & a->security_flags & SASL_SEC_FORWARD_SECRECY) return 1;
+ if (sec_diff & b->security_flags & SASL_SEC_FORWARD_SECRECY) return -1;
+
+ features_diff = a->features ^ b->features;
+ if (features_diff & a->features & SASL_FEAT_CHANNEL_BINDING) return 1;
+ if (features_diff & b->features & SASL_FEAT_CHANNEL_BINDING) return -1;
+
+ if (a->max_ssf > b->max_ssf) return 1;
+ if (a->max_ssf < b->max_ssf) return -1;
+
+ if (SASL_GET_HASH_STRENGTH(a->security_flags) > SASL_GET_HASH_STRENGTH(b->security_flags)) return 1;
+ if (SASL_GET_HASH_STRENGTH(a->security_flags) < SASL_GET_HASH_STRENGTH(b->security_flags)) return -1;
+
+ return 0;
+}
+
+/*
+ * parameters:
+ * p - entry point
+ */
+int sasl_server_add_plugin(const char *plugname,
+ sasl_server_plug_init_t *p)
+{
+ int plugcount;
+ sasl_server_plug_t *pluglist = NULL;
+ sasl_server_plug_init_t *entry_point = NULL;
+ int result;
+ int version;
+ int lupe;
+
+ if(!plugname || !p) return SASL_BADPARAM;
+
+ entry_point = (sasl_server_plug_init_t *)p;
+
+ /* call into the shared library asking for information about it */
+ /* version is filled in with the version of the plugin */
+ result = entry_point(mechlist->utils, SASL_SERVER_PLUG_VERSION, &version,
+ &pluglist, &plugcount);
+
+ if ((result != SASL_OK) && (result != SASL_NOUSER)
+ && (result != SASL_CONTINUE)) {
+ _sasl_log(NULL, SASL_LOG_DEBUG,
+ "%s_client_plug_init() failed in sasl_server_add_plugin(): %z\n",
+ plugname, result);
+ return result;
+ }
+
+ /* Make sure plugin is using the same SASL version as us */
+ if (version != SASL_SERVER_PLUG_VERSION)
+ {
+ _sasl_log(NULL,
+ SASL_LOG_ERR,
+ "version mismatch on sasl_server_add_plugin for '%s': %d expected, but %d reported",
+ plugname,
+ SASL_SERVER_PLUG_VERSION,
+ version);
+ return SASL_BADVERS;
+ }
+
+ for (lupe=0;lupe < plugcount ;lupe++, pluglist++)
+ {
+ mechanism_t *mech, *mp;
+
+ mech = sasl_ALLOC(sizeof(mechanism_t));
+ if (! mech) return SASL_NOMEM;
+ memset (mech, 0, sizeof(mechanism_t));
+
+ mech->m.plug = pluglist;
+ if(_sasl_strdup(plugname, &mech->m.plugname, NULL) != SASL_OK) {
+ sasl_FREE(mech);
+ return SASL_NOMEM;
+ }
+ mech->m.version = version;
+
+ /* whether this mech actually has any users in it's db */
+ mech->m.condition = result; /* SASL_OK, SASL_CONTINUE or SASL_NOUSER */
+
+ /* mech->m.f = NULL; */
+
+ /* sort mech_list by relative "strength" */
+ mp = mechlist->mech_list;
+ if (!mp || mech_compare(pluglist, mp->m.plug) >= 0) {
+ /* add mech to head of list */
+ mech->next = mechlist->mech_list;
+ mechlist->mech_list = mech;
+ } else {
+ /* find where to insert mech into list */
+ while (mp->next &&
+ mech_compare(pluglist, mp->next->m.plug) <= 0) mp = mp->next;
+ mech->next = mp->next;
+ mp->next = mech;
+ }
+ mechlist->mech_length++;
+ }
+
+ return SASL_OK;
+}
+
+int sasl_server_done(void)
+{
+ int result = SASL_CONTINUE;
+
+ if (_sasl_server_cleanup_hook == NULL && _sasl_client_cleanup_hook == NULL) {
+ return SASL_NOTINIT;
+ }
+
+ if (_sasl_server_cleanup_hook) {
+ result = _sasl_server_cleanup_hook();
+
+ if (result == SASL_OK) {
+ _sasl_server_idle_hook = NULL;
+ _sasl_server_cleanup_hook = NULL;
+ } else {
+ return result;
+ }
+ }
+
+ if (_sasl_server_cleanup_hook || _sasl_client_cleanup_hook) {
+ return result;
+ }
+
+ sasl_common_done();
+
+ return SASL_OK;
+}
+
+static int server_done(void) {
+ mechanism_t *m;
+ mechanism_t *prevm;
+
+ if(_sasl_server_active == 0)
+ return SASL_NOTINIT;
+ else
+ _sasl_server_active--;
+
+ if(_sasl_server_active) {
+ /* Don't de-init yet! Our refcount is nonzero. */
+ return SASL_CONTINUE;
+ }
+
+ if (mechlist != NULL)
+ {
+ m=mechlist->mech_list; /* m point to beginning of the list */
+
+ while (m!=NULL)
+ {
+ prevm=m;
+ m=m->next;
+
+ if (prevm->m.plug->mech_free) {
+ prevm->m.plug->mech_free(prevm->m.plug->glob_context,
+ mechlist->utils);
+ }
+
+ sasl_FREE(prevm->m.plugname);
+ sasl_FREE(prevm);
+ }
+ _sasl_free_utils(&mechlist->utils);
+ sasl_FREE(mechlist);
+ mechlist = NULL;
+ }
+
+ /* Free the auxprop plugins */
+ _sasl_auxprop_free();
+
+ global_callbacks.callbacks = NULL;
+ global_callbacks.appname = NULL;
+
+ sasl_config_done();
+
+ return SASL_OK;
+}
+
+static int server_idle(sasl_conn_t *conn)
+{
+ sasl_server_conn_t *s_conn = NULL;
+ mechanism_t *m;
+
+ if (! mechlist) {
+ return 0;
+ }
+
+ if (!conn)
+ return 1;
+ s_conn = (sasl_server_conn_t *) conn;
+
+ for (m = s_conn->mech_list;
+ m != NULL;
+ m = m->next) {
+ if (m->m.plug->idle
+ && m->m.plug->idle(m->m.plug->glob_context,
+ conn,
+ s_conn->sparams)) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int load_config(const sasl_callback_t *verifyfile_cb)
+{
+ int result;
+ const char *path_to_config = NULL;
+ size_t path_len;
+ char *config_filename = NULL;
+ size_t len;
+ const sasl_callback_t *getconfpath_cb = NULL;
+ const char * next;
+
+ /* If appname was not provided, behave as if there is no config file
+ (see also sasl_config_init() */
+ if (global_callbacks.appname == NULL) {
+ return SASL_CONTINUE;
+ }
+
+ /* get the path to the config file */
+ getconfpath_cb = _sasl_find_getconfpath_callback( global_callbacks.callbacks );
+ if (getconfpath_cb == NULL) return SASL_BADPARAM;
+
+ /* getconfpath_cb->proc MUST be a sasl_getconfpath_t; if only C had a type
+ system */
+ result = ((sasl_getconfpath_t *)(getconfpath_cb->proc))(getconfpath_cb->context,
+ (char **) &path_to_config);
+ if (result != SASL_OK) goto done;
+ if (path_to_config == NULL) path_to_config = "";
+
+ next = path_to_config;
+
+ while (next != NULL) {
+ next = strchr(path_to_config, PATHS_DELIMITER);
+
+ /* length = length of path + '/' + length of appname + ".conf" + 1
+ for '\0' */
+
+ if (next != NULL) {
+ path_len = next - path_to_config;
+ next++; /* Skip to the next path */
+ } else {
+ path_len = strlen(path_to_config);
+ }
+
+ len = path_len + 2 + strlen(global_callbacks.appname) + 5 + 1;
+
+ if (len > PATH_MAX ) {
+ result = SASL_FAIL;
+ goto done;
+ }
+
+ /* construct the filename for the config file */
+ config_filename = sasl_ALLOC((unsigned)len);
+ if (! config_filename) {
+ result = SASL_NOMEM;
+ goto done;
+ }
+
+ snprintf(config_filename, len, "%.*s%c%s.conf", (int)path_len, path_to_config,
+ HIER_DELIMITER, global_callbacks.appname);
+
+ /* Ask the application if it's safe to use this file */
+ result = ((sasl_verifyfile_t *)(verifyfile_cb->proc))(verifyfile_cb->context,
+ config_filename, SASL_VRFY_CONF);
+
+ /* returns SASL_CONTINUE if the config file doesn't exist */
+ if (result == SASL_OK) {
+ result = sasl_config_init(config_filename);
+
+ if (result != SASL_CONTINUE) {
+ /* We are done */
+ break;
+ }
+ }
+
+ if (config_filename) {
+ sasl_FREE(config_filename);
+ config_filename = NULL;
+ }
+
+ path_to_config = next;
+ }
+
+ done:
+ if (config_filename) sasl_FREE(config_filename);
+
+ return result;
+}
+
+/*
+ * Verify that all the callbacks are valid
+ */
+static int verify_server_callbacks(const sasl_callback_t *callbacks)
+{
+ if (callbacks == NULL) return SASL_OK;
+
+ while (callbacks->id != SASL_CB_LIST_END) {
+ if (callbacks->proc==NULL) return SASL_FAIL;
+
+ callbacks++;
+ }
+
+ return SASL_OK;
+}
+
+static char *grab_field(char *line, char **eofield)
+{
+ int d = 0;
+ char *field;
+
+ while (isspace((int) *line)) line++;
+
+ /* find end of field */
+ while (line[d] && !isspace(((int) line[d]))) d++;
+ field = sasl_ALLOC(d + 1);
+ if (!field) { return NULL; }
+ memcpy(field, line, d);
+ field[d] = '\0';
+ *eofield = line + d;
+
+ return field;
+}
+
+struct secflag_map_s {
+ char *name;
+ int value;
+};
+
+struct secflag_map_s secflag_map[] = {
+ { "noplaintext", SASL_SEC_NOPLAINTEXT },
+ { "noactive", SASL_SEC_NOACTIVE },
+ { "nodictionary", SASL_SEC_NODICTIONARY },
+ { "forward_secrecy", SASL_SEC_FORWARD_SECRECY },
+ { "noanonymous", SASL_SEC_NOANONYMOUS },
+ { "pass_credentials", SASL_SEC_PASS_CREDENTIALS },
+ { "mutual_auth", SASL_SEC_MUTUAL_AUTH },
+ { NULL, 0x0 }
+};
+
+static int parse_mechlist_file(const char *mechlistfile)
+{
+ FILE *f;
+ char buf[1024];
+ char *t, *ptr;
+ int r = 0;
+
+ f = fopen(mechlistfile, "r");
+ if (!f) return SASL_FAIL;
+
+ r = SASL_OK;
+ while (fgets(buf, sizeof(buf), f) != NULL) {
+ mechanism_t *n = sasl_ALLOC(sizeof(mechanism_t));
+ sasl_server_plug_t *nplug;
+
+ if (n == NULL) { r = SASL_NOMEM; break; }
+ n->m.version = SASL_SERVER_PLUG_VERSION;
+ n->m.condition = SASL_CONTINUE;
+ nplug = sasl_ALLOC(sizeof(sasl_server_plug_t));
+ if (nplug == NULL) { r = SASL_NOMEM; break; }
+ memset(nplug, 0, sizeof(sasl_server_plug_t));
+
+ /* each line is:
+ plugin-file WS mech_name WS max_ssf *(WS security_flag) RET
+ */
+
+ /* grab file */
+ n->m.f = grab_field(buf, &ptr);
+
+ /* grab mech_name */
+ nplug->mech_name = grab_field(ptr, &ptr);
+
+ /* grab max_ssf */
+ nplug->max_ssf = strtol(ptr, &ptr, 10);
+
+ /* grab security flags */
+ while (*ptr != '\n') {
+ struct secflag_map_s *map;
+
+ /* read security flag */
+ t = grab_field(ptr, &ptr);
+ map = secflag_map;
+ while (map->name) {
+ if (!strcasecmp(t, map->name)) {
+ nplug->security_flags |= map->value;
+ break;
+ }
+ map++;
+ }
+ if (!map->name) {
+ _sasl_log(NULL, SASL_LOG_ERR,
+ "%s: couldn't identify flag '%s'",
+ nplug->mech_name, t);
+ }
+ free(t);
+ }
+
+ /* insert mechanism into mechlist */
+ n->m.plug = nplug;
+ n->next = mechlist->mech_list;
+ mechlist->mech_list = n;
+ mechlist->mech_length++;
+ }
+
+ fclose(f);
+ return r;
+}
+
+/* initialize server drivers, done once per process
+ * callbacks -- callbacks for all server connections; must include
+ * getopt callback
+ * appname -- name of calling application
+ * (for lower level logging and reading of the configuration file)
+ * results:
+ * state -- server state
+ * returns:
+ * SASL_OK -- success
+ * SASL_BADPARAM -- error in config file
+ * SASL_NOMEM -- memory failure
+ * SASL_BADVERS -- Mechanism version mismatch
+ */
+
+int sasl_server_init(const sasl_callback_t *callbacks,
+ const char *appname)
+{
+ int ret;
+ const sasl_callback_t *vf;
+ const char *pluginfile = NULL;
+#ifdef PIC
+ sasl_getopt_t *getopt;
+ void *context;
+#endif
+
+ const add_plugin_list_t ep_list[] = {
+ { "sasl_server_plug_init", (add_plugin_t *)sasl_server_add_plugin },
+ { "sasl_auxprop_plug_init", (add_plugin_t *)sasl_auxprop_add_plugin },
+ { "sasl_canonuser_init", (add_plugin_t *)sasl_canonuser_add_plugin },
+ { NULL, NULL }
+ };
+
+ /* lock allocation type */
+ _sasl_allocation_locked++;
+
+ /* we require the appname (if present) to be short enough to be a path */
+ if (appname != NULL && strlen(appname) >= PATH_MAX)
+ return SASL_BADPARAM;
+
+ if (_sasl_server_active) {
+ /* We're already active, just increase our refcount */
+ /* xxx do something with the callback structure? */
+ _sasl_server_active++;
+ return SASL_OK;
+ }
+
+ ret = _sasl_common_init(&global_callbacks);
+ if (ret != SASL_OK)
+ return ret;
+
+ /* verify that the callbacks look ok */
+ ret = verify_server_callbacks(callbacks);
+ if (ret != SASL_OK)
+ return ret;
+
+ global_callbacks.callbacks = callbacks;
+
+ /* A shared library calling sasl_server_init will pass NULL as appname.
+ This should retain the original appname. */
+ if (appname != NULL) {
+ global_callbacks.appname = appname;
+ }
+
+ /* If we fail now, we have to call server_done */
+ _sasl_server_active = 1;
+
+ /* allocate mechlist and set it to empty */
+ mechlist = sasl_ALLOC(sizeof(mech_list_t));
+ if (mechlist == NULL) {
+ server_done();
+ return SASL_NOMEM;
+ }
+
+ ret = init_mechlist();
+ if (ret != SASL_OK) {
+ server_done();
+ return ret;
+ }
+
+ vf = _sasl_find_verifyfile_callback(callbacks);
+
+ /* load config file if applicable */
+ ret = load_config(vf);
+ if ((ret != SASL_OK) && (ret != SASL_CONTINUE)) {
+ server_done();
+ return ret;
+ }
+
+ /* load internal plugins */
+ sasl_server_add_plugin("EXTERNAL", &external_server_plug_init);
+
+#ifdef PIC
+ /* delayed loading of plugins? (DSO only, as it doesn't
+ * make much [any] sense to delay in the static library case) */
+ if (_sasl_getcallback(NULL, SASL_CB_GETOPT, (sasl_callback_ft *)&getopt, &context)
+ == SASL_OK) {
+ /* No sasl_conn_t was given to getcallback, so we provide the
+ * global callbacks structure */
+ ret = getopt(&global_callbacks, NULL, "plugin_list", &pluginfile, NULL);
+ }
+#endif
+
+ if (pluginfile != NULL) {
+ /* this file should contain a list of plugins available.
+ we'll load on demand. */
+
+ /* Ask the application if it's safe to use this file */
+ ret = ((sasl_verifyfile_t *)(vf->proc))(vf->context,
+ pluginfile,
+ SASL_VRFY_CONF);
+ if (ret != SASL_OK) {
+ _sasl_log(NULL, SASL_LOG_ERR,
+ "unable to load plugin list %s: %z", pluginfile, ret);
+ }
+
+ if (ret == SASL_OK) {
+ ret = parse_mechlist_file(pluginfile);
+ }
+ } else {
+ /* load all plugins now */
+ ret = _sasl_load_plugins(ep_list,
+ _sasl_find_getpath_callback(callbacks),
+ _sasl_find_verifyfile_callback(callbacks));
+ }
+
+ if (ret == SASL_OK) {
+ _sasl_server_cleanup_hook = &server_done;
+ _sasl_server_idle_hook = &server_idle;
+
+ ret = _sasl_build_mechlist();
+ } else {
+ server_done();
+ }
+
+ return ret;
+}
+
+/*
+ * Once we have the users plaintext password we
+ * may want to transition them. That is put entries
+ * for them in the passwd database for other
+ * stronger mechanism
+ *
+ * for example PLAIN -> CRAM-MD5
+ */
+static int
+_sasl_transition(sasl_conn_t * conn,
+ const char * pass,
+ unsigned passlen)
+{
+ const char *dotrans = "n";
+ sasl_getopt_t *getopt;
+ int result = SASL_OK;
+ void *context;
+ unsigned flags = 0;
+
+ if (! conn)
+ return SASL_BADPARAM;
+
+ if (! conn->oparams.authid)
+ PARAMERROR(conn);
+
+ /* check if this is enabled: default to false */
+ if (_sasl_getcallback(conn, SASL_CB_GETOPT, (sasl_callback_ft *)&getopt, &context) == SASL_OK)
+ {
+ getopt(context, NULL, "auto_transition", &dotrans, NULL);
+ if (dotrans == NULL) dotrans = "n";
+ }
+
+
+ if (!strcmp(dotrans, "noplain")) flags |= SASL_SET_NOPLAIN;
+
+ if (flags || *dotrans == '1' || *dotrans == 'y' ||
+ (*dotrans == 'o' && dotrans[1] == 'n') || *dotrans == 't') {
+ /* ok, it's on! */
+ _sasl_log(conn, SASL_LOG_NOTE,
+ "transitioning user %s to auxprop database",
+ conn->oparams.authid);
+ result = sasl_setpass(conn,
+ conn->oparams.authid,
+ pass,
+ passlen,
+ NULL, 0, SASL_SET_CREATE | flags);
+ }
+
+ RETURN(conn,result);
+}
+
+
+/* create context for a single SASL connection
+ * service -- registered name of the service using SASL (e.g. "imap")
+ * serverFQDN -- Fully qualified domain name of server. NULL means use
+ * gethostname() or equivalent.
+ * Useful for multi-homed servers.
+ * user_realm -- permits multiple user realms on server, NULL = default
+ * iplocalport -- server IPv4/IPv6 domain literal string with port
+ * (if NULL, then mechanisms requiring IPaddr are disabled)
+ * ipremoteport -- client IPv4/IPv6 domain literal string with port
+ * (if NULL, then mechanisms requiring IPaddr are disabled)
+ * callbacks -- callbacks (e.g., authorization, lang, new getopt context)
+ * flags -- usage flags (see above)
+ * returns:
+ * pconn -- new connection context
+ *
+ * returns:
+ * SASL_OK -- success
+ * SASL_NOMEM -- not enough memory
+ */
+
+int sasl_server_new(const char *service,
+ const char *serverFQDN,
+ const char *user_realm,
+ const char *iplocalport,
+ const char *ipremoteport,
+ const sasl_callback_t *callbacks,
+ unsigned flags,
+ sasl_conn_t **pconn)
+{
+ int result;
+ sasl_server_conn_t *serverconn;
+ sasl_utils_t *utils;
+ sasl_getopt_t *getopt;
+ void *context;
+ const char *log_level, *auto_trans;
+ const char *mlist = NULL;
+ int plus = 0;
+
+ if (_sasl_server_active==0) return SASL_NOTINIT;
+ if (! pconn) return SASL_FAIL;
+ if (! service) return SASL_FAIL;
+
+ *pconn=sasl_ALLOC(sizeof(sasl_server_conn_t));
+ if (*pconn==NULL) return SASL_NOMEM;
+
+ memset(*pconn, 0, sizeof(sasl_server_conn_t));
+
+ serverconn = (sasl_server_conn_t *)*pconn;
+
+ /* make sparams */
+ serverconn->sparams=sasl_ALLOC(sizeof(sasl_server_params_t));
+ if (serverconn->sparams==NULL)
+ MEMERROR(*pconn);
+
+ memset(serverconn->sparams, 0, sizeof(sasl_server_params_t));
+
+ (*pconn)->destroy_conn = &server_dispose;
+ result = _sasl_conn_init(*pconn, service, flags, SASL_CONN_SERVER,
+ &server_idle, serverFQDN,
+ iplocalport, ipremoteport,
+ callbacks, &global_callbacks);
+ if (result != SASL_OK)
+ goto done_error;
+
+
+ /* set util functions - need to do rest */
+ utils=_sasl_alloc_utils(*pconn, &global_callbacks);
+ if (!utils) {
+ result = SASL_NOMEM;
+ goto done_error;
+ }
+
+ utils->checkpass = &_sasl_checkpass;
+
+ /* Setup the propctx -> We'll assume the default size */
+ serverconn->sparams->propctx=prop_new(0);
+ if(!serverconn->sparams->propctx) {
+ result = SASL_NOMEM;
+ goto done_error;
+ }
+
+ serverconn->sparams->service = (*pconn)->service;
+ serverconn->sparams->servicelen = (unsigned) strlen((*pconn)->service);
+
+ if (global_callbacks.appname && global_callbacks.appname[0] != '\0') {
+ result = _sasl_strdup (global_callbacks.appname,
+ &serverconn->appname,
+ NULL);
+ if (result != SASL_OK) {
+ result = SASL_NOMEM;
+ goto done_error;
+ }
+ serverconn->sparams->appname = serverconn->appname;
+ serverconn->sparams->applen = (unsigned) strlen(serverconn->sparams->appname);
+ } else {
+ serverconn->appname = NULL;
+ serverconn->sparams->appname = NULL;
+ serverconn->sparams->applen = 0;
+ }
+
+ serverconn->sparams->serverFQDN = (*pconn)->serverFQDN;
+ serverconn->sparams->slen = (unsigned) strlen((*pconn)->serverFQDN);
+
+ if (user_realm) {
+ result = _sasl_strdup(user_realm, &serverconn->user_realm, NULL);
+ serverconn->sparams->urlen = (unsigned) strlen(user_realm);
+ serverconn->sparams->user_realm = serverconn->user_realm;
+ } else {
+ serverconn->user_realm = NULL;
+ /* the sparams is already zeroed */
+ }
+
+ serverconn->sparams->callbacks = callbacks;
+
+ log_level = auto_trans = NULL;
+ if(_sasl_getcallback(*pconn, SASL_CB_GETOPT, (sasl_callback_ft *)&getopt, &context) == SASL_OK) {
+ getopt(context, NULL, "log_level", &log_level, NULL);
+ getopt(context, NULL, "auto_transition", &auto_trans, NULL);
+ getopt(context, NULL, "mech_list", &mlist, NULL);
+ }
+ serverconn->sparams->log_level = log_level ? atoi(log_level) : SASL_LOG_ERR;
+
+ serverconn->sparams->utils = utils;
+
+ if (auto_trans &&
+ (*auto_trans == '1' || *auto_trans == 'y' || *auto_trans == 't' ||
+ (*auto_trans == 'o' && auto_trans[1] == 'n') ||
+ !strcmp(auto_trans, "noplain")) &&
+ sasl_auxprop_store(NULL, NULL, NULL) == SASL_OK) {
+ serverconn->sparams->transition = &_sasl_transition;
+ }
+
+ /* if we have a mech_list, create ordered list of avail mechs for this conn */
+ if (mlist) {
+ const char *cp;
+ mechanism_t *mptr, *tail = NULL;
+
+ while (*mlist) {
+ /* find end of current mech name */
+ for (cp = mlist; *cp && !isspace((int) *cp); cp++);
+
+ /* search for mech name in loaded plugins */
+ for (mptr = mechlist->mech_list; mptr; mptr = mptr->next) {
+ const sasl_server_plug_t *plug = mptr->m.plug;
+
+ if (_sasl_is_equal_mech(mlist, plug->mech_name, (size_t) (cp - mlist), &plus)) {
+ /* found a match */
+ break;
+ }
+ }
+ if (mptr) {
+ mechanism_t *new = sasl_ALLOC(sizeof(mechanism_t));
+ if (!new) return SASL_NOMEM;
+
+ memcpy(&new->m, &mptr->m, sizeof(server_sasl_mechanism_t));
+ new->next = NULL;
+
+ if (!serverconn->mech_list) {
+ serverconn->mech_list = new;
+ tail = serverconn->mech_list;
+ }
+ else {
+ if (tail)
+ tail->next = new;
+ tail = new;
+ }
+ serverconn->mech_length++;
+ }
+
+ /* find next mech name */
+ mlist = cp;
+ while (*mlist && isspace((int) *mlist)) mlist++;
+ }
+ }
+ else {
+ serverconn->mech_list = mechlist->mech_list;
+ serverconn->mech_length = mechlist->mech_length;
+ }
+
+ serverconn->sparams->canon_user = &_sasl_canon_user_lookup;
+ serverconn->sparams->props = serverconn->base.props;
+ serverconn->sparams->flags = flags;
+
+ if(result == SASL_OK) return SASL_OK;
+
+ done_error:
+ _sasl_conn_dispose(*pconn);
+ sasl_FREE(*pconn);
+ *pconn = NULL;
+ return result;
+}
+
+/*
+ * The rule is:
+ * IF mech strength + external strength < min ssf THEN FAIL.
+ * We also have to look at the security properties and make sure
+ * that this mechanism has everything we want.
+ */
+static int mech_permitted(sasl_conn_t *conn,
+ mechanism_t *mech)
+{
+ sasl_server_conn_t *s_conn = (sasl_server_conn_t *)conn;
+ const sasl_server_plug_t *plug;
+ int ret;
+ int myflags;
+ context_list_t *cur;
+ context_list_t *mech_context_list_entry = NULL;
+ void *context = NULL;
+ sasl_ssf_t minssf = 0;
+
+ if(!conn) return SASL_NOMECH;
+
+ if(! mech || ! mech->m.plug) {
+ PARAMERROR(conn);
+ return SASL_NOMECH;
+ }
+
+ plug = mech->m.plug;
+
+ /* setup parameters for the call to mech_avail */
+ s_conn->sparams->serverFQDN=conn->serverFQDN;
+ s_conn->sparams->service=conn->service;
+ s_conn->sparams->user_realm=s_conn->user_realm;
+ s_conn->sparams->props=conn->props;
+ s_conn->sparams->external_ssf=conn->external.ssf;
+
+ /* Check if we have banished this one already */
+ for (cur = s_conn->mech_contexts; cur; cur=cur->next) {
+ if (cur->mech == mech) {
+ /* If it's not mech_avail'd, then stop now */
+ if (!cur->context) {
+ return SASL_NOMECH;
+ } else {
+ context = cur->context;
+ mech_context_list_entry = cur;
+ }
+ break;
+ }
+ }
+
+ if (conn->props.min_ssf < conn->external.ssf) {
+ minssf = 0;
+ } else {
+ minssf = conn->props.min_ssf - conn->external.ssf;
+ }
+
+ /* Generic mechanism */
+ if (plug->max_ssf < minssf) {
+ sasl_seterror(conn, SASL_NOLOG,
+ "mech %s is too weak", plug->mech_name);
+ return SASL_TOOWEAK; /* too weak */
+ }
+
+ if (plug->mech_avail
+ && (ret = plug->mech_avail(plug->glob_context,
+ s_conn->sparams,
+ (void **)&context)) != SASL_OK ) {
+ if (ret == SASL_NOMECH) {
+ /* Mark this mech as no good for this connection */
+ cur = sasl_ALLOC(sizeof(context_list_t));
+ if (!cur) {
+ MEMERROR(conn);
+ return SASL_NOMECH;
+ }
+ cur->context = NULL;
+ cur->mech = mech;
+ cur->next = s_conn->mech_contexts;
+ s_conn->mech_contexts = cur;
+ }
+
+ /* SASL_NOTDONE might also get us here */
+
+ /* Error should be set by mech_avail call */
+ return SASL_NOMECH;
+ } else if (context) {
+ if (mech_context_list_entry != NULL) {
+ /* Update the context. It shouldn't have changed, but who knows */
+ mech_context_list_entry->context = context;
+ } else {
+ /* Save this context */
+ cur = sasl_ALLOC(sizeof(context_list_t));
+ if (!cur) {
+ MEMERROR(conn);
+ return SASL_NOMECH;
+ }
+ cur->context = context;
+ cur->mech = mech;
+ cur->next = s_conn->mech_contexts;
+ s_conn->mech_contexts = cur;
+ }
+ }
+
+ /* Generic mechanism */
+ if (plug->max_ssf < minssf) {
+ sasl_seterror(conn, SASL_NOLOG, "too weak");
+ return SASL_TOOWEAK; /* too weak */
+ }
+
+ /* if there are no users in the secrets database we can't use this
+ mechanism */
+ if (mech->m.condition == SASL_NOUSER) {
+ sasl_seterror(conn, 0, "no users in secrets db");
+ return SASL_NOMECH;
+ }
+
+ /* Can it meet our features? */
+ if ((conn->flags & SASL_NEED_PROXY) &&
+ !(plug->features & SASL_FEAT_ALLOWS_PROXY)) {
+ return SASL_NOMECH;
+ }
+ if ((conn->flags & SASL_NEED_HTTP) &&
+ !(plug->features & SASL_FEAT_SUPPORTS_HTTP)) {
+ return SASL_NOMECH;
+ }
+
+ /* security properties---if there are any flags that differ and are
+ in what the connection are requesting, then fail */
+
+ /* special case plaintext */
+ myflags = conn->props.security_flags;
+
+ /* if there's an external layer this is no longer plaintext */
+ if ((conn->props.min_ssf <= conn->external.ssf) &&
+ (conn->external.ssf > 1)) {
+ myflags &= ~SASL_SEC_NOPLAINTEXT;
+ }
+
+ /* do we want to special case SASL_SEC_PASS_CREDENTIALS? nah.. */
+ if ((myflags &= (myflags ^ plug->security_flags)) != 0) {
+ sasl_seterror(conn, SASL_NOLOG,
+ "security flags do not match required");
+ return (myflags & SASL_SEC_NOPLAINTEXT) ? SASL_ENCRYPT : SASL_NOMECH;
+ }
+
+ /* Check Features */
+ if (plug->features & SASL_FEAT_GETSECRET) {
+ /* We no longer support sasl_server_{get,put}secret */
+ sasl_seterror(conn, 0,
+ "mech %s requires unprovided secret facility",
+ plug->mech_name);
+ return SASL_NOMECH;
+ }
+
+ return SASL_OK;
+}
+
+/*
+ * make the authorization
+ *
+ */
+
+static int do_authorization(sasl_server_conn_t *s_conn)
+{
+ int ret;
+ sasl_authorize_t *authproc;
+ void *auth_context;
+
+ /* now let's see if authname is allowed to proxy for username! */
+
+ /* check the proxy callback */
+ if (_sasl_getcallback(&s_conn->base, SASL_CB_PROXY_POLICY,
+ (sasl_callback_ft *)&authproc, &auth_context) != SASL_OK) {
+ INTERROR(&s_conn->base, SASL_NOAUTHZ);
+ }
+
+ ret = authproc(&(s_conn->base), auth_context,
+ s_conn->base.oparams.user, s_conn->base.oparams.ulen,
+ s_conn->base.oparams.authid, s_conn->base.oparams.alen,
+ s_conn->user_realm,
+ (s_conn->user_realm ? (unsigned) strlen(s_conn->user_realm) : 0),
+ s_conn->sparams->propctx);
+
+ RETURN(&s_conn->base, ret);
+}
+
+
+/* start a mechanism exchange within a connection context
+ * mech -- the mechanism name client requested
+ * clientin -- client initial response (NUL terminated), NULL if empty
+ * clientinlen -- length of initial response
+ * serverout -- initial server challenge, NULL if done
+ * (library handles freeing this string)
+ * serveroutlen -- length of initial server challenge
+ * output:
+ * pconn -- the connection negotiation state on success
+ *
+ * Same returns as sasl_server_step() or
+ * SASL_NOMECH if mechanism not available.
+ */
+int sasl_server_start(sasl_conn_t *conn,
+ const char *mech,
+ const char *clientin,
+ unsigned clientinlen,
+ const char **serverout,
+ unsigned *serveroutlen)
+{
+ sasl_server_conn_t *s_conn=(sasl_server_conn_t *) conn;
+ int result;
+ context_list_t *cur, **prev;
+ mechanism_t *m;
+ size_t mech_len;
+ int plus = 0;
+
+ if (_sasl_server_active==0) return SASL_NOTINIT;
+
+ /* check parameters */
+ if(!conn) return SASL_BADPARAM;
+
+ if (!mech || ((clientin == NULL) && (clientinlen > 0)))
+ PARAMERROR(conn);
+
+ if (serverout) *serverout = NULL;
+ if (serveroutlen) *serveroutlen = 0;
+
+ /* make sure mech is valid mechanism
+ if not return appropriate error */
+ m = s_conn->mech_list;
+ mech_len = strlen(mech);
+
+ while (m != NULL) {
+ if (_sasl_is_equal_mech(mech, m->m.plug->mech_name, mech_len, &plus)) {
+ break;
+ }
+
+ m = m->next;
+ }
+
+ if (m == NULL) {
+ sasl_seterror(conn, 0, "Couldn't find mech %s", mech);
+ result = SASL_NOMECH;
+ goto done;
+ }
+
+ /* Make sure that we're willing to use this mech */
+ if ((result = mech_permitted(conn, m)) != SASL_OK) {
+ goto done;
+ }
+
+ if (m->m.condition == SASL_CONTINUE) {
+ sasl_server_plug_init_t *entry_point = NULL;
+ void *library = NULL;
+ sasl_server_plug_t *pluglist = NULL;
+ int version, plugcount;
+ int l = 0;
+
+ /* need to load this plugin */
+ result = _sasl_get_plugin(m->m.f,
+ _sasl_find_verifyfile_callback(global_callbacks.callbacks),
+ &library);
+
+ if (result == SASL_OK) {
+ result = _sasl_locate_entry(library, "sasl_server_plug_init",
+ (void **)&entry_point);
+ }
+
+ if (result == SASL_OK) {
+ result = entry_point(mechlist->utils, SASL_SERVER_PLUG_VERSION,
+ &version, &pluglist, &plugcount);
+ }
+
+ if (result == SASL_OK) {
+ /* find the correct mechanism in this plugin */
+ for (l = 0; l < plugcount; l++) {
+ if (!strcasecmp(pluglist[l].mech_name,
+ m->m.plug->mech_name)) break;
+ }
+ if (l == plugcount) {
+ result = SASL_NOMECH;
+ }
+ }
+ if (result == SASL_OK) {
+ /* check that the parameters are the same */
+ if ((pluglist[l].max_ssf != m->m.plug->max_ssf) ||
+ (pluglist[l].security_flags != m->m.plug->security_flags)) {
+ _sasl_log(conn, SASL_LOG_ERR,
+ "%s: security parameters don't match mechlist file",
+ pluglist[l].mech_name);
+ result = SASL_NOMECH;
+ }
+ }
+ if (result == SASL_OK) {
+ /* copy mechlist over */
+ sasl_FREE((sasl_server_plug_t *) m->m.plug);
+ m->m.plug = &pluglist[l];
+ m->m.condition = SASL_OK;
+ }
+
+ if (result != SASL_OK) {
+ /* The library will eventually be freed, don't sweat it */
+ RETURN(conn, result);
+ }
+ }
+
+ if (conn->context) {
+ s_conn->mech->m.plug->mech_dispose(conn->context,
+ s_conn->sparams->utils);
+ conn->context = NULL;
+ }
+
+ /* We used to setup sparams HERE, but now it's done
+ inside of mech_permitted (which is called above) */
+ prev = &s_conn->mech_contexts;
+ for (cur = *prev; cur; prev=&cur->next,cur=cur->next) {
+ if (cur->mech == m) {
+ if (!cur->context) {
+ sasl_seterror(conn, 0,
+ "Got past mech_permitted with a disallowed mech!");
+ return SASL_NOMECH;
+ }
+ /* If we find it, we need to pull cur out of the
+ list so it won't be freed later! */
+ *prev = cur->next;
+ conn->context = cur->context;
+ sasl_FREE(cur);
+ break;
+ }
+ }
+
+ s_conn->mech = m;
+
+ if (!conn->context) {
+ /* Note that we don't hand over a new challenge */
+ result = s_conn->mech->m.plug->mech_new(s_conn->mech->m.plug->glob_context,
+ s_conn->sparams,
+ NULL,
+ 0,
+ &(conn->context));
+ } else {
+ /* the work was already done by mech_avail! */
+ result = SASL_OK;
+ }
+
+ if (result == SASL_OK) {
+ if (clientin) {
+ if (s_conn->mech->m.plug->features & SASL_FEAT_SERVER_FIRST) {
+ /* Remote sent first, but mechanism does not support it.
+ * RFC 2222 says we fail at this point. */
+ sasl_seterror(conn,
+ 0,
+ "Remote sent first but mech does not allow it.");
+ result = SASL_BADPROT;
+ } else {
+ /* Mech wants client-first, so let them have it */
+ result = sasl_server_step(conn,
+ clientin,
+ clientinlen,
+ serverout,
+ serveroutlen);
+ }
+ } else {
+ if (s_conn->mech->m.plug->features & SASL_FEAT_WANT_CLIENT_FIRST) {
+ /* Mech wants client first anyway, so we should do that */
+ if (serverout) *serverout = "";
+ if (serveroutlen) *serveroutlen = 0;
+ result = SASL_CONTINUE;
+ } else {
+ /* Mech wants server-first, so let them have it */
+ result = sasl_server_step(conn,
+ clientin,
+ clientinlen,
+ serverout,
+ serveroutlen);
+ }
+ }
+ }
+
+ done:
+ if ( result != SASL_OK
+ && result != SASL_CONTINUE
+ && result != SASL_INTERACT) {
+ if (conn->context) {
+ s_conn->mech->m.plug->mech_dispose(conn->context,
+ s_conn->sparams->utils);
+ conn->context = NULL;
+ }
+ conn->oparams.doneflag = 0;
+ }
+
+ RETURN(conn,result);
+}
+
+
+/* perform one step of the SASL exchange
+ * clientinlen & clientin -- client data
+ * NULL on first step if no optional client step
+ * serveroutlen & serverout -- set to the server data to transmit
+ * to the client in the next step
+ * (library handles freeing this)
+ *
+ * returns:
+ * SASL_OK -- exchange is complete.
+ * SASL_CONTINUE -- indicates another step is necessary.
+ * SASL_TRANS -- entry for user exists, but not for mechanism
+ * and transition is possible
+ * SASL_BADPARAM -- service name needed
+ * SASL_BADPROT -- invalid input from client
+ * ...
+ */
+
+int sasl_server_step(sasl_conn_t *conn,
+ const char *clientin,
+ unsigned clientinlen,
+ const char **serverout,
+ unsigned *serveroutlen)
+{
+ int ret;
+ sasl_server_conn_t *s_conn = (sasl_server_conn_t *) conn; /* cast */
+
+ /* check parameters */
+ if (_sasl_server_active==0) return SASL_NOTINIT;
+ if (!conn) return SASL_BADPARAM;
+ if ((clientin==NULL) && (clientinlen>0))
+ PARAMERROR(conn);
+
+ /* If we've already done the last send, return! */
+ if (s_conn->sent_last == 1) {
+ return SASL_OK;
+ }
+
+ /* Don't do another step if the plugin told us that we're done */
+ if (conn->oparams.doneflag) {
+ _sasl_log(conn, SASL_LOG_ERR, "attempting server step after doneflag");
+ return SASL_FAIL;
+ }
+
+ if (serverout) *serverout = NULL;
+ if (serveroutlen) *serveroutlen = 0;
+
+ ret = s_conn->mech->m.plug->mech_step(conn->context,
+ s_conn->sparams,
+ clientin,
+ clientinlen,
+ serverout,
+ serveroutlen,
+ &conn->oparams);
+
+ if (ret == SASL_OK) {
+ ret = do_authorization(s_conn);
+ }
+
+ if (ret == SASL_OK) {
+ /* if we're done, we need to watch out for the following:
+ * 1. the mech does server-send-last
+ * 2. the protocol does not
+ *
+ * in this case, return SASL_CONTINUE and remember we are done.
+ */
+ if(*serverout && !(conn->flags & SASL_SUCCESS_DATA)) {
+ s_conn->sent_last = 1;
+ ret = SASL_CONTINUE;
+ }
+ if(!conn->oparams.maxoutbuf) {
+ conn->oparams.maxoutbuf = conn->props.maxbufsize;
+ }
+
+ /* Validate channel bindings */
+ switch (conn->oparams.cbindingdisp) {
+ case SASL_CB_DISP_NONE:
+ if (SASL_CB_CRITICAL(s_conn->sparams)) {
+ sasl_seterror(conn, 0,
+ "server requires channel binding but client provided none");
+ ret = SASL_BADBINDING;
+ }
+ break;
+ case SASL_CB_DISP_WANT:
+ if (SASL_CB_PRESENT(s_conn->sparams)) {
+ sasl_seterror(conn, 0,
+ "client incorrectly assumed server had no channel binding");
+ ret = SASL_BADAUTH;
+ }
+ break;
+ case SASL_CB_DISP_USED:
+ if (!SASL_CB_PRESENT(s_conn->sparams)) {
+ sasl_seterror(conn, 0,
+ "client provided channel binding but server had none");
+ ret = SASL_BADBINDING;
+ } else if (strcmp(conn->oparams.cbindingname,
+ s_conn->sparams->cbinding->name) != 0) {
+ sasl_seterror(conn, 0,
+ "client channel binding %s does not match server %s",
+ conn->oparams.cbindingname, s_conn->sparams->cbinding->name);
+ ret = SASL_BADBINDING;
+ }
+ break;
+ }
+
+ if (ret == SASL_OK &&
+ (conn->oparams.user == NULL || conn->oparams.authid == NULL)) {
+ sasl_seterror(conn, 0,
+ "mech did not call canon_user for both authzid " \
+ "and authid");
+ ret = SASL_BADPROT;
+ }
+ }
+
+ if ( ret != SASL_OK
+ && ret != SASL_CONTINUE
+ && ret != SASL_INTERACT) {
+ if (conn->context) {
+ s_conn->mech->m.plug->mech_dispose(conn->context,
+ s_conn->sparams->utils);
+ conn->context = NULL;
+ }
+ conn->oparams.doneflag = 0;
+ }
+
+ RETURN(conn, ret);
+}
+
+/* returns the length of all the mechanisms
+ * added up
+ */
+
+static unsigned mech_names_len(mechanism_t *mech_list)
+{
+ mechanism_t *listptr;
+ unsigned result = 0;
+
+ for (listptr = mech_list;
+ listptr;
+ listptr = listptr->next)
+ result += (unsigned) strlen(listptr->m.plug->mech_name);
+
+ return result;
+}
+
+/* This returns a list of mechanisms in a NUL-terminated string
+ *
+ * The default behavior is to separate with spaces if sep == NULL
+ */
+int _sasl_server_listmech(sasl_conn_t *conn,
+ const char *user __attribute__((unused)),
+ const char *prefix,
+ const char *sep,
+ const char *suffix,
+ const char **result,
+ unsigned *plen,
+ int *pcount)
+{
+ sasl_server_conn_t *s_conn = (sasl_server_conn_t *) conn; /* cast */
+ int lup;
+ mechanism_t *listptr;
+ int ret;
+ size_t resultlen;
+ int flag;
+ const char *mysep;
+
+ /* if there hasn't been a sasl_sever_init() fail */
+ if (_sasl_server_active==0) return SASL_NOTINIT;
+ if (!conn) return SASL_BADPARAM;
+ if (conn->type != SASL_CONN_SERVER) PARAMERROR(conn);
+
+ if (! result)
+ PARAMERROR(conn);
+
+ if (plen != NULL)
+ *plen = 0;
+ if (pcount != NULL)
+ *pcount = 0;
+
+ if (sep) {
+ mysep = sep;
+ } else {
+ mysep = " ";
+ }
+
+ if (!s_conn->mech_list || s_conn->mech_length <= 0)
+ INTERROR(conn, SASL_NOMECH);
+
+ resultlen = (prefix ? strlen(prefix) : 0)
+ + (strlen(mysep) * (s_conn->mech_length - 1) * 2)
+ + (mech_names_len(s_conn->mech_list) * 2) /* including -PLUS variant */
+ + (s_conn->mech_length * (sizeof("-PLUS") - 1))
+ + (suffix ? strlen(suffix) : 0)
+ + 1;
+
+ ret = _buf_alloc(&conn->mechlist_buf,
+ &conn->mechlist_buf_len, resultlen);
+ if(ret != SASL_OK) MEMERROR(conn);
+
+ if (prefix)
+ strcpy (conn->mechlist_buf,prefix);
+ else
+ *(conn->mechlist_buf) = '\0';
+
+ listptr = s_conn->mech_list;
+
+ flag = 0;
+ /* make list */
+ for (lup = 0; lup < s_conn->mech_length; lup++) {
+ /* currently, we don't use the "user" parameter for anything */
+ if (mech_permitted(conn, listptr) == SASL_OK) {
+
+ /*
+ * If the server would never succeed in the authentication of
+ * the non-PLUS-variant due to policy reasons, it MUST advertise
+ * only the PLUS-variant.
+ */
+ if ((listptr->m.plug->features & SASL_FEAT_CHANNEL_BINDING) &&
+ SASL_CB_PRESENT(s_conn->sparams)) {
+ if (pcount != NULL) {
+ (*pcount)++;
+ }
+ if (flag) {
+ strcat(conn->mechlist_buf, mysep);
+ } else {
+ flag = 1;
+ }
+ strcat(conn->mechlist_buf, listptr->m.plug->mech_name);
+ strcat(conn->mechlist_buf, "-PLUS");
+ }
+
+ /*
+ * If the server cannot support channel binding, it SHOULD
+ * advertise only the non-PLUS-variant. Here, supporting channel
+ * binding means the underlying SASL mechanism supports it and
+ * the application has set some channel binding data.
+ */
+ if (!SASL_CB_PRESENT(s_conn->sparams) ||
+ !SASL_CB_CRITICAL(s_conn->sparams)) {
+ if (pcount != NULL) {
+ (*pcount)++;
+ }
+ if (flag) {
+ strcat(conn->mechlist_buf, mysep);
+ } else {
+ flag = 1;
+ }
+ strcat(conn->mechlist_buf, listptr->m.plug->mech_name);
+ }
+ }
+
+ listptr = listptr->next;
+ }
+
+ if (suffix)
+ strcat(conn->mechlist_buf,suffix);
+
+ if (plen!=NULL)
+ *plen = (unsigned) strlen(conn->mechlist_buf);
+
+ *result = conn->mechlist_buf;
+
+ return SASL_OK;
+}
+
+sasl_string_list_t *_sasl_server_mechs(void)
+{
+ mechanism_t *listptr;
+ sasl_string_list_t *retval = NULL, *next=NULL;
+
+ if(!_sasl_server_active) return NULL;
+
+ /* make list */
+ for (listptr = mechlist->mech_list; listptr; listptr = listptr->next) {
+ next = sasl_ALLOC(sizeof(sasl_string_list_t));
+
+ if(!next && !retval) return NULL;
+ else if(!next) {
+ next = retval->next;
+ do {
+ sasl_FREE(retval);
+ retval = next;
+ next = retval->next;
+ } while(next);
+ return NULL;
+ }
+
+ next->d = listptr->m.plug->mech_name;
+
+ if(!retval) {
+ next->next = NULL;
+ retval = next;
+ } else {
+ next->next = retval;
+ retval = next;
+ }
+ }
+
+ return retval;
+}
+
+#define EOSTR(s,n) (((s)[n] == '\0') || ((s)[n] == ' ') || ((s)[n] == '\t'))
+static int is_mech(const char *t, const char *m)
+{
+ size_t sl = strlen(m);
+ return ((!strncasecmp(m, t, sl)) && EOSTR(t, sl));
+}
+
+/* returns OK if it's valid */
+static int _sasl_checkpass(sasl_conn_t *conn,
+ const char *user,
+ unsigned userlen,
+ const char *pass,
+ unsigned passlen)
+{
+ sasl_server_conn_t *s_conn = (sasl_server_conn_t *) conn;
+ int result;
+ sasl_getopt_t *getopt;
+ sasl_server_userdb_checkpass_t *checkpass_cb;
+ void *context;
+ const char *mlist = NULL, *mech = NULL;
+ struct sasl_verify_password_s *v;
+ const char *service = conn->service;
+
+ if (!userlen) userlen = (unsigned) strlen(user);
+ if (!passlen) passlen = (unsigned) strlen(pass);
+
+ /* call userdb callback function, if available */
+ result = _sasl_getcallback(conn, SASL_CB_SERVER_USERDB_CHECKPASS,
+ (sasl_callback_ft *)&checkpass_cb, &context);
+ if(result == SASL_OK && checkpass_cb) {
+ result = checkpass_cb(conn, context, user, pass, passlen,
+ s_conn->sparams->propctx);
+ if(result == SASL_OK)
+ return SASL_OK;
+ }
+
+ /* figure out how to check (i.e. auxprop or saslauthd or pwcheck) */
+ if (_sasl_getcallback(conn, SASL_CB_GETOPT, (sasl_callback_ft *)&getopt, &context)
+ == SASL_OK) {
+ getopt(context, NULL, "pwcheck_method", &mlist, NULL);
+ }
+
+ if(!mlist) mlist = DEFAULT_CHECKPASS_MECH;
+
+ result = SASL_NOMECH;
+
+ mech = mlist;
+ while (*mech && result != SASL_OK) {
+ for (v = _sasl_verify_password; v->name; v++) {
+ if(is_mech(mech, v->name)) {
+ result = v->verify(conn, user, pass, service,
+ s_conn->user_realm);
+ break;
+ }
+ }
+ if (result != SASL_OK) {
+ /* skip to next mech in list */
+ while (*mech && !isspace((int) *mech)) mech++;
+ while (*mech && isspace((int) *mech)) mech++;
+ }
+ else if (!is_mech(mech, "auxprop") && s_conn->sparams->transition) {
+ s_conn->sparams->transition(conn, pass, passlen);
+ }
+ }
+
+ if (result == SASL_NOMECH) {
+ /* no mechanism available ?!? */
+ _sasl_log(conn, SASL_LOG_ERR, "unknown password verifier(s) %s", mlist);
+ }
+
+ if (result != SASL_OK)
+ sasl_seterror(conn, SASL_NOLOG, "checkpass failed");
+
+ RETURN(conn, result);
+}
+
+/* check if a plaintext password is valid
+ * if user is NULL, check if plaintext passwords are enabled
+ * inputs:
+ * user -- user to query in current user_domain
+ * userlen -- length of username, 0 = strlen(user)
+ * pass -- plaintext password to check
+ * passlen -- length of password, 0 = strlen(pass)
+ * returns
+ * SASL_OK -- success
+ * SASL_NOMECH -- mechanism not supported
+ * SASL_NOVERIFY -- user found, but no verifier
+ * SASL_NOUSER -- user not found
+ */
+int sasl_checkpass(sasl_conn_t *conn,
+ const char *user,
+ unsigned userlen,
+ const char *pass,
+ unsigned passlen)
+{
+ int result;
+
+ if (_sasl_server_active==0) return SASL_NOTINIT;
+
+ /* check if it's just a query if we are enabled */
+ if (!user)
+ return SASL_OK;
+
+ if (!conn) return SASL_BADPARAM;
+
+ /* check params */
+ if (pass == NULL)
+ PARAMERROR(conn);
+
+ /* canonicalize the username */
+ result = _sasl_canon_user(conn, user, userlen,
+ SASL_CU_AUTHID | SASL_CU_AUTHZID,
+ &(conn->oparams));
+ if(result != SASL_OK) RETURN(conn, result);
+ user = conn->oparams.user;
+
+ /* Check the password and lookup additional properties */
+ result = _sasl_checkpass(conn, user, userlen, pass, passlen);
+
+ /* Do authorization */
+ if(result == SASL_OK) {
+ result = do_authorization((sasl_server_conn_t *)conn);
+ }
+
+ RETURN(conn,result);
+}
+
+/* check if a user exists on server
+ * conn -- connection context (may be NULL, used to hold last error)
+ * service -- registered name of the service using SASL (e.g. "imap")
+ * user_realm -- permits multiple user realms on server, NULL = default
+ * user -- NUL terminated user name
+ *
+ * returns:
+ * SASL_OK -- success
+ * SASL_DISABLED -- account disabled [FIXME: currently not detected]
+ * SASL_NOUSER -- user not found
+ * SASL_NOVERIFY -- user found, but no usable mechanism [FIXME: not supported]
+ * SASL_NOMECH -- no mechanisms enabled
+ * SASL_UNAVAIL -- remote authentication server unavailable, try again later
+ */
+int sasl_user_exists(sasl_conn_t *conn,
+ const char *service,
+ const char *user_realm,
+ const char *user)
+{
+ int result=SASL_NOMECH;
+ const char *mlist = NULL, *mech = NULL;
+ void *context;
+ sasl_getopt_t *getopt;
+ struct sasl_verify_password_s *v;
+
+ /* check params */
+ if (_sasl_server_active==0) return SASL_NOTINIT;
+ if (!conn) return SASL_BADPARAM;
+ if (!user || conn->type != SASL_CONN_SERVER)
+ PARAMERROR(conn);
+
+ if(!service) service = conn->service;
+
+ /* figure out how to check (i.e. auxprop or saslauthd or pwcheck) */
+ if (_sasl_getcallback(conn, SASL_CB_GETOPT, (sasl_callback_ft *)&getopt, &context)
+ == SASL_OK) {
+ getopt(context, NULL, "pwcheck_method", &mlist, NULL);
+ }
+
+ if(!mlist) mlist = DEFAULT_CHECKPASS_MECH;
+
+ result = SASL_NOMECH;
+
+ mech = mlist;
+ while (*mech && result != SASL_OK) {
+ for (v = _sasl_verify_password; v->name; v++) {
+ if(is_mech(mech, v->name)) {
+ result = v->verify(conn, user, NULL, service, user_realm);
+ break;
+ }
+ }
+ if (result != SASL_OK) {
+ /* skip to next mech in list */
+ while (*mech && !isspace((int) *mech)) mech++;
+ while (*mech && isspace((int) *mech)) mech++;
+ }
+ }
+
+ /* Screen out the SASL_BADPARAM response
+ * we'll get from not giving a password */
+ if (result == SASL_BADPARAM) {
+ result = SASL_OK;
+ }
+
+ if (result == SASL_NOMECH) {
+ /* no mechanism available ?!? */
+ _sasl_log(conn, SASL_LOG_ERR, "no plaintext password verifier?");
+ sasl_seterror(conn, SASL_NOLOG, "no plaintext password verifier?");
+ }
+
+ RETURN(conn, result);
+}
+
+/* check if an apop exchange is valid
+ * (note this is an optional part of the SASL API)
+ * if challenge is NULL, just check if APOP is enabled
+ * inputs:
+ * challenge -- challenge which was sent to client
+ * challen -- length of challenge, 0 = strlen(challenge)
+ * response -- client response, "<user> <digest>" (RFC 1939)
+ * resplen -- length of response, 0 = strlen(response)
+ * returns
+ * SASL_OK -- success
+ * SASL_BADAUTH -- authentication failed
+ * SASL_BADPARAM -- missing challenge
+ * SASL_BADPROT -- protocol error (e.g., response in wrong format)
+ * SASL_NOVERIFY -- user found, but no verifier
+ * SASL_NOMECH -- mechanism not supported
+ * SASL_NOUSER -- user not found
+ */
+int sasl_checkapop(sasl_conn_t *conn,
+#ifdef DO_SASL_CHECKAPOP
+ const char *challenge,
+ unsigned challen __attribute__((unused)),
+ const char *response,
+ unsigned resplen __attribute__((unused)))
+#else
+ const char *challenge __attribute__((unused)),
+ unsigned challen __attribute__((unused)),
+ const char *response __attribute__((unused)),
+ unsigned resplen __attribute__((unused)))
+#endif
+{
+#ifdef DO_SASL_CHECKAPOP
+ sasl_server_conn_t *s_conn = (sasl_server_conn_t *) conn;
+ char *user, *user_end;
+ const char *password_request[] = { SASL_AUX_PASSWORD, NULL };
+ size_t user_len;
+ int result;
+
+ if (_sasl_server_active==0)
+ return SASL_NOTINIT;
+
+ /* check if it's just a query if we are enabled */
+ if(!challenge)
+ return SASL_OK;
+
+ /* check params */
+ if (!conn) return SASL_BADPARAM;
+ if (!response)
+ PARAMERROR(conn);
+
+ /* Parse out username and digest.
+ *
+ * Per RFC 1939, response must be "<user> <digest>", where
+ * <digest> is a 16-octet value which is sent in hexadecimal
+ * format, using lower-case ASCII characters.
+ */
+ user_end = strrchr(response, ' ');
+ if (!user_end || strspn(user_end + 1, "0123456789abcdef") != 32)
+ {
+ sasl_seterror(conn, 0, "Bad Digest");
+ RETURN(conn,SASL_BADPROT);
+ }
+
+ user_len = (size_t)(user_end - response);
+ user = sasl_ALLOC(user_len + 1);
+ memcpy(user, response, user_len);
+ user[user_len] = '\0';
+
+ result = prop_request(s_conn->sparams->propctx, password_request);
+ if(result != SASL_OK)
+ {
+ sasl_FREE(user);
+ RETURN(conn, result);
+ }
+
+ /* erase the plaintext password */
+ s_conn->sparams->utils->prop_erase(s_conn->sparams->propctx,
+ password_request[0]);
+
+ /* canonicalize the username and lookup any associated properties */
+ result = _sasl_canon_user_lookup (conn,
+ user,
+ user_len,
+ SASL_CU_AUTHID | SASL_CU_AUTHZID,
+ &(conn->oparams));
+ sasl_FREE(user);
+
+ if(result != SASL_OK) RETURN(conn, result);
+
+ /* Do APOP verification */
+ result = _sasl_auxprop_verify_apop(conn, conn->oparams.authid,
+ challenge, user_end + 1, s_conn->user_realm);
+
+ /* Do authorization */
+ if(result == SASL_OK) {
+ result = do_authorization((sasl_server_conn_t *)conn);
+ } else {
+ /* If verification failed, we don't want to encourage getprop to work */
+ conn->oparams.user = NULL;
+ conn->oparams.authid = NULL;
+ }
+
+ RETURN(conn, result);
+#else /* sasl_checkapop was disabled at compile time */
+ sasl_seterror(conn, SASL_NOLOG,
+ "sasl_checkapop called, but was disabled at compile time");
+ RETURN(conn, SASL_NOMECH);
+#endif /* DO_SASL_CHECKAPOP */
+}
+
+/* It would be nice if we can show other information like Author, Company, Year, plugin version */
+static void
+_sasl_print_mechanism (
+ server_sasl_mechanism_t *m,
+ sasl_info_callback_stage_t stage,
+ void *rock __attribute__((unused))
+)
+{
+ char delimiter;
+
+ if (stage == SASL_INFO_LIST_START) {
+ printf ("List of server plugins follows\n");
+ return;
+ } else if (stage == SASL_INFO_LIST_END) {
+ return;
+ }
+
+ /* Process the mechanism */
+ printf ("Plugin \"%s\" ", m->plugname);
+
+ switch (m->condition) {
+ case SASL_OK:
+ printf ("[loaded]");
+ break;
+
+ case SASL_CONTINUE:
+ printf ("[delayed]");
+ break;
+
+ case SASL_NOUSER:
+ printf ("[no users]");
+ break;
+
+ default:
+ printf ("[unknown]");
+ break;
+ }
+
+ printf (", \tAPI version: %d\n", m->version);
+
+ if (m->plug != NULL) {
+ printf ("\tSASL mechanism: %s, best SSF: %d, supports setpass: %s\n",
+ m->plug->mech_name,
+ m->plug->max_ssf,
+ (m->plug->setpass != NULL) ? "yes" : "no"
+ );
+
+
+ printf ("\tsecurity flags:");
+
+ delimiter = ' ';
+ if (m->plug->security_flags & SASL_SEC_NOANONYMOUS) {
+ printf ("%cNO_ANONYMOUS", delimiter);
+ delimiter = '|';
+ }
+
+ if (m->plug->security_flags & SASL_SEC_NOPLAINTEXT) {
+ printf ("%cNO_PLAINTEXT", delimiter);
+ delimiter = '|';
+ }
+
+ if (m->plug->security_flags & SASL_SEC_NOACTIVE) {
+ printf ("%cNO_ACTIVE", delimiter);
+ delimiter = '|';
+ }
+
+ if (m->plug->security_flags & SASL_SEC_NODICTIONARY) {
+ printf ("%cNO_DICTIONARY", delimiter);
+ delimiter = '|';
+ }
+
+ if (m->plug->security_flags & SASL_SEC_FORWARD_SECRECY) {
+ printf ("%cFORWARD_SECRECY", delimiter);
+ delimiter = '|';
+ }
+
+ if (m->plug->security_flags & SASL_SEC_PASS_CREDENTIALS) {
+ printf ("%cPASS_CREDENTIALS", delimiter);
+ delimiter = '|';
+ }
+
+ if (m->plug->security_flags & SASL_SEC_MUTUAL_AUTH) {
+ printf ("%cMUTUAL_AUTH", delimiter);
+ delimiter = '|';
+ }
+
+
+
+ printf ("\n\tfeatures:");
+
+ delimiter = ' ';
+ if (m->plug->features & SASL_FEAT_WANT_CLIENT_FIRST) {
+ printf ("%cWANT_CLIENT_FIRST", delimiter);
+ delimiter = '|';
+ }
+
+ if (m->plug->features & SASL_FEAT_SERVER_FIRST) {
+ printf ("%cSERVER_FIRST", delimiter);
+ delimiter = '|';
+ }
+
+ if (m->plug->features & SASL_FEAT_ALLOWS_PROXY) {
+ printf ("%cPROXY_AUTHENTICATION", delimiter);
+ delimiter = '|';
+ }
+
+ if (m->plug->features & SASL_FEAT_DONTUSE_USERPASSWD) {
+ printf ("%cDONTUSE_USERPASSWD", delimiter);
+ delimiter = '|';
+ }
+
+ if (m->plug->features & SASL_FEAT_NEEDSERVERFQDN) {
+ printf ("%cNEED_SERVER_FQDN", delimiter);
+ delimiter = '|';
+ }
+
+ /* Is this one used? */
+ if (m->plug->features & SASL_FEAT_SERVICE) {
+ printf ("%cSERVICE", delimiter);
+ delimiter = '|';
+ }
+
+ if (m->plug->features & SASL_FEAT_GETSECRET) {
+ printf ("%cNEED_GETSECRET", delimiter);
+ delimiter = '|';
+ }
+
+ if (m->plug->features & SASL_FEAT_GSS_FRAMING) {
+ printf ("%cGSS_FRAMING", delimiter);
+ delimiter = '|';
+ }
+
+ if (m->plug->features & SASL_FEAT_CHANNEL_BINDING) {
+ printf ("%cCHANNEL_BINDING", delimiter);
+ delimiter = '|';
+ }
+
+ if (m->plug->features & SASL_FEAT_SUPPORTS_HTTP) {
+ printf ("%cSUPPORTS_HTTP", delimiter);
+ delimiter = '|';
+ }
+ }
+
+ if (m->f) {
+ printf ("\n\twill be loaded from \"%s\"", m->f);
+ }
+
+ printf ("\n");
+}
+
+/* Dump information about available server plugins (separate functions should be
+ used for canon and auxprop plugins */
+int sasl_server_plugin_info (
+ const char *c_mech_list, /* space separated mechanism list or NULL for ALL */
+ sasl_server_info_callback_t *info_cb,
+ void *info_cb_rock
+)
+{
+ mechanism_t *m;
+ server_sasl_mechanism_t plug_data;
+ char * cur_mech;
+ char *mech_list = NULL;
+ char * p;
+
+ if (info_cb == NULL) {
+ info_cb = _sasl_print_mechanism;
+ }
+
+ if (mechlist != NULL) {
+ info_cb (NULL, SASL_INFO_LIST_START, info_cb_rock);
+
+ if (c_mech_list == NULL) {
+ m = mechlist->mech_list; /* m point to beginning of the list */
+
+ while (m != NULL) {
+ memcpy (&plug_data, &m->m, sizeof(plug_data));
+
+ info_cb (&plug_data, SASL_INFO_LIST_MECH, info_cb_rock);
+
+ m = m->next;
+ }
+ } else {
+ mech_list = strdup(c_mech_list);
+
+ cur_mech = mech_list;
+
+ while (cur_mech != NULL) {
+ p = strchr (cur_mech, ' ');
+ if (p != NULL) {
+ *p = '\0';
+ p++;
+ }
+
+ m = mechlist->mech_list; /* m point to beginning of the list */
+
+ while (m != NULL) {
+ if (strcasecmp (cur_mech, m->m.plug->mech_name) == 0) {
+ memcpy (&plug_data, &m->m, sizeof(plug_data));
+
+ info_cb (&plug_data, SASL_INFO_LIST_MECH, info_cb_rock);
+ }
+
+ m = m->next;
+ }
+
+ cur_mech = p;
+ }
+
+ free (mech_list);
+ }
+
+ info_cb (NULL, SASL_INFO_LIST_END, info_cb_rock);
+
+ return (SASL_OK);
+ }
+
+ return (SASL_NOTINIT);
+}
diff --git a/contrib/libs/sasl/lib/seterror.c b/contrib/libs/sasl/lib/seterror.c
new file mode 100644
index 0000000000..05eec9a8e2
--- /dev/null
+++ b/contrib/libs/sasl/lib/seterror.c
@@ -0,0 +1,263 @@
+/* seterror.c - sasl_seterror split out because glue libraries
+ * can't pass varargs lists
+ * Rob Siemborski
+ * Tim Martin
+ * split from common.c by Rolf Braun
+ */
+
+/*
+ * Copyright (c) 1998-2016 Carnegie Mellon University. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For permission or any other legal
+ * details, please contact
+ * Carnegie Mellon University
+ * Center for Technology Transfer and Enterprise Creation
+ * 4615 Forbes Avenue
+ * Suite 302
+ * Pittsburgh, PA 15213
+ * (412) 268-7393, fax: (412) 268-7395
+ * innovation@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Computing Services
+ * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+#ifdef HAVE_SYSLOG
+#include <syslog.h>
+#endif
+#include <stdarg.h>
+#include <ctype.h>
+
+#include <sasl.h>
+#include <saslutil.h>
+#include <saslplug.h>
+#include "saslint.h"
+
+#ifdef WIN32
+/* need to handle the fact that errno has been defined as a function
+ in a dll, not an extern int */
+# ifdef errno
+# undef errno
+# endif /* errno */
+#endif /* WIN32 */
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+/* this is apparently no longer a user function */
+static int _sasl_seterror_usererr(int saslerr)
+{
+ /* Hide the difference in a username failure and a password failure */
+ if (saslerr == SASL_NOUSER)
+ return SASL_BADAUTH;
+
+ /* otherwise return the error given; no transform necessary */
+ return saslerr;
+}
+
+/* set the error string which will be returned by sasl_errdetail() using
+ * syslog()-style formatting (e.g. printf-style with %m as the string form
+ * of an errno error)
+ *
+ * primarily for use by server callbacks such as the sasl_authorize_t
+ * callback and internally to plug-ins
+ *
+ * This will also trigger a call to the SASL logging callback (if any)
+ * with a level of SASL_LOG_FAIL unless the SASL_NOLOG flag is set.
+ *
+ * Messages should be sensitive to the current language setting. If there
+ * is no SASL_CB_LANGUAGE callback messages MUST be US-ASCII otherwise UTF-8
+ * is used and use of RFC 2482 for mixed-language text is encouraged.
+ *
+ * if conn is NULL, function does nothing
+ */
+void sasl_seterror(sasl_conn_t *conn,
+ unsigned flags,
+ const char *fmt, ...)
+{
+ size_t outlen=0; /* current length of output buffer */
+ size_t pos = 0; /* current position in format string */
+ size_t formatlen;
+ int result;
+ sasl_log_t *log_cb = NULL;
+ void *log_ctx;
+ int ival;
+ char *cval;
+ va_list ap; /* varargs thing */
+ char **error_buf;
+ size_t *error_buf_len;
+
+ if(!conn) {
+#ifndef SASL_OSX_CFMGLUE
+ if(!(flags & SASL_NOLOG)) {
+ /* See if we have a logging callback... */
+ result = _sasl_getcallback(NULL, SASL_CB_LOG, (sasl_callback_ft *)&log_cb, &log_ctx);
+ if (result == SASL_OK && ! log_cb)
+ result = SASL_FAIL;
+ if (result != SASL_OK)
+ return;
+
+ log_cb(log_ctx, SASL_LOG_FAIL,
+ "No sasl_conn_t passed to sasl_seterror");
+ }
+#endif /* SASL_OSX_CFMGLUE */
+ return;
+ } else if(!fmt) return;
+
+/* we need to use a back end function to get the buffer because the
+ cfm glue can't be rooting around in the internal structs */
+ _sasl_get_errorbuf(conn, &error_buf, &error_buf_len);
+
+ formatlen = strlen(fmt);
+
+ va_start(ap, fmt); /* start varargs */
+
+ while(pos<formatlen)
+ {
+ if (fmt[pos]!='%') /* regular character */
+ {
+ result = _buf_alloc(error_buf, error_buf_len, outlen+1);
+ if (result != SASL_OK)
+ goto done;
+ (*error_buf)[outlen]=fmt[pos];
+ outlen++;
+ pos++;
+ } else { /* formating thing */
+ int done=0;
+ char frmt[10];
+ int frmtpos=1;
+ char tempbuf[21];
+ frmt[0]='%';
+ pos++;
+
+ while (done==0)
+ {
+ switch(fmt[pos])
+ {
+ case 's': /* need to handle this */
+ cval = va_arg(ap, char *); /* get the next arg */
+ result = _sasl_add_string(error_buf, error_buf_len,
+ &outlen, cval);
+
+ if (result != SASL_OK) /* add the string */
+ goto done;
+
+ done=1;
+ break;
+
+ case '%': /* double % output the '%' character */
+ result = _buf_alloc(error_buf, error_buf_len, outlen+1);
+ if (result != SASL_OK)
+ goto done;
+ (*error_buf)[outlen]='%';
+ outlen++;
+ done=1;
+ break;
+
+ case 'm': /* insert the errno string */
+ result = _sasl_add_string(error_buf, error_buf_len,
+ &outlen,
+ strerror(va_arg(ap, int)));
+ if (result != SASL_OK)
+ goto done;
+ done=1;
+ break;
+
+ case 'z': /* insert the sasl error string */
+ result = _sasl_add_string(error_buf, error_buf_len, &outlen,
+ (char *)sasl_errstring(_sasl_seterror_usererr(
+ va_arg(ap, int)),NULL,NULL));
+ if (result != SASL_OK)
+ goto done;
+ done=1;
+ break;
+
+ case 'c':
+ frmt[frmtpos++]=fmt[pos];
+ frmt[frmtpos]=0;
+ tempbuf[0] = (char) va_arg(ap, int); /* get the next arg */
+ tempbuf[1]='\0';
+
+ /* now add the character */
+ result = _sasl_add_string(error_buf, error_buf_len,
+ &outlen, tempbuf);
+ if (result != SASL_OK)
+ goto done;
+ done=1;
+ break;
+
+ case 'd':
+ case 'i':
+ frmt[frmtpos++]=fmt[pos];
+ frmt[frmtpos]=0;
+ ival = va_arg(ap, int); /* get the next arg */
+
+ snprintf(tempbuf,20,frmt,ival); /* have snprintf do the work */
+ /* now add the string */
+ result = _sasl_add_string(error_buf, error_buf_len,
+ &outlen, tempbuf);
+ if (result != SASL_OK)
+ goto done;
+ done=1;
+
+ break;
+ default:
+ frmt[frmtpos++]=fmt[pos]; /* add to the formating */
+ frmt[frmtpos]=0;
+ if (frmtpos>9)
+ done=1;
+ }
+ pos++;
+ if (pos>formatlen)
+ done=1;
+ }
+
+ }
+ }
+
+ (*error_buf)[outlen]='\0'; /* put 0 at end */
+
+#ifndef SASL_OSX_CFMGLUE
+ if(!(flags & SASL_NOLOG)) {
+ /* See if we have a logging callback... */
+ result = _sasl_getcallback(conn, SASL_CB_LOG, (sasl_callback_ft *)&log_cb, &log_ctx);
+ if (result == SASL_OK && ! log_cb)
+ result = SASL_FAIL;
+ if (result != SASL_OK)
+ goto done;
+
+ result = log_cb(log_ctx, SASL_LOG_FAIL, conn->error_buf);
+ }
+#endif /* SASL_OSX_CFMGLUE */
+done:
+ va_end(ap);
+}
diff --git a/contrib/libs/sasl/lib/staticopen.h b/contrib/libs/sasl/lib/staticopen.h
new file mode 100644
index 0000000000..d1983163d9
--- /dev/null
+++ b/contrib/libs/sasl/lib/staticopen.h
@@ -0,0 +1,188 @@
+/* staticopen.h
+ * Rob Siemborski
+ * Howard Chu
+ */
+/*
+ * Copyright (c) 1998-2016 Carnegie Mellon University. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For permission or any other legal
+ * details, please contact
+ * Carnegie Mellon University
+ * Center for Technology Transfer and Enterprise Creation
+ * 4615 Forbes Avenue
+ * Suite 302
+ * Pittsburgh, PA 15213
+ * (412) 268-7393, fax: (412) 268-7395
+ * innovation@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Computing Services
+ * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+typedef enum {
+ UNKNOWN = 0, SERVER = 1, CLIENT = 2, AUXPROP = 3, CANONUSER = 4
+} _sasl_plug_type;
+
+typedef struct {
+ _sasl_plug_type type;
+ char *name;
+ sasl_client_plug_init_t *plug;
+} _sasl_plug_rec;
+
+/* For static linking */
+#define SPECIFIC_CLIENT_PLUG_INIT_PROTO( x ) \
+sasl_client_plug_init_t x##_client_plug_init
+
+#define SPECIFIC_SERVER_PLUG_INIT_PROTO( x ) \
+sasl_server_plug_init_t x##_server_plug_init
+
+#define SPECIFIC_AUXPROP_PLUG_INIT_PROTO( x ) \
+sasl_auxprop_init_t x##_auxprop_plug_init
+
+#define SPECIFIC_CANONUSER_PLUG_INIT_PROTO( x ) \
+sasl_canonuser_init_t x##_canonuser_plug_init
+
+/* Static Compillation Foo */
+#define SPECIFIC_CLIENT_PLUG_INIT( x, n )\
+ { CLIENT, n, x##_client_plug_init }
+#define SPECIFIC_SERVER_PLUG_INIT( x, n )\
+ { SERVER, n, (sasl_client_plug_init_t *)x##_server_plug_init }
+#define SPECIFIC_AUXPROP_PLUG_INIT( x, n )\
+ { AUXPROP, n, (sasl_client_plug_init_t *)x##_auxprop_plug_init }
+#define SPECIFIC_CANONUSER_PLUG_INIT( x, n )\
+ { CANONUSER, n, (sasl_client_plug_init_t *)x##_canonuser_plug_init }
+
+#ifdef STATIC_ANONYMOUS
+extern SPECIFIC_SERVER_PLUG_INIT_PROTO( anonymous );
+extern SPECIFIC_CLIENT_PLUG_INIT_PROTO( anonymous );
+#endif
+#ifdef STATIC_CRAMMD5
+extern SPECIFIC_SERVER_PLUG_INIT_PROTO( crammd5 );
+extern SPECIFIC_CLIENT_PLUG_INIT_PROTO( crammd5 );
+#endif
+#ifdef STATIC_DIGESTMD5
+extern SPECIFIC_SERVER_PLUG_INIT_PROTO( digestmd5 );
+extern SPECIFIC_CLIENT_PLUG_INIT_PROTO( digestmd5 );
+#endif
+#ifdef STATIC_SCRAM
+extern SPECIFIC_SERVER_PLUG_INIT_PROTO( scram );
+extern SPECIFIC_CLIENT_PLUG_INIT_PROTO( scram );
+#endif
+#ifdef STATIC_GSSAPIV2
+extern SPECIFIC_SERVER_PLUG_INIT_PROTO( gssapiv2 );
+extern SPECIFIC_CLIENT_PLUG_INIT_PROTO( gssapiv2 );
+#endif
+#ifdef STATIC_KERBEROS4
+extern SPECIFIC_SERVER_PLUG_INIT_PROTO( kerberos4 );
+extern SPECIFIC_CLIENT_PLUG_INIT_PROTO( kerberos4 );
+#endif
+#ifdef STATIC_LOGIN
+extern SPECIFIC_SERVER_PLUG_INIT_PROTO( login );
+extern SPECIFIC_CLIENT_PLUG_INIT_PROTO( login );
+#endif
+#ifdef STATIC_NTLM
+extern SPECIFIC_SERVER_PLUG_INIT_PROTO( ntlm );
+extern SPECIFIC_CLIENT_PLUG_INIT_PROTO( ntlm );
+#endif
+#ifdef STATIC_OTP
+extern SPECIFIC_SERVER_PLUG_INIT_PROTO( otp );
+extern SPECIFIC_CLIENT_PLUG_INIT_PROTO( otp );
+#endif
+#ifdef STATIC_PLAIN
+extern SPECIFIC_SERVER_PLUG_INIT_PROTO( plain );
+extern SPECIFIC_CLIENT_PLUG_INIT_PROTO( plain );
+#endif
+#ifdef STATIC_SRP
+extern SPECIFIC_SERVER_PLUG_INIT_PROTO( srp );
+extern SPECIFIC_CLIENT_PLUG_INIT_PROTO( srp );
+#endif
+#ifdef STATIC_SASLDB
+extern SPECIFIC_AUXPROP_PLUG_INIT_PROTO( sasldb );
+#endif
+#ifdef STATIC_SQL
+extern SPECIFIC_AUXPROP_PLUG_INIT_PROTO( sql );
+#endif
+#ifdef STATIC_LDAPDB
+extern SPECIFIC_AUXPROP_PLUG_INIT_PROTO( ldapdb );
+#endif
+
+_sasl_plug_rec _sasl_static_plugins[] = {
+#ifdef STATIC_ANONYMOUS
+ SPECIFIC_SERVER_PLUG_INIT( anonymous, "ANONYMOUS" ),
+ SPECIFIC_CLIENT_PLUG_INIT( anonymous, "ANONYMOUS" ),
+#endif
+#ifdef STATIC_CRAMMD5
+ SPECIFIC_SERVER_PLUG_INIT( crammd5, "CRAM-MD5" ),
+ SPECIFIC_CLIENT_PLUG_INIT( crammd5, "CRAM-MD5" ),
+#endif
+#ifdef STATIC_DIGESTMD5
+ SPECIFIC_SERVER_PLUG_INIT( digestmd5, "DIGEST-MD5" ),
+ SPECIFIC_CLIENT_PLUG_INIT( digestmd5, "DIGEST-MD5" ),
+#endif
+#ifdef STATIC_GSSAPIV2
+ SPECIFIC_SERVER_PLUG_INIT( gssapiv2, "GSSAPI" ),
+ SPECIFIC_CLIENT_PLUG_INIT( gssapiv2, "GSSAPI" ),
+#endif
+#ifdef STATIC_KERBEROS4
+ SPECIFIC_SERVER_PLUG_INIT( kerberos4, "KERBEROS_V4" ),
+ SPECIFIC_CLIENT_PLUG_INIT( kerberos4, "KERBEROS_V4" ),
+#endif
+#ifdef STATIC_LOGIN
+ SPECIFIC_SERVER_PLUG_INIT( login, "LOGIN" ),
+ SPECIFIC_CLIENT_PLUG_INIT( login, "LOGIN" ),
+#endif
+#ifdef STATIC_NTLM
+ SPECIFIC_SERVER_PLUG_INIT( ntlm, "NTLM" ),
+ SPECIFIC_CLIENT_PLUG_INIT( ntlm, "NTLM" ),
+#endif
+#ifdef STATIC_OTP
+ SPECIFIC_SERVER_PLUG_INIT( otp, "OTP" ),
+ SPECIFIC_CLIENT_PLUG_INIT( otp, "OTP" ),
+#endif
+#ifdef STATIC_PLAIN
+ SPECIFIC_SERVER_PLUG_INIT( plain, "PLAIN" ),
+ SPECIFIC_CLIENT_PLUG_INIT( plain, "PLAIN" ),
+#endif
+#ifdef STATIC_SCRAM
+ SPECIFIC_SERVER_PLUG_INIT( scram, "SCRAM" ),
+ SPECIFIC_CLIENT_PLUG_INIT( scram, "SCRAM" ),
+#endif
+#ifdef STATIC_SRP
+ SPECIFIC_SERVER_PLUG_INIT( srp, "SRP" ),
+ SPECIFIC_CLIENT_PLUG_INIT( srp, "SRP" ),
+#endif
+#ifdef STATIC_SASLDB
+ SPECIFIC_AUXPROP_PLUG_INIT( sasldb, "SASLDB" ),
+#endif
+#ifdef STATIC_SQL
+ SPECIFIC_AUXPROP_PLUG_INIT( sql, "SQL" ),
+#endif
+#ifdef STATIC_LDAPDB
+ SPECIFIC_AUXPROP_PLUG_INIT( ldapdb, "LDAPDB" ),
+#endif
+ { UNKNOWN, NULL, NULL }
+};
diff --git a/contrib/libs/sasl/plugins/anonymous.c b/contrib/libs/sasl/plugins/anonymous.c
new file mode 100644
index 0000000000..a57266a746
--- /dev/null
+++ b/contrib/libs/sasl/plugins/anonymous.c
@@ -0,0 +1,387 @@
+/* Anonymous SASL plugin
+ * Rob Siemborski
+ * Tim Martin
+ */
+/*
+ * Copyright (c) 1998-2016 Carnegie Mellon University. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For permission or any other legal
+ * details, please contact
+ * Carnegie Mellon University
+ * Center for Technology Transfer and Enterprise Creation
+ * 4615 Forbes Avenue
+ * Suite 302
+ * Pittsburgh, PA 15213
+ * (412) 268-7393, fax: (412) 268-7395
+ * innovation@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Computing Services
+ * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <sasl.h>
+#include <saslplug.h>
+
+#include "plugin_common.h"
+
+#ifdef macintosh
+#error #include <sasl_anonymous_plugin_decl.h>
+#endif
+
+/***************************** Common Section *****************************/
+
+static const char anonymous_id[] = "anonymous";
+
+/***************************** Server Section *****************************/
+
+static int
+anonymous_server_mech_new(void *glob_context __attribute__((unused)),
+ sasl_server_params_t *sparams,
+ const char *challenge __attribute__((unused)),
+ unsigned challen __attribute__((unused)),
+ void **conn_context)
+{
+ /* holds state are in */
+ if (!conn_context) {
+ PARAMERROR( sparams->utils );
+ return SASL_BADPARAM;
+ }
+
+ *conn_context = NULL;
+
+ return SASL_OK;
+}
+
+static int
+anonymous_server_mech_step(void *conn_context __attribute__((unused)),
+ sasl_server_params_t *sparams,
+ const char *clientin,
+ unsigned clientinlen,
+ const char **serverout,
+ unsigned *serveroutlen,
+ sasl_out_params_t *oparams)
+{
+ char *clientdata;
+ int result;
+
+ if (!sparams
+ || !serverout
+ || !serveroutlen
+ || !oparams) {
+ if (sparams) PARAMERROR( sparams->utils );
+ return SASL_BADPARAM;
+ }
+
+ *serverout = NULL;
+ *serveroutlen = 0;
+
+ if (!clientin) {
+ return SASL_CONTINUE;
+ }
+
+ /* We force a truncation 255 characters (specified by RFC 2245) */
+ if (clientinlen > 255) clientinlen = 255;
+
+ /* NULL-terminate the clientin... */
+ clientdata = sparams->utils->malloc(clientinlen + 1);
+ if (!clientdata) {
+ MEMERROR(sparams->utils);
+ return SASL_NOMEM;
+ }
+
+ strncpy(clientdata, clientin, clientinlen);
+ clientdata[clientinlen] = '\0';
+
+ sparams->utils->log(sparams->utils->conn,
+ SASL_LOG_NOTE,
+ "ANONYMOUS login: \"%s\"",
+ clientdata);
+
+ if (clientdata != clientin)
+ sparams->utils->free(clientdata);
+
+ result = sparams->canon_user(sparams->utils->conn,
+ anonymous_id, 0,
+ SASL_CU_AUTHID | SASL_CU_AUTHZID, oparams);
+
+ if (result != SASL_OK) return result;
+
+ /* set oparams */
+ oparams->doneflag = 1;
+ oparams->mech_ssf = 0;
+ oparams->maxoutbuf = 0;
+ oparams->encode_context = NULL;
+ oparams->encode = NULL;
+ oparams->decode_context = NULL;
+ oparams->decode = NULL;
+ oparams->param_version = 0;
+
+ return SASL_OK;
+}
+
+static sasl_server_plug_t anonymous_server_plugins[] =
+{
+ {
+ "ANONYMOUS", /* mech_name */
+ 0, /* max_ssf */
+ SASL_SEC_NOPLAINTEXT, /* security_flags */
+ SASL_FEAT_WANT_CLIENT_FIRST
+ | SASL_FEAT_DONTUSE_USERPASSWD, /* features */
+ NULL, /* glob_context */
+ &anonymous_server_mech_new, /* mech_new */
+ &anonymous_server_mech_step, /* mech_step */
+ NULL, /* mech_dispose */
+ NULL, /* mech_free */
+ NULL, /* setpass */
+ NULL, /* user_query */
+ NULL, /* idle */
+ NULL, /* mech_avail */
+ NULL /* spare */
+ }
+};
+
+int anonymous_server_plug_init(const sasl_utils_t *utils,
+ int maxversion,
+ int *out_version,
+ sasl_server_plug_t **pluglist,
+ int *plugcount)
+{
+ if (maxversion < SASL_SERVER_PLUG_VERSION) {
+ SETERROR( utils, "ANONYMOUS version mismatch" );
+ return SASL_BADVERS;
+ }
+
+ *out_version = SASL_SERVER_PLUG_VERSION;
+ *pluglist = anonymous_server_plugins;
+ *plugcount = 1;
+
+ return SASL_OK;
+}
+
+/***************************** Client Section *****************************/
+
+typedef struct client_context {
+ char *out_buf;
+ unsigned out_buf_len;
+} client_context_t;
+
+static int
+anonymous_client_mech_new(void *glob_context __attribute__((unused)),
+ sasl_client_params_t *cparams,
+ void **conn_context)
+{
+ client_context_t *text;
+
+ if (!conn_context) {
+ PARAMERROR(cparams->utils);
+ return SASL_BADPARAM;
+ }
+
+ /* holds state are in */
+ text = cparams->utils->malloc(sizeof(client_context_t));
+ if (text == NULL) {
+ MEMERROR(cparams->utils);
+ return SASL_NOMEM;
+ }
+
+ memset(text, 0, sizeof(client_context_t));
+
+ *conn_context = text;
+
+ return SASL_OK;
+}
+
+static int
+anonymous_client_mech_step(void *conn_context,
+ sasl_client_params_t *cparams,
+ const char *serverin __attribute__((unused)),
+ unsigned serverinlen,
+ sasl_interact_t **prompt_need,
+ const char **clientout,
+ unsigned *clientoutlen,
+ sasl_out_params_t *oparams)
+{
+ client_context_t *text = (client_context_t *) conn_context;
+ size_t userlen;
+ char hostname[256];
+ const char *user = NULL;
+ int user_result = SASL_OK;
+ int result;
+
+ if (!cparams
+ || !clientout
+ || !clientoutlen
+ || !oparams) {
+ if (cparams) PARAMERROR( cparams->utils );
+ return SASL_BADPARAM;
+ }
+
+ *clientout = NULL;
+ *clientoutlen = 0;
+
+ if (serverinlen != 0) {
+ SETERROR( cparams->utils,
+ "Nonzero serverinlen in ANONYMOUS continue_step" );
+ return SASL_BADPROT;
+ }
+
+ /* check if sec layer strong enough */
+ if (cparams->props.min_ssf > cparams->external_ssf) {
+ SETERROR( cparams->utils, "SSF requested of ANONYMOUS plugin");
+ return SASL_TOOWEAK;
+ }
+
+ /* try to get the trace info */
+ if (user == NULL) {
+ user_result = _plug_get_userid(cparams->utils, &user, prompt_need);
+
+ if ((user_result != SASL_OK) && (user_result != SASL_INTERACT)) {
+ return user_result;
+ }
+ }
+
+ /* free prompts we got */
+ if (prompt_need && *prompt_need) {
+ cparams->utils->free(*prompt_need);
+ *prompt_need = NULL;
+ }
+
+ /* if there are prompts not filled in */
+ if (user_result == SASL_INTERACT) {
+ /* make the prompt list */
+ result =
+ _plug_make_prompts(cparams->utils, prompt_need,
+ "Please enter anonymous identification",
+ "",
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL);
+ if (result != SASL_OK) return result;
+
+ return SASL_INTERACT;
+ }
+
+ if (!user || !*user) {
+ user = anonymous_id;
+ }
+ userlen = strlen(user);
+
+ result = cparams->canon_user(cparams->utils->conn,
+ anonymous_id, 0,
+ SASL_CU_AUTHID | SASL_CU_AUTHZID, oparams);
+ if (result != SASL_OK) return result;
+
+ memset(hostname, 0, sizeof(hostname));
+ gethostname(hostname, sizeof(hostname));
+ hostname[sizeof(hostname)-1] = '\0';
+
+ *clientoutlen = (unsigned) (userlen + strlen(hostname) + 1);
+
+ result = _plug_buf_alloc(cparams->utils, &text->out_buf,
+ &text->out_buf_len, *clientoutlen);
+
+ if (result != SASL_OK) return result;
+
+ strcpy(text->out_buf, user);
+ text->out_buf[userlen] = '@';
+ /* use memcpy() instead of strcpy() so we don't add the NUL */
+ memcpy(text->out_buf + userlen + 1, hostname, strlen(hostname));
+
+ *clientout = text->out_buf;
+
+ /* set oparams */
+ oparams->doneflag = 1;
+ oparams->mech_ssf = 0;
+ oparams->maxoutbuf = 0;
+ oparams->encode_context = NULL;
+ oparams->encode = NULL;
+ oparams->decode_context = NULL;
+ oparams->decode = NULL;
+ oparams->param_version = 0;
+
+ return SASL_OK;
+}
+
+static void anonymous_client_dispose(void *conn_context,
+ const sasl_utils_t *utils)
+{
+ client_context_t *text = (client_context_t *) conn_context;
+
+ if(!text) return;
+
+ if (text->out_buf) utils->free(text->out_buf);
+
+ utils->free(text);
+}
+
+static const unsigned long anonymous_required_prompts[] = {
+ SASL_CB_LIST_END
+};
+
+static sasl_client_plug_t anonymous_client_plugins[] =
+{
+ {
+ "ANONYMOUS", /* mech_name */
+ 0, /* max_ssf */
+ SASL_SEC_NOPLAINTEXT, /* security_flags */
+ SASL_FEAT_WANT_CLIENT_FIRST, /* features */
+ anonymous_required_prompts, /* required_prompts */
+ NULL, /* glob_context */
+ &anonymous_client_mech_new, /* mech_new */
+ &anonymous_client_mech_step, /* mech_step */
+ &anonymous_client_dispose, /* mech_dispose */
+ NULL, /* mech_free */
+ NULL, /* idle */
+ NULL, /* spare */
+ NULL /* spare */
+ }
+};
+
+int anonymous_client_plug_init(const sasl_utils_t *utils,
+ int maxversion,
+ int *out_version,
+ sasl_client_plug_t **pluglist,
+ int *plugcount)
+{
+ if (maxversion < SASL_CLIENT_PLUG_VERSION) {
+ SETERROR( utils, "ANONYMOUS version mismatch" );
+ return SASL_BADVERS;
+ }
+
+ *out_version = SASL_CLIENT_PLUG_VERSION;
+ *pluglist = anonymous_client_plugins;
+ *plugcount = 1;
+
+ return SASL_OK;
+}
diff --git a/contrib/libs/sasl/plugins/cram.c b/contrib/libs/sasl/plugins/cram.c
new file mode 100644
index 0000000000..4d19a64068
--- /dev/null
+++ b/contrib/libs/sasl/plugins/cram.c
@@ -0,0 +1,687 @@
+/* CRAM-MD5 SASL plugin
+ * Rob Siemborski
+ * Tim Martin
+ */
+/*
+ * Copyright (c) 1998-2016 Carnegie Mellon University. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For permission or any other legal
+ * details, please contact
+ * Carnegie Mellon University
+ * Center for Technology Transfer and Enterprise Creation
+ * 4615 Forbes Avenue
+ * Suite 302
+ * Pittsburgh, PA 15213
+ * (412) 268-7393, fax: (412) 268-7395
+ * innovation@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Computing Services
+ * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#ifndef macintosh
+#include <sys/stat.h>
+#endif
+#include <fcntl.h>
+
+#include <sasl.h>
+#include <saslplug.h>
+#include <saslutil.h>
+
+#include "plugin_common.h"
+
+#ifdef macintosh
+#error #include <sasl_cram_plugin_decl.h>
+#endif
+
+/***************************** Common Section *****************************/
+
+/* convert a string of 8bit chars to it's representation in hex
+ * using lowercase letters
+ */
+static char *convert16(unsigned char *in, int inlen, const sasl_utils_t *utils)
+{
+ static char hex[]="0123456789abcdef";
+ int lup;
+ char *out;
+
+ out = utils->malloc(inlen*2+1);
+ if (out == NULL) return NULL;
+
+ for (lup=0; lup < inlen; lup++) {
+ out[lup*2] = hex[in[lup] >> 4];
+ out[lup*2+1] = hex[in[lup] & 15];
+ }
+
+ out[lup*2] = 0;
+ return out;
+}
+
+
+/***************************** Server Section *****************************/
+
+typedef struct server_context {
+ int state;
+
+ char *challenge;
+} server_context_t;
+
+static int
+crammd5_server_mech_new(void *glob_context __attribute__((unused)),
+ sasl_server_params_t *sparams,
+ const char *challenge __attribute__((unused)),
+ unsigned challen __attribute__((unused)),
+ void **conn_context)
+{
+ server_context_t *text;
+
+ /* holds state are in */
+ text = sparams->utils->malloc(sizeof(server_context_t));
+ if (text == NULL) {
+ MEMERROR( sparams->utils );
+ return SASL_NOMEM;
+ }
+
+ memset(text, 0, sizeof(server_context_t));
+
+ text->state = 1;
+
+ *conn_context = text;
+
+ return SASL_OK;
+}
+
+/*
+ * Returns the current time (or part of it) in string form
+ * maximum length=15
+ */
+static char *gettime(sasl_server_params_t *sparams)
+{
+ char *ret;
+ time_t t;
+
+ t=time(NULL);
+ ret= sparams->utils->malloc(15);
+ if (ret==NULL) return NULL;
+
+ /* the bottom bits are really the only random ones so if
+ we overflow we don't want to loose them */
+ snprintf(ret,15,"%lu",t%(0xFFFFFF));
+
+ return ret;
+}
+
+static char *randomdigits(sasl_server_params_t *sparams)
+{
+ unsigned int num;
+ char *ret;
+ unsigned char temp[5]; /* random 32-bit number */
+
+ sparams->utils->rand(sparams->utils->rpool,(char *) temp,4);
+ num=(temp[0] * 256 * 256 * 256) +
+ (temp[1] * 256 * 256) +
+ (temp[2] * 256) +
+ (temp[3] );
+
+ ret = sparams->utils->malloc(15); /* there's no way an unsigned can be longer than this right? */
+ if (ret == NULL) return NULL;
+ sprintf(ret, "%u", num);
+
+ return ret;
+}
+
+static int
+crammd5_server_mech_step1(server_context_t *text,
+ sasl_server_params_t *sparams,
+ const char *clientin __attribute__((unused)),
+ unsigned clientinlen,
+ const char **serverout,
+ unsigned *serveroutlen,
+ sasl_out_params_t *oparams __attribute__((unused)))
+{
+ char *time, *randdigits;
+
+ /* we shouldn't have received anything */
+ if (clientinlen != 0) {
+ SETERROR(sparams->utils, "CRAM-MD5 does not accept inital data");
+ return SASL_BADPROT;
+ }
+
+ /* get time and a random number for the nonce */
+ time = gettime(sparams);
+ randdigits = randomdigits(sparams);
+ if ((time == NULL) || (randdigits == NULL)) {
+ MEMERROR( sparams->utils );
+ return SASL_NOMEM;
+ }
+
+ /* allocate some space for the challenge */
+ text->challenge = sparams->utils->malloc(200 + 1);
+ if (text->challenge == NULL) {
+ MEMERROR(sparams->utils);
+ return SASL_NOMEM;
+ }
+
+ /* create the challenge */
+ snprintf(text->challenge, 200, "<%s.%s@%s>", randdigits, time,
+ sparams->serverFQDN);
+
+ *serverout = text->challenge;
+ *serveroutlen = (unsigned) strlen(text->challenge);
+
+ /* free stuff */
+ sparams->utils->free(time);
+ sparams->utils->free(randdigits);
+
+ text->state = 2;
+
+ return SASL_CONTINUE;
+}
+
+static int
+crammd5_server_mech_step2(server_context_t *text,
+ sasl_server_params_t *sparams,
+ const char *clientin,
+ unsigned clientinlen,
+ const char **serverout __attribute__((unused)),
+ unsigned *serveroutlen __attribute__((unused)),
+ sasl_out_params_t *oparams)
+{
+ char *userid = NULL;
+ sasl_secret_t *sec = NULL;
+ int pos;
+ size_t len;
+ int result = SASL_FAIL;
+ const char *password_request[] = { SASL_AUX_PASSWORD,
+#if defined(OBSOLETE_CRAM_ATTR)
+ "*cmusaslsecretCRAM-MD5",
+#endif
+ NULL };
+ struct propval auxprop_values[3];
+ HMAC_MD5_CTX tmphmac;
+ HMAC_MD5_STATE md5state;
+ int clear_md5state = 0;
+ char *digest_str = NULL;
+ SASL_UINT4 digest[4];
+
+ /* extract userid; everything before last space */
+ pos = clientinlen-1;
+ while ((pos > 0) && (clientin[pos] != ' ')) pos--;
+
+ if (pos <= 0) {
+ SETERROR( sparams->utils,"need authentication name");
+ return SASL_BADPROT;
+ }
+
+ userid = (char *) sparams->utils->malloc(pos+1);
+ if (userid == NULL) {
+ MEMERROR( sparams->utils);
+ return SASL_NOMEM;
+ }
+
+ /* copy authstr out */
+ memcpy(userid, clientin, pos);
+ userid[pos] = '\0';
+
+ result = sparams->utils->prop_request(sparams->propctx, password_request);
+ if (result != SASL_OK) goto done;
+
+ /* this will trigger the getting of the aux properties */
+ result = sparams->canon_user(sparams->utils->conn,
+ userid, 0, SASL_CU_AUTHID | SASL_CU_AUTHZID,
+ oparams);
+ if (result != SASL_OK) goto done;
+
+ result = sparams->utils->prop_getnames(sparams->propctx,
+ password_request,
+ auxprop_values);
+ if (result < 0 ||
+ ((!auxprop_values[0].name || !auxprop_values[0].values)
+#if defined(OBSOLETE_CRAM_ATTR)
+ && (!auxprop_values[1].name || !auxprop_values[1].values)
+#endif
+ )) {
+ /* We didn't find this username */
+ sparams->utils->seterror(sparams->utils->conn,0,
+ "no secret in database");
+ result = sparams->transition ? SASL_TRANS : SASL_NOUSER;
+ goto done;
+ }
+
+ if (auxprop_values[0].name && auxprop_values[0].values) {
+ len = strlen(auxprop_values[0].values[0]);
+ if (len == 0) {
+ sparams->utils->seterror(sparams->utils->conn,0,
+ "empty secret");
+ result = SASL_FAIL;
+ goto done;
+ }
+
+ sec = sparams->utils->malloc(sizeof(sasl_secret_t) + len);
+ if (!sec) goto done;
+
+ sec->len = (unsigned) len;
+ strncpy((char *)sec->data, auxprop_values[0].values[0], len + 1);
+
+ clear_md5state = 1;
+ /* Do precalculation on plaintext secret */
+ sparams->utils->hmac_md5_precalc(&md5state, /* OUT */
+ sec->data,
+ sec->len);
+#if defined(OBSOLETE_CRAM_ATTR)
+ } else if (auxprop_values[1].name && auxprop_values[1].values) {
+ /* We have a precomputed secret */
+ memcpy(&md5state, auxprop_values[1].values[0],
+ sizeof(HMAC_MD5_STATE));
+#endif
+ } else {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "Have neither type of secret");
+ return SASL_FAIL;
+ }
+
+ /* erase the plaintext password */
+ sparams->utils->prop_erase(sparams->propctx, password_request[0]);
+
+ /* ok this is annoying:
+ so we have this half-way hmac transform instead of the plaintext
+ that means we half to:
+ -import it back into a md5 context
+ -do an md5update with the nonce
+ -finalize it
+ */
+ sparams->utils->hmac_md5_import(&tmphmac, (HMAC_MD5_STATE *) &md5state);
+ sparams->utils->MD5Update(&(tmphmac.ictx),
+ (const unsigned char *) text->challenge,
+ (unsigned) strlen(text->challenge));
+ sparams->utils->hmac_md5_final((unsigned char *) &digest, &tmphmac);
+
+ /* convert to base 16 with lower case letters */
+ digest_str = convert16((unsigned char *) digest, 16, sparams->utils);
+
+ /* if same then verified
+ * - we know digest_str is null terminated but clientin might not be
+ * - verify the length of clientin anyway!
+ */
+ len = strlen(digest_str);
+ if (clientinlen-pos-1 < len ||
+ strncmp(digest_str, clientin+pos+1, len) != 0) {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "incorrect digest response");
+ result = SASL_BADAUTH;
+ goto done;
+ }
+
+ /* set oparams */
+ oparams->doneflag = 1;
+ oparams->mech_ssf = 0;
+ oparams->maxoutbuf = 0;
+ oparams->encode_context = NULL;
+ oparams->encode = NULL;
+ oparams->decode_context = NULL;
+ oparams->decode = NULL;
+ oparams->param_version = 0;
+
+ result = SASL_OK;
+
+ done:
+ if (userid) sparams->utils->free(userid);
+ if (sec) _plug_free_secret(sparams->utils, &sec);
+
+ if (digest_str) sparams->utils->free(digest_str);
+ if (clear_md5state) memset(&md5state, 0, sizeof(md5state));
+
+ return result;
+}
+
+static int crammd5_server_mech_step(void *conn_context,
+ sasl_server_params_t *sparams,
+ const char *clientin,
+ unsigned clientinlen,
+ const char **serverout,
+ unsigned *serveroutlen,
+ sasl_out_params_t *oparams)
+{
+ server_context_t *text = (server_context_t *) conn_context;
+
+ *serverout = NULL;
+ *serveroutlen = 0;
+
+ if (text == NULL) {
+ return SASL_BADPROT;
+ }
+
+ /* this should be well more than is ever needed */
+ if (clientinlen > 1024) {
+ SETERROR(sparams->utils, "CRAM-MD5 input longer than 1024 bytes");
+ return SASL_BADPROT;
+ }
+
+ switch (text->state) {
+
+ case 1:
+ return crammd5_server_mech_step1(text, sparams,
+ clientin, clientinlen,
+ serverout, serveroutlen,
+ oparams);
+
+ case 2:
+ return crammd5_server_mech_step2(text, sparams,
+ clientin, clientinlen,
+ serverout, serveroutlen,
+ oparams);
+
+ default: /* should never get here */
+ sparams->utils->log(NULL, SASL_LOG_ERR,
+ "Invalid CRAM-MD5 server step %d\n", text->state);
+ return SASL_FAIL;
+ }
+
+ return SASL_FAIL; /* should never get here */
+}
+
+static void crammd5_server_mech_dispose(void *conn_context,
+ const sasl_utils_t *utils)
+{
+ server_context_t *text = (server_context_t *) conn_context;
+
+ if (!text) return;
+
+ if (text->challenge) _plug_free_string(utils,&(text->challenge));
+
+ utils->free(text);
+}
+
+static sasl_server_plug_t crammd5_server_plugins[] =
+{
+ {
+ "CRAM-MD5", /* mech_name */
+ 0, /* max_ssf */
+ SASL_SEC_NOPLAINTEXT
+ | SASL_SEC_NOANONYMOUS, /* security_flags */
+ SASL_FEAT_SERVER_FIRST, /* features */
+ NULL, /* glob_context */
+ &crammd5_server_mech_new, /* mech_new */
+ &crammd5_server_mech_step, /* mech_step */
+ &crammd5_server_mech_dispose, /* mech_dispose */
+ NULL, /* mech_free */
+ NULL, /* setpass */
+ NULL, /* user_query */
+ NULL, /* idle */
+ NULL, /* mech avail */
+ NULL /* spare */
+ }
+};
+
+int crammd5_server_plug_init(const sasl_utils_t *utils,
+ int maxversion,
+ int *out_version,
+ sasl_server_plug_t **pluglist,
+ int *plugcount)
+{
+ if (maxversion < SASL_SERVER_PLUG_VERSION) {
+ SETERROR( utils, "CRAM version mismatch");
+ return SASL_BADVERS;
+ }
+
+ *out_version = SASL_SERVER_PLUG_VERSION;
+ *pluglist = crammd5_server_plugins;
+ *plugcount = 1;
+
+ return SASL_OK;
+}
+
+/***************************** Client Section *****************************/
+
+typedef struct client_context {
+ char *out_buf;
+ unsigned out_buf_len;
+} client_context_t;
+
+static int crammd5_client_mech_new(void *glob_context __attribute__((unused)),
+ sasl_client_params_t *params,
+ void **conn_context)
+{
+ client_context_t *text;
+
+ /* holds state are in */
+ text = params->utils->malloc(sizeof(client_context_t));
+ if (text == NULL) {
+ MEMERROR(params->utils);
+ return SASL_NOMEM;
+ }
+
+ memset(text, 0, sizeof(client_context_t));
+
+ *conn_context = text;
+
+ return SASL_OK;
+}
+
+static char *make_hashed(sasl_secret_t *sec, char *nonce, int noncelen,
+ const sasl_utils_t *utils)
+{
+ unsigned char digest[24];
+ char *in16;
+
+ if (sec == NULL) return NULL;
+
+ /* do the hmac md5 hash output 128 bits */
+ utils->hmac_md5((unsigned char *) nonce, noncelen,
+ sec->data, sec->len, digest);
+
+ /* convert that to hex form */
+ in16 = convert16(digest, 16, utils);
+ if (in16 == NULL) return NULL;
+
+ return in16;
+}
+
+static int crammd5_client_mech_step(void *conn_context,
+ sasl_client_params_t *params,
+ const char *serverin,
+ unsigned serverinlen,
+ sasl_interact_t **prompt_need,
+ const char **clientout,
+ unsigned *clientoutlen,
+ sasl_out_params_t *oparams)
+{
+ client_context_t *text = (client_context_t *) conn_context;
+ const char *authid = NULL;
+ sasl_secret_t *password = NULL;
+ unsigned int free_password = 0; /* set if we need to free password */
+ int auth_result = SASL_OK;
+ int pass_result = SASL_OK;
+ int result;
+ size_t maxsize;
+ char *in16 = NULL;
+
+ *clientout = NULL;
+ *clientoutlen = 0;
+
+ /* First check for absurd lengths */
+ if (serverinlen > 1024) {
+ params->utils->seterror(params->utils->conn, 0,
+ "CRAM-MD5 input longer than 1024 bytes");
+ return SASL_BADPROT;
+ }
+
+ /* check if sec layer strong enough */
+ if (params->props.min_ssf > params->external_ssf) {
+ SETERROR( params->utils, "SSF requested of CRAM-MD5 plugin");
+ return SASL_TOOWEAK;
+ }
+
+ /* try to get the userid */
+ if (oparams->authid == NULL) {
+ auth_result=_plug_get_authid(params->utils, &authid, prompt_need);
+
+ if ((auth_result != SASL_OK) && (auth_result != SASL_INTERACT))
+ return auth_result;
+ }
+
+ /* try to get the password */
+ if (password == NULL) {
+ pass_result=_plug_get_password(params->utils, &password,
+ &free_password, prompt_need);
+
+ if ((pass_result != SASL_OK) && (pass_result != SASL_INTERACT))
+ return pass_result;
+ }
+
+ /* free prompts we got */
+ if (prompt_need && *prompt_need) {
+ params->utils->free(*prompt_need);
+ *prompt_need = NULL;
+ }
+
+ /* if there are prompts not filled in */
+ if ((auth_result == SASL_INTERACT) || (pass_result == SASL_INTERACT)) {
+ /* make the prompt list */
+ result =
+ _plug_make_prompts(params->utils, prompt_need,
+ NULL, NULL,
+ auth_result == SASL_INTERACT ?
+ "Please enter your authentication name" : NULL,
+ NULL,
+ pass_result == SASL_INTERACT ?
+ "Please enter your password" : NULL, NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL);
+ if (result != SASL_OK) goto cleanup;
+
+ return SASL_INTERACT;
+ }
+
+ if (!password) {
+ PARAMERROR(params->utils);
+ return SASL_BADPARAM;
+ }
+
+ result = params->canon_user(params->utils->conn, authid, 0,
+ SASL_CU_AUTHID | SASL_CU_AUTHZID, oparams);
+ if (result != SASL_OK) goto cleanup;
+
+ /*
+ * username SP digest (keyed md5 where key is passwd)
+ */
+
+ in16 = make_hashed(password, (char *) serverin, serverinlen,
+ params->utils);
+
+ if (in16 == NULL) {
+ SETERROR(params->utils, "whoops, make_hashed failed us this time");
+ result = SASL_FAIL;
+ goto cleanup;
+ }
+
+ maxsize = 32+1+strlen(oparams->authid)+30;
+ result = _plug_buf_alloc(params->utils, &(text->out_buf),
+ &(text->out_buf_len), (unsigned) maxsize);
+ if (result != SASL_OK) goto cleanup;
+
+ snprintf(text->out_buf, maxsize, "%s %s", oparams->authid, in16);
+
+ *clientout = text->out_buf;
+ *clientoutlen = (unsigned) strlen(*clientout);
+
+ /* set oparams */
+ oparams->doneflag = 1;
+ oparams->mech_ssf = 0;
+ oparams->maxoutbuf = 0;
+ oparams->encode_context = NULL;
+ oparams->encode = NULL;
+ oparams->decode_context = NULL;
+ oparams->decode = NULL;
+ oparams->param_version = 0;
+
+ result = SASL_OK;
+
+ cleanup:
+ /* get rid of private information */
+ if (in16) _plug_free_string(params->utils, &in16);
+
+ /* get rid of all sensitive info */
+ if (free_password) _plug_free_secret(params-> utils, &password);
+
+ return result;
+}
+
+static void crammd5_client_mech_dispose(void *conn_context,
+ const sasl_utils_t *utils)
+{
+ client_context_t *text = (client_context_t *) conn_context;
+
+ if (!text) return;
+
+ if (text->out_buf) utils->free(text->out_buf);
+
+ utils->free(text);
+}
+
+static sasl_client_plug_t crammd5_client_plugins[] =
+{
+ {
+ "CRAM-MD5", /* mech_name */
+ 0, /* max_ssf */
+ SASL_SEC_NOPLAINTEXT
+ | SASL_SEC_NOANONYMOUS, /* security_flags */
+ SASL_FEAT_SERVER_FIRST, /* features */
+ NULL, /* required_prompts */
+ NULL, /* glob_context */
+ &crammd5_client_mech_new, /* mech_new */
+ &crammd5_client_mech_step, /* mech_step */
+ &crammd5_client_mech_dispose, /* mech_dispose */
+ NULL, /* mech_free */
+ NULL, /* idle */
+ NULL, /* spare */
+ NULL /* spare */
+ }
+};
+
+int crammd5_client_plug_init(const sasl_utils_t *utils,
+ int maxversion,
+ int *out_version,
+ sasl_client_plug_t **pluglist,
+ int *plugcount)
+{
+ if (maxversion < SASL_CLIENT_PLUG_VERSION) {
+ SETERROR( utils, "CRAM version mismatch");
+ return SASL_BADVERS;
+ }
+
+ *out_version = SASL_CLIENT_PLUG_VERSION;
+ *pluglist = crammd5_client_plugins;
+ *plugcount = 1;
+
+ return SASL_OK;
+}
diff --git a/contrib/libs/sasl/plugins/digestmd5.c b/contrib/libs/sasl/plugins/digestmd5.c
new file mode 100644
index 0000000000..59f87135f6
--- /dev/null
+++ b/contrib/libs/sasl/plugins/digestmd5.c
@@ -0,0 +1,4778 @@
+/* DIGEST-MD5 SASL plugin
+ * Ken Murchison
+ * Rob Siemborski
+ * Tim Martin
+ * Alexey Melnikov
+ */
+/*
+ * Copyright (c) 1998-2016 Carnegie Mellon University. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For permission or any other legal
+ * details, please contact
+ * Carnegie Mellon University
+ * Center for Technology Transfer and Enterprise Creation
+ * 4615 Forbes Avenue
+ * Suite 302
+ * Pittsburgh, PA 15213
+ * (412) 268-7393, fax: (412) 268-7395
+ * innovation@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Computing Services
+ * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#ifndef macintosh
+#include <sys/types.h>
+#include <sys/stat.h>
+#endif
+#include <fcntl.h>
+#include <ctype.h>
+
+/* DES support */
+#ifdef WITH_DES
+# ifdef WITH_SSL_DES
+# include <openssl/des.h>
+# include <openssl/opensslv.h>
+# if (OPENSSL_VERSION_NUMBER >= 0x0090700f) && \
+ !defined(OPENSSL_ENABLE_OLD_DES_SUPPORT)
+# define des_cblock DES_cblock
+# define des_key_schedule DES_key_schedule
+# define des_key_sched(k,ks) \
+ DES_key_sched((k),&(ks))
+# define des_cbc_encrypt(i,o,l,k,iv,e) \
+ DES_cbc_encrypt((i),(o),(l),&(k),(iv),(e))
+# define des_ede2_cbc_encrypt(i,o,l,k1,k2,iv,e) \
+ DES_ede2_cbc_encrypt((i),(o),(l),&(k1),&(k2),(iv),(e))
+# endif /* OpenSSL 0.9.7+ w/o old DES support */
+# else /* system DES library */
+#ifdef HAVE_DES_H
+# error #include <des.h>
+#endif
+# endif
+#endif /* WITH_DES */
+
+#ifdef WIN32
+# include <winsock2.h>
+#else /* Unix */
+# include <netinet/in.h>
+#endif /* WIN32 */
+
+#include <sasl.h>
+#include <saslplug.h>
+
+#include "plugin_common.h"
+
+#ifndef WIN32
+extern int strcasecmp(const char *s1, const char *s2);
+#endif /* end WIN32 */
+
+#ifdef macintosh
+#error #include <sasl_md5_plugin_decl.h>
+#endif
+
+/* external definitions */
+
+#define bool int
+
+#ifndef TRUE
+#define TRUE (1)
+#define FALSE (0)
+#endif
+
+/* MAX_UIN32_DIV_10 * 10 + MAX_UIN32_MOD_10 == 2^32-1 == 4294967295 */
+#define MAX_UIN32_DIV_10 429496729
+#define MAX_UIN32_MOD_10 5
+
+#define DEFAULT_BUFSIZE 0xFFFF
+#define MAX_SASL_BUFSIZE 0xFFFFFF
+
+/***************************** Common Section *****************************/
+
+/* Definitions */
+#define NONCE_SIZE (32) /* arbitrary */
+
+/* Layer Flags */
+#define DIGEST_NOLAYER (1)
+#define DIGEST_INTEGRITY (2)
+#define DIGEST_PRIVACY (4)
+
+/* defines */
+#define HASHLEN 16
+typedef unsigned char HASH[HASHLEN + 1];
+#define HASHHEXLEN 32
+typedef unsigned char HASHHEX[HASHHEXLEN + 1];
+
+#define MAC_SIZE 10
+#define MAC_OFFS 2
+
+const char *SEALING_CLIENT_SERVER="Digest H(A1) to client-to-server sealing key magic constant";
+const char *SEALING_SERVER_CLIENT="Digest H(A1) to server-to-client sealing key magic constant";
+
+const char *SIGNING_CLIENT_SERVER="Digest session key to client-to-server signing key magic constant";
+const char *SIGNING_SERVER_CLIENT="Digest session key to server-to-client signing key magic constant";
+
+#define HT (9)
+#define CR (13)
+#define LF (10)
+#define SP (32)
+#define DEL (127)
+
+#define NEED_ESCAPING "\"\\"
+
+#define REALM_CHAL_PREFIX "Available realms:"
+
+static char *quote (char *str);
+
+struct context;
+
+/* function definitions for cipher encode/decode */
+typedef int cipher_function_t(struct context *,
+ const char *,
+ unsigned,
+ unsigned char[],
+ char *,
+ unsigned *);
+
+typedef int cipher_init_t(struct context *, unsigned char [16],
+ unsigned char [16]);
+typedef void cipher_free_t(struct context *);
+
+enum Context_type { SERVER = 0, CLIENT = 1 };
+
+typedef struct cipher_context cipher_context_t;
+
+/* cached auth info used for fast reauth */
+typedef struct reauth_entry {
+ char *authid;
+ char *realm;
+ unsigned char *nonce;
+ unsigned int nonce_count;
+ unsigned char *cnonce;
+
+ union {
+ struct {
+ time_t timestamp;
+ } s; /* server stuff */
+
+ struct {
+ char *serverFQDN;
+ int protection;
+ struct digest_cipher *cipher;
+ unsigned long server_maxbuf;
+
+ /* for HTTP mode (RFC 2617) only */
+ char *algorithm;
+ unsigned char *opaque;
+ } c; /* client stuff */
+ } u;
+} reauth_entry_t;
+
+typedef struct reauth_cache {
+ /* static stuff */
+ enum Context_type i_am; /* are we the client or server? */
+ time_t timeout;
+ void *mutex;
+ unsigned size;
+
+ reauth_entry_t *e; /* fixed-size hash table of entries */
+} reauth_cache_t;
+
+/* global context for reauth use */
+typedef struct digest_glob_context {
+ reauth_cache_t *reauth;
+} digest_glob_context_t;
+
+/* context that stores info */
+typedef struct context {
+ int state; /* state in the authentication we are in */
+ enum Context_type i_am; /* are we the client or server? */
+ int http_mode; /* use RFC 2617 compatible protocol? */
+
+ reauth_cache_t *reauth;
+
+ char *authid;
+ char *realm;
+ unsigned char *nonce;
+ unsigned int nonce_count;
+ unsigned char *cnonce;
+
+ /* only used by the client */
+ char ** realms;
+ int realm_cnt;
+
+ char *response_value;
+
+ unsigned int seqnum;
+ unsigned int rec_seqnum; /* for checking integrity */
+
+ HASH Ki_send;
+ HASH Ki_receive;
+
+ HASH HA1; /* Kcc or Kcs */
+
+ /* copy of utils from the params structures */
+ const sasl_utils_t *utils;
+
+ /* For general use */
+ char *out_buf;
+ unsigned out_buf_len;
+
+ /* for encoding/decoding */
+ buffer_info_t *enc_in_buf;
+ char *encode_buf, *decode_buf, *decode_packet_buf;
+ unsigned encode_buf_len, decode_buf_len, decode_packet_buf_len;
+
+ decode_context_t decode_context;
+
+ /* if privacy mode is used use these functions for encode and decode */
+ cipher_function_t *cipher_enc;
+ cipher_function_t *cipher_dec;
+ cipher_init_t *cipher_init;
+ cipher_free_t *cipher_free;
+ struct cipher_context *cipher_enc_context;
+ struct cipher_context *cipher_dec_context;
+} context_t;
+
+struct digest_cipher {
+ char *name;
+ sasl_ssf_t ssf;
+ int n; /* bits to make privacy key */
+ int flag; /* a bitmask to make things easier for us */
+
+ cipher_function_t *cipher_enc;
+ cipher_function_t *cipher_dec;
+ cipher_init_t *cipher_init;
+ cipher_free_t *cipher_free;
+};
+#if 0
+static const unsigned char *COLON = ":";
+#else
+static const unsigned char COLON[] = { ':', '\0' };
+#endif
+/* Hashes a string to produce an unsigned short */
+static unsigned hash(const char *str)
+{
+ unsigned val = 0;
+ int i;
+
+ while (str && *str) {
+ i = (int) *str;
+ val ^= i;
+ val <<= 1;
+ str++;
+ }
+
+ return val;
+}
+
+static void CvtHex(HASH Bin, HASHHEX Hex)
+{
+ unsigned short i;
+ unsigned char j;
+
+ for (i = 0; i < HASHLEN; i++) {
+ j = (Bin[i] >> 4) & 0xf;
+ if (j <= 9)
+ Hex[i * 2] = (j + '0');
+ else
+ Hex[i * 2] = (j + 'a' - 10);
+ j = Bin[i] & 0xf;
+ if (j <= 9)
+ Hex[i * 2 + 1] = (j + '0');
+ else
+ Hex[i * 2 + 1] = (j + 'a' - 10);
+ }
+ Hex[HASHHEXLEN] = '\0';
+}
+
+/*
+ * calculate request-digest/response-digest as per HTTP Digest spec
+ */
+void
+DigestCalcResponse(const sasl_utils_t * utils,
+ HASHHEX HA1, /* HEX(H(A1)) */
+ unsigned char *pszNonce, /* nonce from server */
+ unsigned int pszNonceCount, /* 8 hex digits */
+ unsigned char *pszCNonce, /* client nonce */
+ unsigned char *pszQop, /* qop-value: "", "auth",
+ * "auth-int" */
+ unsigned char *pszDigestUri, /* requested URL */
+ unsigned char *pszMethod,
+ HASHHEX HEntity, /* H(entity body) if qop="auth-int" */
+ HASHHEX Response /* request-digest or response-digest */
+ )
+{
+ MD5_CTX Md5Ctx;
+ HASH HA2;
+ HASH RespHash;
+ HASHHEX HA2Hex;
+ unsigned char ncvalue[10];
+
+ /* calculate H(A2) */
+ utils->MD5Init(&Md5Ctx);
+
+ if (pszMethod != NULL) {
+ utils->MD5Update(&Md5Ctx, pszMethod, (unsigned) strlen((char *) pszMethod));
+ }
+ utils->MD5Update(&Md5Ctx, (unsigned char *) COLON, 1);
+
+ /* utils->MD5Update(&Md5Ctx, (unsigned char *) "AUTHENTICATE:", 13); */
+ utils->MD5Update(&Md5Ctx, pszDigestUri, (unsigned) strlen((char *) pszDigestUri));
+ if (strcasecmp((char *) pszQop, "auth") != 0) {
+ /* append ":00000000000000000000000000000000" */
+ utils->MD5Update(&Md5Ctx, COLON, 1);
+ utils->MD5Update(&Md5Ctx, HEntity, HASHHEXLEN);
+ }
+ utils->MD5Final(HA2, &Md5Ctx);
+ CvtHex(HA2, HA2Hex);
+
+ /* calculate response */
+ utils->MD5Init(&Md5Ctx);
+ utils->MD5Update(&Md5Ctx, HA1, HASHHEXLEN);
+ utils->MD5Update(&Md5Ctx, COLON, 1);
+ utils->MD5Update(&Md5Ctx, pszNonce, (unsigned) strlen((char *) pszNonce));
+ utils->MD5Update(&Md5Ctx, COLON, 1);
+ if (*pszQop) {
+ sprintf((char *)ncvalue, "%08x", pszNonceCount);
+ utils->MD5Update(&Md5Ctx, ncvalue, (unsigned) strlen((char *)ncvalue));
+ utils->MD5Update(&Md5Ctx, COLON, 1);
+ utils->MD5Update(&Md5Ctx, pszCNonce, (unsigned) strlen((char *) pszCNonce));
+ utils->MD5Update(&Md5Ctx, COLON, 1);
+ utils->MD5Update(&Md5Ctx, pszQop, (unsigned) strlen((char *) pszQop));
+ utils->MD5Update(&Md5Ctx, COLON, 1);
+ }
+ utils->MD5Update(&Md5Ctx, HA2Hex, HASHHEXLEN);
+ utils->MD5Final(RespHash, &Md5Ctx);
+ CvtHex(RespHash, Response);
+}
+
+static bool UTF8_In_8859_1(const unsigned char *base, size_t len)
+{
+ const unsigned char *scan, *end;
+
+ end = base + len;
+ for (scan = base; scan < end; ++scan) {
+ if (*scan > 0xC3)
+ break; /* abort if outside 8859-1 */
+ if (*scan >= 0xC0 && *scan <= 0xC3) {
+ if (++scan == end || *scan < 0x80 || *scan > 0xBF)
+ break;
+ }
+ }
+
+ /* if scan >= end, then this is a 8859-1 string. */
+ return (scan >= end);
+}
+
+/*
+ * if the string is entirely in the 8859-1 subset of UTF-8, then translate to
+ * 8859-1 prior to MD5
+ */
+static void MD5_UTF8_8859_1(const sasl_utils_t * utils,
+ MD5_CTX * ctx,
+ bool In_ISO_8859_1,
+ const unsigned char *base,
+ int len)
+{
+ const unsigned char *scan, *end;
+ unsigned char cbuf;
+
+ end = base + len;
+
+ /* if we found a character outside 8859-1, don't alter string */
+ if (!In_ISO_8859_1) {
+ utils->MD5Update(ctx, base, len);
+ return;
+ }
+ /* convert to 8859-1 prior to applying hash */
+ do {
+ for (scan = base; scan < end && *scan < 0xC0; ++scan);
+ if (scan != base)
+ utils->MD5Update(ctx, base, (unsigned) (scan - base));
+ if (scan + 1 >= end)
+ break;
+ cbuf = ((scan[0] & 0x3) << 6) | (scan[1] & 0x3f);
+ utils->MD5Update(ctx, &cbuf, 1);
+ base = scan + 2;
+ }
+ while (base < end);
+}
+
+/**
+ * Returns true if it mangled the username.
+ */
+static bool DigestCalcSecret(const sasl_utils_t * utils,
+ unsigned char *pszUserName,
+ unsigned char *pszRealm,
+ unsigned char *Password,
+ int PasswordLen,
+ bool Ignore_8859,
+ HASH HA1)
+{
+ bool In_8859_1;
+ bool Any_8859_1 = FALSE;
+ MD5_CTX Md5Ctx;
+
+ /* Chris Newman clarified that the following text in DIGEST-MD5 spec
+ is bogus: "if name and password are both in ISO 8859-1 charset"
+ We shoud use code example instead */
+
+ utils->MD5Init(&Md5Ctx);
+
+ /* We have to convert UTF-8 to ISO-8859-1 if possible */
+ if (Ignore_8859 == FALSE) {
+ In_8859_1 = UTF8_In_8859_1(pszUserName, strlen((char *) pszUserName));
+ MD5_UTF8_8859_1(utils, &Md5Ctx, In_8859_1,
+ pszUserName, (unsigned) strlen((char *) pszUserName));
+ Any_8859_1 |= In_8859_1;
+ } else {
+ utils->MD5Update(&Md5Ctx, pszUserName, (unsigned) strlen((char *) pszUserName));
+ }
+
+ utils->MD5Update(&Md5Ctx, COLON, 1);
+
+ /* a NULL realm is equivalent to the empty string */
+ if (pszRealm != NULL && pszRealm[0] != '\0') {
+ if (Ignore_8859 == FALSE) {
+ /* We have to convert UTF-8 to ISO-8859-1 if possible */
+ In_8859_1 = UTF8_In_8859_1(pszRealm, strlen((char *) pszRealm));
+ MD5_UTF8_8859_1(utils, &Md5Ctx, In_8859_1,
+ pszRealm, (unsigned) strlen((char *) pszRealm));
+ Any_8859_1 |= In_8859_1;
+ } else {
+ utils->MD5Update(&Md5Ctx, pszRealm, (unsigned) strlen((char *) pszRealm));
+ }
+ }
+
+ utils->MD5Update(&Md5Ctx, COLON, 1);
+
+ if (Ignore_8859 == FALSE) {
+ /* We have to convert UTF-8 to ISO-8859-1 if possible */
+ In_8859_1 = UTF8_In_8859_1(Password, PasswordLen);
+ MD5_UTF8_8859_1(utils, &Md5Ctx, In_8859_1,
+ Password, PasswordLen);
+ Any_8859_1 |= In_8859_1;
+ } else {
+ utils->MD5Update(&Md5Ctx, Password, PasswordLen);
+ }
+ utils->MD5Final(HA1, &Md5Ctx);
+
+ return Any_8859_1;
+}
+
+static unsigned char *create_nonce(const sasl_utils_t * utils)
+{
+ unsigned char *base64buf;
+ int base64len;
+
+ char *ret = (char *) utils->malloc(NONCE_SIZE);
+ if (ret == NULL)
+ return NULL;
+
+ utils->rand(utils->rpool, (char *) ret, NONCE_SIZE);
+
+ /* base 64 encode it so it has valid chars */
+ base64len = (NONCE_SIZE * 4 / 3) + (NONCE_SIZE % 3 ? 4 : 0);
+
+ base64buf = (unsigned char *) utils->malloc(base64len + 1);
+ if (base64buf == NULL) {
+ utils->seterror(utils->conn, 0, "Unable to allocate final buffer");
+ return NULL;
+ }
+
+ /*
+ * Returns SASL_OK on success, SASL_BUFOVER if result won't fit
+ */
+ if (utils->encode64(ret, NONCE_SIZE,
+ (char *) base64buf, base64len, NULL) != SASL_OK) {
+ utils->free(ret);
+ return NULL;
+ }
+ utils->free(ret);
+
+ return base64buf;
+}
+
+static int add_to_challenge(const sasl_utils_t *utils,
+ char **str, unsigned *buflen, unsigned *curlen,
+ char *name,
+ unsigned char *value,
+ bool need_quotes)
+{
+ size_t namesize = strlen(name);
+ size_t valuesize = strlen((char *) value);
+ unsigned newlen;
+ int ret;
+
+ newlen = (unsigned) (*curlen + 1 + namesize + 2 + valuesize + 2);
+ ret = _plug_buf_alloc(utils, str, buflen, newlen);
+ if(ret != SASL_OK) return ret;
+
+ if (*curlen > 0) {
+ strcat(*str, ",");
+ strcat(*str, name);
+ } else {
+ strcpy(*str, name);
+ }
+
+ if (need_quotes) {
+ strcat(*str, "=\"");
+
+ /* Check if the value needs quoting */
+ if (strpbrk ((char *)value, NEED_ESCAPING) != NULL) {
+ char * quoted = quote ((char *) value);
+ if (quoted == NULL)
+ MEMERROR(utils);
+ valuesize = strlen(quoted);
+ /* As the quoted string is bigger, make sure we have enough
+ space now */
+ ret = _plug_buf_alloc(utils, str, buflen, newlen);
+ if (ret == SASL_OK) {
+ strcat(*str, quoted);
+ free (quoted);
+ } else {
+ free (quoted);
+ return ret;
+ }
+ } else {
+ strcat(*str, (char *) value);
+ }
+ strcat(*str, "\"");
+ } else {
+ strcat(*str, "=");
+ strcat(*str, (char *) value);
+ }
+
+ *curlen = newlen;
+ return SASL_OK;
+}
+
+static int is_lws_char (char c)
+{
+ return (c == ' ' || c == HT || c == CR || c == LF);
+}
+
+static char *skip_lws (char *s)
+{
+ if (!s) return NULL;
+
+ /* skipping spaces: */
+ while (is_lws_char(s[0])) {
+ if (s[0] == '\0') break;
+ s++;
+ }
+
+ return s;
+}
+
+/* Same as skip_lws, but do this right to left */
+/* skip LWSP at the end of the value (if any), skip_r_lws returns pointer to
+ the first LWSP character, NUL (if there were none) or NULL if the value
+ is entirely from LWSP characters */
+static char *skip_r_lws (char *s)
+{
+ char *end;
+ size_t len;
+
+ if (!s) return NULL;
+
+ len = strlen(s);
+ if (len == 0) return NULL;
+
+ /* the last character before terminating NUL */
+ end = s + len - 1;
+
+ /* skipping spaces: */
+ while (end > s && (end[0] == ' ' || end[0] == HT || end[0] == CR || end[0] == LF)) {
+ end--;
+ }
+
+ /* If all string from spaces, return NULL */
+ if (end == s && (end[0] == ' ' || end[0] == HT || end[0] == CR || end[0] == LF)) {
+ return NULL;
+ } else {
+ return (end + 1);
+ }
+}
+
+static char *skip_token (char *s, int caseinsensitive)
+{
+ if(!s) return NULL;
+
+ while (s[0]>SP) {
+ if (s[0]==DEL || s[0]=='(' || s[0]==')' || s[0]=='<' || s[0]=='>' ||
+ s[0]=='@' || s[0]==',' || s[0]==';' || s[0]==':' || s[0]=='\\' ||
+ s[0]=='\'' || s[0]=='/' || s[0]=='[' || s[0]==']' || s[0]== '?' ||
+ s[0]=='=' || s[0]== '{' || s[0]== '}') {
+ if (caseinsensitive == 1) {
+ if (!isupper((unsigned char) s[0]))
+ break;
+ } else {
+ break;
+ }
+ }
+ s++;
+ }
+ return s;
+}
+
+/* Convert a string to 32 bit unsigned integer.
+ Any number of trailing spaces is allowed, but not a string
+ entirely comprised of spaces */
+static bool str2ul32 (char *str, unsigned long * value)
+{
+ unsigned int n;
+ char c;
+
+ if (str == NULL) {
+ return (FALSE);
+ }
+
+ *value = 0;
+
+ str = skip_lws (str);
+ if (str[0] == '\0') {
+ return (FALSE);
+ }
+
+ n = 0;
+ while (str[0] != '\0') {
+ c = str[0];
+ if (!isdigit((int)c)) {
+ return (FALSE);
+ }
+
+/* Will overflow after adding additional digit */
+ if (n > MAX_UIN32_DIV_10) {
+ return (FALSE);
+ } else if (n == MAX_UIN32_DIV_10 && ((unsigned) (c - '0') > MAX_UIN32_MOD_10)) {
+ return (FALSE);
+ }
+
+ n = n * 10 + (unsigned) (c - '0');
+ str++;
+ }
+
+ *value = n;
+ return (TRUE);
+}
+
+/* NULL - error (unbalanced quotes),
+ otherwise pointer to the first character after the value.
+ The function performs work in place. */
+static char *unquote (char *qstr)
+{
+ char *endvalue;
+ int escaped = 0;
+ char *outptr;
+
+ if(!qstr) return NULL;
+
+ if (qstr[0] == '"') {
+ qstr++;
+ outptr = qstr;
+
+ for (endvalue = qstr; endvalue[0] != '\0'; endvalue++, outptr++) {
+ if (escaped) {
+ outptr[0] = endvalue[0];
+ escaped = 0;
+ }
+ else if (endvalue[0] == '\\') {
+ escaped = 1;
+ outptr--; /* Will be incremented at the end of the loop */
+ }
+ else if (endvalue[0] == '"') {
+ break;
+ }
+ else {
+ outptr[0] = endvalue[0];
+ }
+ }
+
+ if (endvalue[0] != '"') {
+ return NULL;
+ }
+
+ while (outptr <= endvalue) {
+ outptr[0] = '\0';
+ outptr++;
+ }
+ endvalue++;
+ }
+ else { /* not qouted value (token) */
+ /* qstr already contains output */
+ endvalue = skip_token(qstr,0);
+ };
+
+ return endvalue;
+}
+
+/* Unlike unquote, this function returns an allocated quoted copy */
+static char *quote (char *str)
+{
+ char *p;
+ char *outp;
+ char *result;
+ int num_to_escape; /* How many characters need escaping */
+
+ if (!str) return NULL;
+
+ num_to_escape = 0;
+ p = strpbrk (str, NEED_ESCAPING);
+ while (p != NULL) {
+ num_to_escape++;
+ p = strpbrk (p + 1, NEED_ESCAPING);
+ }
+
+ if (num_to_escape == 0) {
+ return (strdup (str));
+ }
+
+ result = malloc (strlen(str) + num_to_escape + 1);
+ if (result == NULL) {
+ return NULL;
+ }
+ for (p = str, outp = result; *p; p++) {
+ if (*p == '"' || *p == '\\') {
+ *outp = '\\';
+ outp++;
+ }
+ *outp = *p;
+ outp++;
+ }
+
+ *outp = '\0';
+
+ return (result);
+}
+
+static void get_pair(char **in, char **name, char **value)
+{
+ char *endpair;
+ char *curp = *in;
+ *name = NULL;
+ *value = NULL;
+
+ if (curp == NULL) return;
+
+ while (curp[0] != '\0') {
+ /* skipping spaces: */
+ curp = skip_lws(curp);
+
+ /* 'LWS "," LWS "," ...' is allowed by the DIGEST-MD5 ABNF */
+ if (curp[0] == ',') {
+ curp++;
+ } else {
+ break;
+ }
+ }
+
+ if (curp[0] == '\0') {
+ /* End of the string is not an error */
+ *name = "";
+ return;
+ }
+
+ *name = curp;
+
+ curp = skip_token(curp,1);
+
+ /* strip wierd chars */
+ if (curp[0] != '=' && curp[0] != '\0') {
+ *curp++ = '\0';
+ };
+
+ curp = skip_lws(curp);
+
+ if (curp[0] != '=') { /* No '=' sign */
+ *name = NULL;
+ return;
+ }
+
+ curp[0] = '\0';
+ curp++;
+
+ curp = skip_lws(curp);
+
+ *value = (curp[0] == '"') ? curp+1 : curp;
+
+ endpair = unquote (curp);
+ if (endpair == NULL) { /* Unbalanced quotes */
+ *name = NULL;
+ *value = NULL;
+ return;
+ }
+
+ /* An optional LWS is allowed after the value. Skip it. */
+ if (is_lws_char (endpair[0])) {
+ /* Remove the trailing LWS from the value */
+ *endpair++ = '\0';
+ endpair = skip_lws(endpair);
+ }
+
+ /* syntax check: MUST be '\0' or ',' */
+ if (endpair[0] == ',') {
+ endpair[0] = '\0';
+ endpair++; /* skipping <,> */
+ } else if (endpair[0] != '\0') {
+ *name = NULL;
+ *value = NULL;
+ return;
+ }
+
+ *in = endpair;
+}
+
+#ifdef WITH_DES
+struct des_context_s {
+ des_key_schedule keysched; /* key schedule for des initialization */
+ des_cblock ivec; /* initial vector for encoding */
+ des_key_schedule keysched2; /* key schedule for 3des initialization */
+};
+
+typedef struct des_context_s des_context_t;
+
+/* slide the first 7 bytes of 'inbuf' into the high seven bits of the
+ first 8 bytes of 'keybuf'. 'keybuf' better be 8 bytes long or longer. */
+static void slidebits(unsigned char *keybuf, unsigned char *inbuf)
+{
+ keybuf[0] = inbuf[0];
+ keybuf[1] = (inbuf[0]<<7) | (inbuf[1]>>1);
+ keybuf[2] = (inbuf[1]<<6) | (inbuf[2]>>2);
+ keybuf[3] = (inbuf[2]<<5) | (inbuf[3]>>3);
+ keybuf[4] = (inbuf[3]<<4) | (inbuf[4]>>4);
+ keybuf[5] = (inbuf[4]<<3) | (inbuf[5]>>5);
+ keybuf[6] = (inbuf[5]<<2) | (inbuf[6]>>6);
+ keybuf[7] = (inbuf[6]<<1);
+}
+
+/******************************
+ *
+ * 3DES functions
+ *
+ *****************************/
+
+static int dec_3des(context_t *text,
+ const char *input,
+ unsigned inputlen,
+ unsigned char digest[16] __attribute__((unused)),
+ char *output,
+ unsigned *outputlen)
+{
+ des_context_t *c = (des_context_t *) text->cipher_dec_context;
+ int padding, p;
+
+ des_ede2_cbc_encrypt((void *) input,
+ (void *) output,
+ inputlen,
+ c->keysched,
+ c->keysched2,
+ &c->ivec,
+ DES_DECRYPT);
+
+ /* now chop off the padding */
+ padding = output[inputlen - 11];
+ if (padding < 1 || padding > 8) {
+ /* invalid padding length */
+ return SASL_FAIL;
+ }
+ /* verify all padding is correct */
+ for (p = 1; p <= padding; p++) {
+ if (output[inputlen - 10 - p] != padding) {
+ return SASL_FAIL;
+ }
+ }
+
+ /* chop off the padding */
+ *outputlen = inputlen - padding - 10;
+
+ return SASL_OK;
+}
+
+static int enc_3des(context_t *text,
+ const char *input,
+ unsigned inputlen,
+ unsigned char digest[16],
+ char *output,
+ unsigned *outputlen)
+{
+ des_context_t *c = (des_context_t *) text->cipher_enc_context;
+ int len;
+ int paddinglen;
+
+ /* determine padding length */
+ paddinglen = 8 - ((inputlen + 10) % 8);
+
+ /* now construct the full stuff to be ciphered */
+ memcpy(output, input, inputlen); /* text */
+ memset(output+inputlen, paddinglen, paddinglen);/* pad */
+ memcpy(output+inputlen+paddinglen, digest, 10); /* hmac */
+
+ len=inputlen+paddinglen+10;
+
+ des_ede2_cbc_encrypt((void *) output,
+ (void *) output,
+ len,
+ c->keysched,
+ c->keysched2,
+ &c->ivec,
+ DES_ENCRYPT);
+
+ *outputlen=len;
+
+ return SASL_OK;
+}
+
+static int init_3des(context_t *text,
+ unsigned char enckey[16],
+ unsigned char deckey[16])
+{
+ des_context_t *c;
+ unsigned char keybuf[8];
+
+ /* allocate enc & dec context */
+ c = (des_context_t *) text->utils->malloc(2 * sizeof(des_context_t));
+ if (c == NULL) return SASL_NOMEM;
+
+ /* setup enc context */
+ slidebits(keybuf, enckey);
+ if (des_key_sched((des_cblock *) keybuf, c->keysched) < 0)
+ return SASL_FAIL;
+
+ slidebits(keybuf, enckey + 7);
+ if (des_key_sched((des_cblock *) keybuf, c->keysched2) < 0)
+ return SASL_FAIL;
+ memcpy(c->ivec, ((char *) enckey) + 8, 8);
+
+ text->cipher_enc_context = (cipher_context_t *) c;
+
+ /* setup dec context */
+ c++;
+ slidebits(keybuf, deckey);
+ if (des_key_sched((des_cblock *) keybuf, c->keysched) < 0)
+ return SASL_FAIL;
+
+ slidebits(keybuf, deckey + 7);
+ if (des_key_sched((des_cblock *) keybuf, c->keysched2) < 0)
+ return SASL_FAIL;
+
+ memcpy(c->ivec, ((char *) deckey) + 8, 8);
+
+ text->cipher_dec_context = (cipher_context_t *) c;
+
+ return SASL_OK;
+}
+
+
+/******************************
+ *
+ * DES functions
+ *
+ *****************************/
+
+static int dec_des(context_t *text,
+ const char *input,
+ unsigned inputlen,
+ unsigned char digest[16] __attribute__((unused)),
+ char *output,
+ unsigned *outputlen)
+{
+ des_context_t *c = (des_context_t *) text->cipher_dec_context;
+ int p, padding = 0;
+
+ des_cbc_encrypt((void *) input,
+ (void *) output,
+ inputlen,
+ c->keysched,
+ &c->ivec,
+ DES_DECRYPT);
+
+ /* Update the ivec (des_cbc_encrypt implementations tend to be broken in
+ this way) */
+ memcpy(c->ivec, input + (inputlen - 8), 8);
+
+ /* now chop off the padding */
+ padding = output[inputlen - 11];
+ if (padding < 1 || padding > 8) {
+ /* invalid padding length */
+ return SASL_FAIL;
+ }
+ /* verify all padding is correct */
+ for (p = 1; p <= padding; p++) {
+ if (output[inputlen - 10 - p] != padding) {
+ return SASL_FAIL;
+ }
+ }
+
+ /* chop off the padding */
+ *outputlen = inputlen - padding - 10;
+
+ return SASL_OK;
+}
+
+static int enc_des(context_t *text,
+ const char *input,
+ unsigned inputlen,
+ unsigned char digest[16],
+ char *output,
+ unsigned *outputlen)
+{
+ des_context_t *c = (des_context_t *) text->cipher_enc_context;
+ int len;
+ int paddinglen;
+
+ /* determine padding length */
+ paddinglen = 8 - ((inputlen+10) % 8);
+
+ /* now construct the full stuff to be ciphered */
+ memcpy(output, input, inputlen); /* text */
+ memset(output+inputlen, paddinglen, paddinglen);/* pad */
+ memcpy(output+inputlen+paddinglen, digest, 10); /* hmac */
+
+ len = inputlen + paddinglen + 10;
+
+ des_cbc_encrypt((void *) output,
+ (void *) output,
+ len,
+ c->keysched,
+ &c->ivec,
+ DES_ENCRYPT);
+
+ /* Update the ivec (des_cbc_encrypt implementations tend to be broken in
+ this way) */
+ memcpy(c->ivec, output + (len - 8), 8);
+
+ *outputlen = len;
+
+ return SASL_OK;
+}
+
+static int init_des(context_t *text,
+ unsigned char enckey[16],
+ unsigned char deckey[16])
+{
+ des_context_t *c;
+ unsigned char keybuf[8];
+
+ /* allocate enc context */
+ c = (des_context_t *) text->utils->malloc(2 * sizeof(des_context_t));
+ if (c == NULL) return SASL_NOMEM;
+
+ /* setup enc context */
+ slidebits(keybuf, enckey);
+ des_key_sched((des_cblock *) keybuf, c->keysched);
+
+ memcpy(c->ivec, ((char *) enckey) + 8, 8);
+
+ text->cipher_enc_context = (cipher_context_t *) c;
+
+ /* setup dec context */
+ c++;
+ slidebits(keybuf, deckey);
+ des_key_sched((des_cblock *) keybuf, c->keysched);
+
+ memcpy(c->ivec, ((char *) deckey) + 8, 8);
+
+ text->cipher_dec_context = (cipher_context_t *) c;
+
+ return SASL_OK;
+}
+
+static void free_des(context_t *text)
+{
+ /* free des contextss. only cipher_enc_context needs to be free'd,
+ since cipher_dec_context was allocated at the same time. */
+ if (text->cipher_enc_context) text->utils->free(text->cipher_enc_context);
+}
+
+#endif /* WITH_DES */
+
+#ifdef WITH_RC4
+#ifdef HAVE_OPENSSL
+#include <openssl/evp.h>
+
+static void free_rc4(context_t *text)
+{
+ if (text->cipher_enc_context) {
+ EVP_CIPHER_CTX_free((EVP_CIPHER_CTX *)text->cipher_enc_context);
+ text->cipher_enc_context = NULL;
+ }
+ if (text->cipher_dec_context) {
+ EVP_CIPHER_CTX_free((EVP_CIPHER_CTX *)text->cipher_dec_context);
+ text->cipher_dec_context = NULL;
+ }
+}
+
+static int init_rc4(context_t *text,
+ unsigned char enckey[16],
+ unsigned char deckey[16])
+{
+ EVP_CIPHER_CTX *ctx;
+ int rc;
+
+ ctx = EVP_CIPHER_CTX_new();
+ if (ctx == NULL) return SASL_NOMEM;
+
+ rc = EVP_EncryptInit_ex(ctx, EVP_rc4(), NULL, enckey, NULL);
+ if (rc != 1) return SASL_FAIL;
+
+ text->cipher_enc_context = (void *)ctx;
+
+ ctx = EVP_CIPHER_CTX_new();
+ if (ctx == NULL) return SASL_NOMEM;
+
+ rc = EVP_DecryptInit_ex(ctx, EVP_rc4(), NULL, deckey, NULL);
+ if (rc != 1) return SASL_FAIL;
+
+ text->cipher_dec_context = (void *)ctx;
+
+ return SASL_OK;
+}
+
+static int dec_rc4(context_t *text,
+ const char *input,
+ unsigned inputlen,
+ unsigned char digest[16] __attribute__((unused)),
+ char *output,
+ unsigned *outputlen)
+{
+ int len;
+ int rc;
+
+ /* decrypt the text part & HMAC */
+ rc = EVP_DecryptUpdate((EVP_CIPHER_CTX *)text->cipher_dec_context,
+ (unsigned char *)output, &len,
+ (const unsigned char *)input, inputlen);
+ if (rc != 1) return SASL_FAIL;
+
+ *outputlen = len;
+
+ rc = EVP_DecryptFinal_ex((EVP_CIPHER_CTX *)text->cipher_dec_context,
+ (unsigned char *)output + len, &len);
+ if (rc != 1) return SASL_FAIL;
+
+ *outputlen += len;
+
+ /* subtract the HMAC to get the text length */
+ *outputlen -= 10;
+
+ return SASL_OK;
+}
+
+static int enc_rc4(context_t *text,
+ const char *input,
+ unsigned inputlen,
+ unsigned char digest[16],
+ char *output,
+ unsigned *outputlen)
+{
+ int len;
+ int rc;
+ /* encrypt the text part */
+ rc = EVP_EncryptUpdate((EVP_CIPHER_CTX *)text->cipher_enc_context,
+ (unsigned char *)output, &len,
+ (const unsigned char *)input, inputlen);
+ if (rc != 1) return SASL_FAIL;
+
+ *outputlen = len;
+
+ /* encrypt the `MAC part */
+ rc = EVP_EncryptUpdate((EVP_CIPHER_CTX *)text->cipher_enc_context,
+ (unsigned char *)output + *outputlen, &len,
+ digest, 10);
+ if (rc != 1) return SASL_FAIL;
+
+ *outputlen += len;
+
+ rc = EVP_EncryptFinal_ex((EVP_CIPHER_CTX *)text->cipher_enc_context,
+ (unsigned char *)output + *outputlen, &len);
+ if (rc != 1) return SASL_FAIL;
+
+ *outputlen += len;
+
+ return SASL_OK;
+}
+#else
+/* quick generic implementation of RC4 */
+struct rc4_context_s {
+ unsigned char sbox[256];
+ int i, j;
+};
+
+typedef struct rc4_context_s rc4_context_t;
+
+static void rc4_init(rc4_context_t *text,
+ const unsigned char *key,
+ unsigned keylen)
+{
+ int i, j;
+
+ /* fill in linearly s0=0 s1=1... */
+ for (i=0;i<256;i++)
+ text->sbox[i]=i;
+
+ j=0;
+ for (i = 0; i < 256; i++) {
+ unsigned char tmp;
+ /* j = (j + Si + Ki) mod 256 */
+ j = (j + text->sbox[i] + key[i % keylen]) % 256;
+
+ /* swap Si and Sj */
+ tmp = text->sbox[i];
+ text->sbox[i] = text->sbox[j];
+ text->sbox[j] = tmp;
+ }
+
+ /* counters initialized to 0 */
+ text->i = 0;
+ text->j = 0;
+}
+
+static void rc4_encrypt(rc4_context_t *text,
+ const char *input,
+ char *output,
+ unsigned len)
+{
+ int tmp;
+ int i = text->i;
+ int j = text->j;
+ int t;
+ int K;
+ const char *input_end = input + len;
+
+ while (input < input_end) {
+ i = (i + 1) % 256;
+
+ j = (j + text->sbox[i]) % 256;
+
+ /* swap Si and Sj */
+ tmp = text->sbox[i];
+ text->sbox[i] = text->sbox[j];
+ text->sbox[j] = tmp;
+
+ t = (text->sbox[i] + text->sbox[j]) % 256;
+
+ K = text->sbox[t];
+
+ /* byte K is Xor'ed with plaintext */
+ *output++ = *input++ ^ K;
+ }
+
+ text->i = i;
+ text->j = j;
+}
+
+static void rc4_decrypt(rc4_context_t *text,
+ const char *input,
+ char *output,
+ unsigned len)
+{
+ int tmp;
+ int i = text->i;
+ int j = text->j;
+ int t;
+ int K;
+ const char *input_end = input + len;
+
+ while (input < input_end) {
+ i = (i + 1) % 256;
+
+ j = (j + text->sbox[i]) % 256;
+
+ /* swap Si and Sj */
+ tmp = text->sbox[i];
+ text->sbox[i] = text->sbox[j];
+ text->sbox[j] = tmp;
+
+ t = (text->sbox[i] + text->sbox[j]) % 256;
+
+ K = text->sbox[t];
+
+ /* byte K is Xor'ed with plaintext */
+ *output++ = *input++ ^ K;
+ }
+
+ text->i = i;
+ text->j = j;
+}
+
+static void free_rc4(context_t *text)
+{
+ /* free rc4 context structures */
+
+ if (text->cipher_enc_context) {
+ text->utils->free(text->cipher_enc_context);
+ text->cipher_enc_context = NULL;
+ }
+ if (text->cipher_dec_context) {
+ text->utils->free(text->cipher_dec_context);
+ text->cipher_dec_context = NULL;
+ }
+}
+
+static int init_rc4(context_t *text,
+ unsigned char enckey[16],
+ unsigned char deckey[16])
+{
+ /* allocate rc4 context structures */
+ text->cipher_enc_context=
+ (cipher_context_t *) text->utils->malloc(sizeof(rc4_context_t));
+ if (text->cipher_enc_context == NULL) return SASL_NOMEM;
+
+ text->cipher_dec_context=
+ (cipher_context_t *) text->utils->malloc(sizeof(rc4_context_t));
+ if (text->cipher_dec_context == NULL) return SASL_NOMEM;
+
+ /* initialize them */
+ rc4_init((rc4_context_t *) text->cipher_enc_context,
+ (const unsigned char *) enckey, 16);
+ rc4_init((rc4_context_t *) text->cipher_dec_context,
+ (const unsigned char *) deckey, 16);
+
+ return SASL_OK;
+}
+
+static int dec_rc4(context_t *text,
+ const char *input,
+ unsigned inputlen,
+ unsigned char digest[16] __attribute__((unused)),
+ char *output,
+ unsigned *outputlen)
+{
+ /* decrypt the text part & HMAC */
+ rc4_decrypt((rc4_context_t *) text->cipher_dec_context,
+ input, output, inputlen);
+
+ /* no padding so we just subtract the HMAC to get the text length */
+ *outputlen = inputlen - 10;
+
+ return SASL_OK;
+}
+
+static int enc_rc4(context_t *text,
+ const char *input,
+ unsigned inputlen,
+ unsigned char digest[16],
+ char *output,
+ unsigned *outputlen)
+{
+ /* pad is zero */
+ *outputlen = inputlen+10;
+
+ /* encrypt the text part */
+ rc4_encrypt((rc4_context_t *) text->cipher_enc_context,
+ input,
+ output,
+ inputlen);
+
+ /* encrypt the HMAC part */
+ rc4_encrypt((rc4_context_t *) text->cipher_enc_context,
+ (const char *) digest,
+ (output)+inputlen, 10);
+
+ return SASL_OK;
+}
+#endif /* HAVE_OPENSSL */
+#endif /* WITH_RC4 */
+
+struct digest_cipher available_ciphers[] =
+{
+#ifdef WITH_RC4
+ { "rc4-40", 40, 5, 0x01, &enc_rc4, &dec_rc4, &init_rc4, &free_rc4 },
+ { "rc4-56", 56, 7, 0x02, &enc_rc4, &dec_rc4, &init_rc4, &free_rc4 },
+ { "rc4", 128, 16, 0x04, &enc_rc4, &dec_rc4, &init_rc4, &free_rc4 },
+#endif
+#ifdef WITH_DES
+ { "des", 55, 16, 0x08, &enc_des, &dec_des, &init_des, &free_des },
+ { "3des", 112, 16, 0x10, &enc_3des, &dec_3des, &init_3des, &free_des },
+#endif
+ { NULL, 0, 0, 0, NULL, NULL, NULL, NULL }
+};
+
+static int create_layer_keys(context_t *text,
+ const sasl_utils_t *utils,
+ HASH key, int keylen,
+ unsigned char enckey[16],
+ unsigned char deckey[16])
+{
+ MD5_CTX Md5Ctx;
+
+ utils->log(utils->conn, SASL_LOG_DEBUG,
+ "DIGEST-MD5 create_layer_keys()");
+
+ utils->MD5Init(&Md5Ctx);
+ utils->MD5Update(&Md5Ctx, key, keylen);
+ if (text->i_am == SERVER) {
+ utils->MD5Update(&Md5Ctx, (const unsigned char *) SEALING_SERVER_CLIENT,
+ (unsigned) strlen(SEALING_SERVER_CLIENT));
+ } else {
+ utils->MD5Update(&Md5Ctx, (const unsigned char *) SEALING_CLIENT_SERVER,
+ (unsigned) strlen(SEALING_CLIENT_SERVER));
+ }
+ utils->MD5Final(enckey, &Md5Ctx);
+
+ utils->MD5Init(&Md5Ctx);
+ utils->MD5Update(&Md5Ctx, key, keylen);
+ if (text->i_am != SERVER) {
+ utils->MD5Update(&Md5Ctx, (const unsigned char *) SEALING_SERVER_CLIENT,
+ (unsigned) strlen(SEALING_SERVER_CLIENT));
+ } else {
+ utils->MD5Update(&Md5Ctx, (const unsigned char *) SEALING_CLIENT_SERVER,
+ (unsigned) strlen(SEALING_CLIENT_SERVER));
+ }
+ utils->MD5Final(deckey, &Md5Ctx);
+
+ /* create integrity keys */
+ /* sending */
+ utils->MD5Init(&Md5Ctx);
+ utils->MD5Update(&Md5Ctx, text->HA1, HASHLEN);
+ if (text->i_am == SERVER) {
+ utils->MD5Update(&Md5Ctx, (const unsigned char *)SIGNING_SERVER_CLIENT,
+ (unsigned) strlen(SIGNING_SERVER_CLIENT));
+ } else {
+ utils->MD5Update(&Md5Ctx, (const unsigned char *)SIGNING_CLIENT_SERVER,
+ (unsigned) strlen(SIGNING_CLIENT_SERVER));
+ }
+ utils->MD5Final(text->Ki_send, &Md5Ctx);
+
+ /* receiving */
+ utils->MD5Init(&Md5Ctx);
+ utils->MD5Update(&Md5Ctx, text->HA1, HASHLEN);
+ if (text->i_am != SERVER) {
+ utils->MD5Update(&Md5Ctx, (const unsigned char *)SIGNING_SERVER_CLIENT,
+ (unsigned) strlen(SIGNING_SERVER_CLIENT));
+ } else {
+ utils->MD5Update(&Md5Ctx, (const unsigned char *)SIGNING_CLIENT_SERVER,
+ (unsigned) strlen(SIGNING_CLIENT_SERVER));
+ }
+ utils->MD5Final(text->Ki_receive, &Md5Ctx);
+
+ return SASL_OK;
+}
+
+static const unsigned short version = 1;
+
+/*
+ * privacy:
+ * len, CIPHER(Kc, {msg, pag, HMAC(ki, {SeqNum, msg})[0..9]}), x0001, SeqNum
+ *
+ * integrity:
+ * len, HMAC(ki, {SeqNum, msg})[0..9], x0001, SeqNum
+ */
+static int digestmd5_encode(void *context,
+ const struct iovec *invec,
+ unsigned numiov,
+ const char **output,
+ unsigned *outputlen)
+{
+ context_t *text = (context_t *) context;
+ int tmp;
+ unsigned int tmpnum;
+ unsigned short int tmpshort;
+ int ret;
+ char *out;
+ struct buffer_info *inblob, bufinfo;
+
+ if(!context || !invec || !numiov || !output || !outputlen) {
+ if (text) PARAMERROR(text->utils);
+ return SASL_BADPARAM;
+ }
+
+ if (numiov > 1) {
+ ret = _plug_iovec_to_buf(text->utils, invec, numiov, &text->enc_in_buf);
+ if (ret != SASL_OK) return ret;
+ inblob = text->enc_in_buf;
+ } else {
+ /* avoid the data copy */
+ bufinfo.data = invec[0].iov_base;
+ bufinfo.curlen = invec[0].iov_len;
+ inblob = &bufinfo;
+ }
+
+ /* make sure the output buffer is big enough for this blob */
+ ret = _plug_buf_alloc(text->utils, &(text->encode_buf),
+ &(text->encode_buf_len),
+ (4 + /* for length */
+ inblob->curlen + /* for content */
+ 10 + /* for MAC */
+ 8 + /* maximum pad */
+ 6)); /* for ver and seqnum */
+ if(ret != SASL_OK) return ret;
+
+ /* skip by the length for now */
+ out = (text->encode_buf)+4;
+
+ /* construct (seqnum, msg)
+ *
+ * Use the output buffer so that the message text is already in place
+ * for an integrity-only layer.
+ */
+ tmpnum = htonl(text->seqnum);
+ memcpy(text->encode_buf, &tmpnum, 4);
+ memcpy(text->encode_buf + 4, inblob->data, inblob->curlen);
+
+ if (text->cipher_enc) {
+ unsigned char digest[16];
+
+ /* HMAC(ki, (seqnum, msg) ) */
+ text->utils->hmac_md5((const unsigned char *) text->encode_buf,
+ inblob->curlen + 4,
+ text->Ki_send, HASHLEN, digest);
+
+ /* calculate the encrypted part */
+ text->cipher_enc(text, inblob->data, inblob->curlen,
+ digest, out, outputlen);
+ out+=(*outputlen);
+ }
+ else {
+ /* HMAC(ki, (seqnum, msg) ) -- put directly into output buffer */
+ text->utils->hmac_md5((const unsigned char *) text->encode_buf,
+ inblob->curlen + 4,
+ text->Ki_send, HASHLEN,
+ (unsigned char *) text->encode_buf +
+ inblob->curlen + 4);
+
+ *outputlen = inblob->curlen + 10; /* for message + CMAC */
+ out+=inblob->curlen + 10;
+ }
+
+ /* copy in version */
+ tmpshort = htons(version);
+ memcpy(out, &tmpshort, 2); /* 2 bytes = version */
+
+ out+=2;
+ (*outputlen)+=2; /* for version */
+
+ /* put in seqnum */
+ tmpnum = htonl(text->seqnum);
+ memcpy(out, &tmpnum, 4); /* 4 bytes = seq # */
+
+ (*outputlen)+=4; /* for seqnum */
+
+ /* put the 1st 4 bytes in */
+ tmp=htonl(*outputlen);
+ memcpy(text->encode_buf, &tmp, 4);
+
+ (*outputlen)+=4;
+
+ *output = text->encode_buf;
+ text->seqnum++;
+
+ return SASL_OK;
+}
+
+static int digestmd5_decode_packet(void *context,
+ const char *input,
+ unsigned inputlen,
+ char **output,
+ unsigned *outputlen)
+{
+ context_t *text = (context_t *) context;
+ int result;
+ unsigned char *digest;
+ int tmpnum;
+ int lup;
+ unsigned short ver;
+ unsigned int seqnum;
+ unsigned char checkdigest[16];
+
+ if (inputlen < 16) {
+ text->utils->seterror(text->utils->conn, 0, "DIGEST-MD5 SASL packets must be at least 16 bytes long");
+ return SASL_FAIL;
+ }
+
+ /* check the version number */
+ memcpy(&ver, input+inputlen-6, 2);
+ ver = ntohs(ver);
+ if (ver != version) {
+ text->utils->seterror(text->utils->conn, 0, "Wrong Version");
+ return SASL_FAIL;
+ }
+
+ /* check the sequence number */
+ memcpy(&seqnum, input+inputlen-4, 4);
+ seqnum = ntohl(seqnum);
+
+ if (seqnum != text->rec_seqnum) {
+ text->utils->seterror(text->utils->conn, 0,
+ "Incorrect Sequence Number: received %u, expected %u",
+ seqnum,
+ text->rec_seqnum);
+ return SASL_FAIL;
+ }
+
+ /* allocate a buffer large enough for the output */
+ result = _plug_buf_alloc(text->utils, &text->decode_packet_buf,
+ &text->decode_packet_buf_len,
+ inputlen /* length of message */
+ - 6 /* skip ver and seqnum */
+ + 4); /* prepend seqnum */
+ if (result != SASL_OK) return result;
+
+ /* construct (seqnum, msg) */
+ tmpnum = htonl(text->rec_seqnum);
+ memcpy(text->decode_packet_buf, &tmpnum, 4);
+
+ text->rec_seqnum++; /* now increment it */
+
+ *output = text->decode_packet_buf + 4; /* skip seqnum */
+
+ if (text->cipher_dec) {
+ /* decrypt message & HMAC into output buffer */
+ result = text->cipher_dec(text, input, inputlen-6, NULL,
+ *output, outputlen);
+ if (result != SASL_OK) return result;
+ }
+ else {
+ /* copy message & HMAC into output buffer */
+ memcpy(*output, input, inputlen - 6);
+ *outputlen = inputlen - 16; /* -16 to skip HMAC, ver and seqnum */
+ }
+ digest = (unsigned char *) *output + (inputlen - 16);
+
+ /* check the CMAC */
+
+ /* HMAC(ki, (seqnum, msg) ) */
+ text->utils->hmac_md5((const unsigned char *) text->decode_packet_buf,
+ (*outputlen) + 4,
+ text->Ki_receive, HASHLEN, checkdigest);
+
+ /* now check it */
+ for (lup = 0; lup < 10; lup++)
+ if (checkdigest[lup] != digest[lup]) {
+ text->utils->seterror(text->utils->conn, 0,
+ "CMAC doesn't match at byte %d!", lup);
+ return SASL_FAIL;
+ }
+
+ return SASL_OK;
+}
+
+static int digestmd5_decode(void *context,
+ const char *input, unsigned inputlen,
+ const char **output, unsigned *outputlen)
+{
+ context_t *text = (context_t *) context;
+ int ret;
+
+ ret = _plug_decode(&text->decode_context, input, inputlen,
+ &text->decode_buf, &text->decode_buf_len, outputlen,
+ digestmd5_decode_packet, text);
+
+ *output = text->decode_buf;
+
+ return ret;
+}
+
+static void digestmd5_common_mech_dispose(void *conn_context,
+ const sasl_utils_t *utils)
+{
+ context_t *text = (context_t *) conn_context;
+ int lup;
+
+ if (!text || !utils) return;
+
+ utils->log(utils->conn, SASL_LOG_DEBUG,
+ "DIGEST-MD5 common mech dispose");
+
+ if (text->authid) utils->free(text->authid);
+ if (text->realm) utils->free(text->realm);
+
+ if (text->realms) {
+ /* need to free all the realms */
+ for (lup = 0; lup < text->realm_cnt; lup++)
+ utils->free (text->realms[lup]);
+
+ utils->free(text->realms);
+ }
+
+ if (text->nonce) utils->free(text->nonce);
+ if (text->cnonce) utils->free(text->cnonce);
+
+ if (text->cipher_free) text->cipher_free(text);
+
+ /* free the stuff in the context */
+ if (text->response_value) utils->free(text->response_value);
+
+ _plug_decode_free(&text->decode_context);
+ if (text->encode_buf) utils->free(text->encode_buf);
+ if (text->decode_buf) utils->free(text->decode_buf);
+ if (text->decode_packet_buf) utils->free(text->decode_packet_buf);
+ if (text->out_buf) utils->free(text->out_buf);
+
+ if (text->enc_in_buf) {
+ if (text->enc_in_buf->data) utils->free(text->enc_in_buf->data);
+ utils->free(text->enc_in_buf);
+ }
+
+ utils->free(conn_context);
+}
+
+static void clear_reauth_entry(reauth_entry_t *reauth, enum Context_type type,
+ const sasl_utils_t *utils)
+{
+ if (!reauth) return;
+
+ if (reauth->authid) utils->free(reauth->authid);
+ if (reauth->realm) utils->free(reauth->realm);
+ if (reauth->nonce) utils->free(reauth->nonce);
+ if (reauth->cnonce) utils->free(reauth->cnonce);
+
+ if (type == CLIENT) {
+ if (reauth->u.c.serverFQDN) utils->free(reauth->u.c.serverFQDN);
+ }
+
+ memset(reauth, 0, sizeof(reauth_entry_t));
+}
+
+static void digestmd5_common_mech_free(void *glob_context,
+ const sasl_utils_t *utils)
+{
+ digest_glob_context_t *my_glob_context =
+ (digest_glob_context_t *) glob_context;
+ reauth_cache_t *reauth_cache = my_glob_context->reauth;
+ size_t n;
+
+ utils->log(utils->conn, SASL_LOG_DEBUG,
+ "DIGEST-MD5 common mech free");
+
+ /* Prevent anybody else from freeing this as well */
+ my_glob_context->reauth = NULL;
+
+ if (!reauth_cache) return;
+
+ for (n = 0; n < reauth_cache->size; n++) {
+ clear_reauth_entry(&reauth_cache->e[n], reauth_cache->i_am, utils);
+ }
+ if (reauth_cache->e) utils->free(reauth_cache->e);
+
+ if (reauth_cache->mutex) {
+ utils->mutex_free(reauth_cache->mutex);
+ reauth_cache->mutex = NULL;
+ }
+
+ utils->free(reauth_cache);
+}
+
+/***************************** Server Section *****************************/
+
+typedef struct server_context {
+ context_t common;
+
+ time_t timestamp;
+ int stale; /* last nonce is stale */
+ sasl_ssf_t limitssf, requiressf; /* application defined bounds */
+} server_context_t;
+
+static digest_glob_context_t server_glob_context;
+
+static void DigestCalcHA1FromSecret(context_t * text,
+ const sasl_utils_t * utils,
+ HASH HA1,
+ unsigned char *authorization_id,
+ unsigned char *pszNonce,
+ unsigned char *pszCNonce,
+ HASHHEX SessionKey)
+{
+ MD5_CTX Md5Ctx;
+
+ /* calculate session key */
+ utils->MD5Init(&Md5Ctx);
+ if (text->http_mode) {
+ /* per RFC 2617 Errata ID 1649 */
+ HASHHEX HA1Hex;
+
+ CvtHex(HA1, HA1Hex);
+ utils->MD5Update(&Md5Ctx, HA1Hex, HASHHEXLEN);
+ }
+ else {
+ /* per RFC 2831 */
+ utils->MD5Update(&Md5Ctx, HA1, HASHLEN);
+ }
+ utils->MD5Update(&Md5Ctx, COLON, 1);
+ utils->MD5Update(&Md5Ctx, pszNonce, (unsigned) strlen((char *) pszNonce));
+ utils->MD5Update(&Md5Ctx, COLON, 1);
+ utils->MD5Update(&Md5Ctx, pszCNonce, (unsigned) strlen((char *) pszCNonce));
+ if (authorization_id != NULL) {
+ utils->MD5Update(&Md5Ctx, COLON, 1);
+ utils->MD5Update(&Md5Ctx, authorization_id,
+ (unsigned) strlen((char *) authorization_id));
+ }
+ utils->MD5Final(HA1, &Md5Ctx);
+
+ CvtHex(HA1, SessionKey);
+
+
+ /* save HA1 because we need it to make the privacy and integrity keys */
+ memcpy(text->HA1, HA1, sizeof(HASH));
+}
+
+static char *create_response(context_t * text,
+ const sasl_utils_t * utils,
+ unsigned char *nonce,
+ unsigned int ncvalue,
+ unsigned char *cnonce,
+ char *qop,
+ const sasl_http_request_t *request,
+ HASH Secret,
+ char *authorization_id,
+ char **response_value)
+{
+ HASHHEX SessionKey;
+ HASH EntityHash;
+ HASHHEX HEntity;
+ HASHHEX Response;
+ char *result;
+
+ if (qop == NULL) qop = "auth";
+
+ DigestCalcHA1FromSecret(text,
+ utils,
+ Secret,
+ (unsigned char *) authorization_id,
+ nonce,
+ cnonce,
+ SessionKey);
+
+ if (text->http_mode) {
+ /* per RFC 2617 */
+ MD5_CTX Md5Ctx;
+
+ utils->MD5Init(&Md5Ctx);
+ utils->MD5Update(&Md5Ctx, request->entity, request->elen);
+ utils->MD5Final(EntityHash, &Md5Ctx);
+ }
+ else {
+ /* per RFC 2831 */
+ memset(EntityHash, 0, HASHLEN);
+ }
+ CvtHex(EntityHash, HEntity);
+
+ /* Calculate response for comparison with client's response */
+ DigestCalcResponse(utils,
+ SessionKey,/* HEX(H(A1)) */
+ nonce, /* nonce from server */
+ ncvalue, /* 8 hex digits */
+ cnonce, /* client nonce */
+ (unsigned char *) qop, /* qop-value: "", "auth",
+ * "auth-int" */
+ (unsigned char *) request->uri, /* requested URL */
+ (unsigned char *) request->method,
+ HEntity, /* H(entity body) if qop="auth-int" */
+ Response /* request-digest or response-digest */
+ );
+
+ result = utils->malloc(HASHHEXLEN + 1);
+ memcpy(result, Response, HASHHEXLEN);
+ result[HASHHEXLEN] = 0;
+
+ /* Calculate response value for mutual auth with the client (NO Method) */
+ if (response_value != NULL) {
+ char * new_response_value;
+
+ DigestCalcResponse(utils,
+ SessionKey, /* HEX(H(A1)) */
+ nonce, /* nonce from server */
+ ncvalue, /* 8 hex digits */
+ cnonce, /* client nonce */
+ (unsigned char *) qop, /* qop-value: "", "auth",
+ * "auth-int" */
+ (unsigned char *) request->uri, /* requested URL */
+ NULL,
+ HEntity, /* H(entity body) if qop="auth-int" */
+ Response /* request-digest or response-digest */
+ );
+
+ new_response_value = utils->realloc(*response_value, HASHHEXLEN + 1);
+ if (new_response_value == NULL) {
+ free (*response_value);
+ *response_value = NULL;
+ return NULL;
+ }
+ *response_value = new_response_value;
+
+ memcpy(*response_value, Response, HASHHEXLEN);
+ (*response_value)[HASHHEXLEN] = 0;
+ }
+ return result;
+}
+
+static int get_server_realm(sasl_server_params_t * params, char **realm)
+{
+ /* look at user realm first */
+ if (params->user_realm != NULL) {
+ if(params->user_realm[0] != '\0') {
+ *realm = (char *) params->user_realm;
+ } else {
+ /* Catch improperly converted apps */
+ params->utils->seterror(params->utils->conn, 0,
+ "user_realm is an empty string!");
+ return SASL_BADPARAM;
+ }
+ } else if (params->serverFQDN != NULL) {
+ *realm = (char *) params->serverFQDN;
+ } else {
+ params->utils->seterror(params->utils->conn, 0,
+ "no way to obtain DIGEST-MD5 realm");
+ return SASL_FAIL;
+ }
+
+ return SASL_OK;
+}
+
+/*
+ * Convert hex string to int
+ */
+static int htoi(unsigned char *hexin, unsigned int *res)
+{
+ size_t lup, inlen;
+ inlen = strlen((char *) hexin);
+
+ *res = 0;
+ for (lup = 0; lup < inlen; lup++) {
+ switch (hexin[lup]) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ *res = (*res << 4) + (hexin[lup] - '0');
+ break;
+
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ *res = (*res << 4) + (hexin[lup] - 'a' + 10);
+ break;
+
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ *res = (*res << 4) + (hexin[lup] - 'A' + 10);
+ break;
+
+ default:
+ return SASL_BADPARAM;
+ }
+
+ }
+
+ return SASL_OK;
+}
+
+static int digestmd5_server_mech_new(void *glob_context,
+ sasl_server_params_t * sparams,
+ const char *challenge __attribute__((unused)),
+ unsigned challen __attribute__((unused)),
+ void **conn_context)
+{
+ context_t *text;
+
+ /* holds state are in -- allocate server size */
+ text = sparams->utils->malloc(sizeof(server_context_t));
+ if (text == NULL)
+ return SASL_NOMEM;
+ memset((server_context_t *)text, 0, sizeof(server_context_t));
+
+ text->state = 1;
+ text->i_am = SERVER;
+ text->http_mode = (sparams->flags & SASL_NEED_HTTP);
+ text->reauth = ((digest_glob_context_t *) glob_context)->reauth;
+
+ *conn_context = text;
+ return SASL_OK;
+}
+
+static int
+digestmd5_server_mech_step1(server_context_t *stext,
+ sasl_server_params_t *sparams,
+ const char *clientin __attribute__((unused)),
+ unsigned clientinlen __attribute__((unused)),
+ const char **serverout,
+ unsigned *serveroutlen,
+ sasl_out_params_t * oparams __attribute__((unused)))
+{
+ context_t *text = (context_t *) stext;
+ int result;
+ char *realm;
+ unsigned char *nonce;
+ char *charset = "utf-8";
+ char qop[1024], cipheropts[1024];
+ struct digest_cipher *cipher;
+ unsigned resplen;
+ int added_conf = 0;
+ char maxbufstr[64];
+
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_DEBUG,
+ "DIGEST-MD5 server step 1");
+
+ /* get realm */
+ result = get_server_realm(sparams, &realm);
+ if(result != SASL_OK) return result;
+
+ /* what options should we offer the client? */
+ qop[0] = '\0';
+ cipheropts[0] = '\0';
+ if (stext->requiressf == 0) {
+ if (*qop) strcat(qop, ",");
+ strcat(qop, "auth");
+ }
+ if (stext->requiressf <= 1 && stext->limitssf >= 1) {
+ if (*qop) strcat(qop, ",");
+ strcat(qop, "auth-int");
+ }
+
+ cipher = available_ciphers;
+ while (cipher->name) {
+ /* do we allow this particular cipher? */
+ if (stext->requiressf <= cipher->ssf &&
+ stext->limitssf >= cipher->ssf) {
+ if (!added_conf) {
+ if (*qop) strcat(qop, ",");
+ strcat(qop, "auth-conf");
+ added_conf = 1;
+ }
+ if (strlen(cipheropts) + strlen(cipher->name) + 1 >= 1024)
+ return SASL_FAIL;
+ if (*cipheropts) strcat(cipheropts, ",");
+ strcat(cipheropts, cipher->name);
+ }
+ cipher++;
+ }
+
+ if (*qop == '\0') {
+ /* we didn't allow anything?!? we'll return SASL_TOOWEAK, since
+ that's close enough */
+ return SASL_TOOWEAK;
+ }
+
+ /*
+ * digest-challenge = 1#( realm | nonce | qop-options | stale | maxbuf |
+ * charset | cipher-opts | auth-param )
+ */
+
+ nonce = create_nonce(sparams->utils);
+ if (nonce == NULL) {
+ SETERROR(sparams->utils, "internal erorr: failed creating a nonce");
+ return SASL_FAIL;
+ }
+
+ resplen = 0;
+ text->out_buf = NULL;
+ text->out_buf_len = 0;
+ if (add_to_challenge(sparams->utils,
+ &text->out_buf, &text->out_buf_len, &resplen,
+ "nonce", (unsigned char *) nonce,
+ TRUE) != SASL_OK) {
+ SETERROR(sparams->utils, "internal error: add_to_challenge failed");
+ return SASL_FAIL;
+ }
+
+ /* add to challenge; if we chose not to specify a realm, we won't
+ * send one to the client */
+ if (realm && add_to_challenge(sparams->utils,
+ &text->out_buf, &text->out_buf_len, &resplen,
+ "realm", (unsigned char *) realm,
+ TRUE) != SASL_OK) {
+ SETERROR(sparams->utils, "internal error: add_to_challenge failed");
+ return SASL_FAIL;
+ }
+ /*
+ * qop-options A quoted string of one or more tokens indicating the
+ * "quality of protection" values supported by the server. The value
+ * "auth" indicates authentication; the value "auth-int" indicates
+ * authentication with integrity protection; the value "auth-conf"
+ * indicates authentication with integrity protection and encryption.
+ */
+
+ /* add qop to challenge */
+ if (add_to_challenge(sparams->utils,
+ &text->out_buf, &text->out_buf_len, &resplen,
+ "qop",
+ (unsigned char *) qop, TRUE) != SASL_OK) {
+ SETERROR(sparams->utils, "internal error: add_to_challenge 3 failed");
+ return SASL_FAIL;
+ }
+
+ /*
+ * Cipheropts - list of ciphers server supports
+ */
+ /* add cipher-opts to challenge; only add if there are some */
+ if (strcmp(cipheropts,"")!=0)
+ {
+ if (add_to_challenge(sparams->utils,
+ &text->out_buf, &text->out_buf_len, &resplen,
+ "cipher", (unsigned char *) cipheropts,
+ TRUE) != SASL_OK) {
+ SETERROR(sparams->utils,
+ "internal error: add_to_challenge 4 failed");
+ return SASL_FAIL;
+ }
+ }
+
+ /* "stale" is true if a reauth failed because of a nonce timeout */
+ if (stext->stale &&
+ add_to_challenge(sparams->utils,
+ &text->out_buf, &text->out_buf_len, &resplen,
+ "stale", (unsigned char *) "true", FALSE) != SASL_OK) {
+ SETERROR(sparams->utils, "internal error: add_to_challenge failed");
+ return SASL_FAIL;
+ }
+
+ /*
+ * maxbuf A number indicating the size of the largest buffer the server
+ * is able to receive when using "auth-int". If this directive is
+ * missing, the default value is 65536. This directive may appear at most
+ * once; if multiple instances are present, the client should abort the
+ * authentication exchange.
+ */
+ if(sparams->props.maxbufsize) {
+ snprintf(maxbufstr, sizeof(maxbufstr), "%u",
+ sparams->props.maxbufsize);
+ if (add_to_challenge(sparams->utils,
+ &text->out_buf, &text->out_buf_len, &resplen,
+ "maxbuf",
+ (unsigned char *) maxbufstr, FALSE) != SASL_OK) {
+ SETERROR(sparams->utils,
+ "internal error: add_to_challenge 5 failed");
+ return SASL_FAIL;
+ }
+ }
+
+ if (add_to_challenge(sparams->utils,
+ &text->out_buf, &text->out_buf_len, &resplen,
+ "charset",
+ (unsigned char *) charset, FALSE) != SASL_OK) {
+ SETERROR(sparams->utils, "internal error: add_to_challenge 6 failed");
+ return SASL_FAIL;
+ }
+
+
+ /*
+ * algorithm
+ * This directive is required for backwards compatibility with HTTP
+ * Digest, which supports other algorithms. This directive is
+ * required and MUST appear exactly once; if not present, or if multiple
+ * instances are present, the client should abort the authentication
+ * exchange.
+ *
+ * algorithm = "algorithm" "=" "md5-sess"
+ */
+
+ if (add_to_challenge(sparams->utils,
+ &text->out_buf, &text->out_buf_len, &resplen,
+ "algorithm",
+ (unsigned char *) "md5-sess", FALSE)!=SASL_OK) {
+ SETERROR(sparams->utils, "internal error: add_to_challenge 7 failed");
+ return SASL_FAIL;
+ }
+
+ /*
+ * The size of a digest-challenge MUST be less than 2048 bytes!!!
+ */
+ if (*serveroutlen > 2048) {
+ SETERROR(sparams->utils,
+ "internal error: challenge larger than 2048 bytes");
+ return SASL_FAIL;
+ }
+
+ text->authid = NULL;
+ if (_plug_strdup(sparams->utils, realm, &text->realm, NULL) != SASL_OK) {
+ SETERROR(sparams->utils,
+ "internal error: out of memory when saving realm");
+ return SASL_FAIL;
+ }
+
+ if (text->http_mode && text->reauth->timeout &&
+ sparams->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
+
+ /* Create an initial cache entry for non-persistent HTTP connections */
+ unsigned val = hash((char *) nonce) % text->reauth->size;
+
+ clear_reauth_entry(&text->reauth->e[val], SERVER, sparams->utils);
+ text->reauth->e[val].authid = NULL;
+ text->reauth->e[val].realm = text->realm; text->realm = NULL;
+ text->reauth->e[val].nonce = nonce;
+ text->reauth->e[val].nonce_count = 1;
+ text->reauth->e[val].cnonce = NULL;
+ text->reauth->e[val].u.s.timestamp = time(0);
+
+ sparams->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
+ }
+ else {
+ text->nonce = nonce;
+ text->nonce_count = 1;
+ text->cnonce = NULL;
+ stext->timestamp = time(0);
+ }
+
+ *serveroutlen = (unsigned) strlen(text->out_buf);
+ *serverout = text->out_buf;
+
+ text->state = 2;
+
+ return SASL_CONTINUE;
+}
+
+static int digestmd5_server_mech_step2(server_context_t *stext,
+ sasl_server_params_t *sparams,
+ const char *clientin,
+ unsigned clientinlen,
+ const char **serverout,
+ unsigned *serveroutlen,
+ sasl_out_params_t * oparams)
+{
+ context_t *text = (context_t *) stext;
+ /* verify digest */
+ sasl_secret_t *sec = NULL;
+ int result;
+ char *serverresponse = NULL;
+ char *username = NULL;
+ char *authorization_id = NULL;
+ char *realm = NULL;
+ unsigned char *nonce = NULL, *cnonce = NULL;
+ unsigned int noncecount = 0;
+ char *qop = NULL;
+ char *digesturi = NULL;
+ sasl_http_request_t rfc2831_request;
+ const sasl_http_request_t *request;
+ char *response = NULL;
+
+ /* setting the default value (65536) */
+ unsigned long client_maxbuf = 65536;
+ int maxbuf_count = 0; /* How many maxbuf instances was found */
+
+ char *charset = NULL;
+ char *cipher = NULL;
+ unsigned int n = 0;
+
+ HASH Secret;
+ HASH SecretBogus;
+ bool Try_8859_1 = FALSE;
+ int client_ignores_realm = 0;
+ char *full_username = NULL;
+ char *internal_username = NULL;
+ int canon_flags;
+
+ /* password prop_request */
+ const char *password_request[] = { SASL_AUX_PASSWORD,
+#if defined(OBSOLETE_DIGEST_ATTR)
+ "*cmusaslsecretDIGEST-MD5",
+#endif
+ NULL };
+ size_t len;
+ struct propval auxprop_values[2];
+
+ /* can we mess with clientin? copy it to be safe */
+ char *in_start = NULL;
+ char *in = NULL;
+ cipher_free_t *old_cipher_free = NULL;
+
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_DEBUG,
+ "DIGEST-MD5 server step 2");
+
+ if (clientinlen == 0) {
+ SETERROR(sparams->utils, "input expected in DIGEST-MD5, step 2");
+ result = SASL_BADAUTH;
+ goto FreeAllMem;
+ }
+
+ if (text->http_mode) {
+ /* per RFC 2617 (HTTP Request as set by calling application) */
+ request = sparams->http_request;
+ if (!request) {
+ SETERROR(sparams->utils,
+ "missing HTTP request in DIGEST-MD5, step 2");
+ result = SASL_BADPARAM;
+ goto FreeAllMem;
+ }
+ }
+ else {
+ /* per RFC 2831 */
+ rfc2831_request.method = "AUTHENTICATE";
+ rfc2831_request.uri = NULL; /* to be filled in below from response */
+ rfc2831_request.entity = NULL;
+ rfc2831_request.elen = 0;
+ rfc2831_request.non_persist = 0;
+ request = &rfc2831_request;
+ }
+
+ in = sparams->utils->malloc(clientinlen + 1);
+
+ memcpy(in, clientin, clientinlen);
+ in[clientinlen] = 0;
+
+ in_start = in;
+
+
+ /* parse what we got */
+ while (in[0] != '\0') {
+ char *name = NULL, *value = NULL;
+ get_pair(&in, &name, &value);
+
+ if (name == NULL) {
+ SETERROR(sparams->utils,
+ "Parse error");
+ result = SASL_BADAUTH;
+ goto FreeAllMem;
+ }
+
+ if (*name == '\0') {
+ break;
+ }
+
+ /* Extracting parameters */
+
+ /*
+ * digest-response = 1#( username | realm | nonce | cnonce |
+ * nonce-count | qop | digest-uri | response | maxbuf | charset |
+ * cipher | auth-param )
+ */
+
+ if (strcasecmp(name, "username") == 0) {
+ _plug_strdup(sparams->utils, value, &username, NULL);
+ } else if (strcasecmp(name, "authzid") == 0) {
+ _plug_strdup(sparams->utils, value, &authorization_id, NULL);
+ } else if (strcasecmp(name, "cnonce") == 0) {
+ _plug_strdup(sparams->utils, value, (char **) &cnonce, NULL);
+ } else if (strcasecmp(name, "nc") == 0) {
+ if (htoi((unsigned char *) value, &noncecount) != SASL_OK) {
+ SETERROR(sparams->utils,
+ "error converting hex to int");
+ result = SASL_BADAUTH;
+ goto FreeAllMem;
+ }
+ } else if (strcasecmp(name, "realm") == 0) {
+ if (realm) {
+ SETERROR(sparams->utils,
+ "duplicate realm: authentication aborted");
+ result = SASL_FAIL;
+ goto FreeAllMem;
+ }
+ _plug_strdup(sparams->utils, value, &realm, NULL);
+ } else if (strcasecmp(name, "nonce") == 0) {
+ _plug_strdup(sparams->utils, value, (char **) &nonce, NULL);
+ } else if (strcasecmp(name, "qop") == 0) {
+ if (qop) {
+ SETERROR(sparams->utils,
+ "duplicate qop: authentication aborted");
+ result = SASL_FAIL;
+ goto FreeAllMem;
+ }
+ _plug_strdup(sparams->utils, value, &qop, NULL);
+ } else if (strcasecmp(name, "digest-uri") == 0 || /* per RFC 2831 */
+ (text->http_mode &&
+ strcasecmp(name, "uri") == 0)) { /* per RFC 2617 */
+ size_t service_len;
+
+ if (digesturi) {
+ SETERROR(sparams->utils,
+ "duplicate digest-uri: authentication aborted");
+ result = SASL_FAIL;
+ goto FreeAllMem;
+ }
+
+ _plug_strdup(sparams->utils, value, &digesturi, NULL);
+
+ if (text->http_mode && request && request->uri) {
+ /* Verify digest-uri matches HTTP request (per RFC 2617) */
+ if (strcmp(digesturi, request->uri)) {
+ result = SASL_BADAUTH;
+ SETERROR(sparams->utils,
+ "bad digest-uri: doesn't match HTTP request");
+ goto FreeAllMem;
+ }
+ }
+ else {
+ /* Verify digest-uri format (per RFC 2831):
+ *
+ * digest-uri-value = serv-type "/" host [ "/" serv-name ]
+ */
+
+ /* make sure it's the service that we're expecting */
+ service_len = strlen(sparams->service);
+ if (strncasecmp(digesturi, sparams->service, service_len) ||
+ digesturi[service_len] != '/') {
+ result = SASL_BADAUTH;
+ SETERROR(sparams->utils,
+ "bad digest-uri: doesn't match service");
+ goto FreeAllMem;
+ }
+
+ /* xxx we don't verify the hostname component */
+
+ rfc2831_request.uri = digesturi;
+ }
+
+ } else if (strcasecmp(name, "response") == 0) {
+ _plug_strdup(sparams->utils, value, &response, NULL);
+ } else if (strcasecmp(name, "cipher") == 0) {
+ _plug_strdup(sparams->utils, value, &cipher, NULL);
+ } else if (strcasecmp(name, "maxbuf") == 0) {
+ maxbuf_count++;
+ if (maxbuf_count != 1) {
+ result = SASL_BADAUTH;
+ SETERROR(sparams->utils,
+ "duplicate maxbuf: authentication aborted");
+ goto FreeAllMem;
+ } else if (str2ul32 (value, &client_maxbuf) == FALSE) {
+ result = SASL_BADAUTH;
+ SETERROR(sparams->utils, "invalid maxbuf parameter");
+ goto FreeAllMem;
+ } else {
+ if (client_maxbuf <= 16) {
+ result = SASL_BADAUTH;
+ SETERROR(sparams->utils,
+ "maxbuf parameter too small");
+ goto FreeAllMem;
+ }
+
+ if (client_maxbuf > MAX_SASL_BUFSIZE) {
+ result = SASL_BADAUTH;
+ SETERROR(sparams->utils,
+ "maxbuf parameter too big");
+ goto FreeAllMem;
+ }
+ }
+ } else if (strcasecmp(name, "charset") == 0) {
+ if (strcasecmp(value, "utf-8") != 0) {
+ SETERROR(sparams->utils, "client doesn't support UTF-8");
+ result = SASL_FAIL;
+ goto FreeAllMem;
+ }
+ _plug_strdup(sparams->utils, value, &charset, NULL);
+ } else if (strcasecmp(name,"algorithm") == 0) {
+ /* per RFC 2831: algorithm MUST be ignored if received */
+ if (text->http_mode && strcasecmp(value, "md5-sess") != 0) {
+ /* per RFC 2617: algorithm MUST match that sent in challenge */
+ SETERROR(sparams->utils, "'algorithm' isn't 'md5-sess'");
+ result = SASL_FAIL;
+ goto FreeAllMem;
+ }
+ } else {
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_DEBUG,
+ "DIGEST-MD5 unrecognized pair %s/%s: ignoring",
+ name, value);
+ }
+ }
+
+ /*
+ * username = "username" "=" <"> username-value <">
+ * username-value = qdstr-val
+ * cnonce = "cnonce" "=" <"> cnonce-value <">
+ * cnonce-value = qdstr-val
+ * nonce-count = "nc" "=" nc-value
+ * nc-value = 8LHEX
+ * qop = "qop" "=" qop-value
+ * digest-uri = "digest-uri" "=" digest-uri-value
+ * digest-uri-value = serv-type "/" host [ "/" serv-name ]
+ * serv-type = 1*ALPHA
+ * host = 1*( ALPHA | DIGIT | "-" | "." )
+ * service = host
+ * response = "response" "=" <"> response-value <">
+ * response-value = 32LHEX
+ * LHEX = "0" | "1" | "2" | "3" | "4" | "5" |
+ * "6" | "7" | "8" | "9" | "a" | "b" | "c" | "d" | "e" | "f"
+ * cipher = "cipher" "=" cipher-value
+ */
+ /* Verifing that all required parameters were received */
+ if ((username == NULL)) {
+ SETERROR(sparams->utils, "required parameters missing: username");
+ result = SASL_BADAUTH;
+ goto FreeAllMem;
+ }
+ if ((nonce == NULL)) {
+ SETERROR(sparams->utils, "required parameters missing: nonce");
+ result = SASL_BADAUTH;
+ goto FreeAllMem;
+ }
+ if ((noncecount == 0)) {
+ SETERROR(sparams->utils, "required parameters missing: noncecount");
+ result = SASL_BADAUTH;
+ goto FreeAllMem;
+ }
+ if ((cnonce == NULL)) {
+ SETERROR(sparams->utils, "required parameters missing: cnonce");
+ result = SASL_BADAUTH;
+ goto FreeAllMem;
+ }
+ if ((digesturi == NULL)) {
+ SETERROR(sparams->utils, "required parameters missing: digesturi");
+ result = SASL_BADAUTH;
+ goto FreeAllMem;
+ }
+ if ((response == NULL)) {
+ SETERROR(sparams->utils, "required parameters missing: response");
+ result = SASL_BADAUTH;
+ goto FreeAllMem;
+ }
+
+ if (realm == NULL) {
+ /* From 2831bis:
+ If the directive is missing, "realm-value" will set to
+ the empty string when computing A1. */
+ _plug_strdup(sparams->utils, "", &realm, NULL);
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_DEBUG,
+ "The client didn't send a realm, assuming empty string.");
+#if 0
+ if (text->realm[0] != '\0') {
+ SETERROR(sparams->utils,
+ "realm changed: authentication aborted");
+ result = SASL_BADAUTH;
+ goto FreeAllMem;
+ }
+#endif
+ }
+
+ if (!text->nonce && text->reauth->timeout && text->reauth->size > 0) {
+ unsigned val = hash((char *) nonce) % text->reauth->size;
+
+ /* reauth attempt or continuation of HTTP Digest on a
+ non-persistent connection, see if we have any info for this nonce */
+ if (sparams->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
+ if (text->reauth->e[val].realm &&
+ !strcmp(realm, text->reauth->e[val].realm) &&
+ ((text->reauth->e[val].nonce_count == 1) ||
+ (text->reauth->e[val].authid &&
+ !strcmp(username, text->reauth->e[val].authid)))) {
+
+ _plug_strdup(sparams->utils, text->reauth->e[val].realm,
+ &text->realm, NULL);
+ _plug_strdup(sparams->utils, (char *) text->reauth->e[val].nonce,
+ (char **) &text->nonce, NULL);
+ text->nonce_count = text->reauth->e[val].nonce_count;
+#if 0 /* XXX Neither RFC 2617 nor RFC 2831 state that the cnonce
+ needs to remain constant for subsequent authentication to work */
+ _plug_strdup(sparams->utils, (char *) text->reauth->e[val].cnonce,
+ (char **) &text->cnonce, NULL);
+#endif
+ stext->timestamp = text->reauth->e[val].u.s.timestamp;
+ }
+ sparams->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
+ }
+
+ if (!text->nonce) {
+ /* we don't have any reauth info */
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_DEBUG,
+ "No reauth info for '%s' found", nonce);
+
+ /* we will continue processing the response to determine
+ if the client knows the password and return stale accordingly */
+ }
+ }
+
+ /* Sanity check the parameters */
+ if (text->nonce) {
+ /* CLAIM: realm is not NULL below */
+ if (text->realm == NULL) {
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_DEBUG,
+ "The client specifies a realm when the server hasn't provided one. Using client's realm.");
+ _plug_strdup(sparams->utils, realm, &text->realm, NULL);
+ } else if ((strcmp(realm, text->realm) != 0) &&
+ /* XXX - Not sure why the check for text->realm not being empty is needed,
+ as it should always be non-empty */
+ (text->realm[0] != 0)) {
+
+ client_ignores_realm = 1;
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_DEBUG,
+ "The client tries to override server provided realm");
+ if (text->realm) sparams->utils->free(text->realm);
+ _plug_strdup(sparams->utils, realm, &text->realm, NULL);
+ }
+
+ if (strcmp((char *) nonce, (char *) text->nonce) != 0) {
+ SETERROR(sparams->utils,
+ "nonce changed: authentication aborted");
+ result = SASL_BADAUTH;
+ goto FreeAllMem;
+ }
+#if 0 /* XXX Possible replay attack, but we will continue processing
+ * the response to determine if the client knows the password and
+ return stale accordingly */
+ if (noncecount != text->nonce_count) {
+ SETERROR(sparams->utils,
+ "incorrect nonce-count: authentication aborted");
+ result = SASL_BADAUTH;
+ goto FreeAllMem;
+ }
+#endif
+#if 0 /* XXX Neither RFC 2617 nor RFC 2831 state that the cnonce
+ needs to remain constant for subsequent authentication to work */
+ if (text->cnonce && strcmp((char *) cnonce, (char *) text->cnonce) != 0) {
+ SETERROR(sparams->utils,
+ "cnonce changed: authentication aborted");
+ result = SASL_BADAUTH;
+ goto FreeAllMem;
+ }
+#endif
+ }
+
+ result = sparams->utils->prop_request(sparams->propctx, password_request);
+ if(result != SASL_OK) {
+ SETERROR(sparams->utils, "unable to obtain user password");
+ goto FreeAllMem;
+ }
+
+ /* this will trigger the getting of the aux properties */
+ /* Note that if we don't have an authorization id, we don't use it... */
+
+ if (client_ignores_realm) {
+ if (strlen(text->realm) == 0) {
+ /* Don't put @ at the end of the username, if the realm is empty */
+ _plug_strdup(sparams->utils, username, &full_username, NULL);
+ } else {
+ full_username = (char *) sparams->utils->malloc(strlen(username) +
+ strlen(text->realm) + 2);
+ full_username[0] = '\0';
+ sprintf (full_username, "%s@%s", username, text->realm);
+ }
+ internal_username = full_username;
+ } else {
+ internal_username = username;
+ }
+
+ canon_flags = SASL_CU_AUTHID;
+ if (!authorization_id || !*authorization_id) {
+ canon_flags |= SASL_CU_AUTHZID;
+ }
+
+ result = sparams->canon_user(sparams->utils->conn,
+ internal_username,
+ 0,
+ canon_flags,
+ oparams);
+ if (result != SASL_OK) {
+ SETERROR(sparams->utils, "unable to canonify user and get auxprops");
+ goto FreeAllMem;
+ }
+
+ if (authorization_id != NULL && *authorization_id != '\0') {
+ result = sparams->canon_user(sparams->utils->conn,
+ authorization_id, 0, SASL_CU_AUTHZID,
+ oparams);
+ }
+ if (result != SASL_OK) {
+ SETERROR(sparams->utils, "unable to canonify authorization ID");
+ goto FreeAllMem;
+ }
+
+ result = sparams->utils->prop_getnames(sparams->propctx, password_request,
+ auxprop_values);
+ if (result < 0 ||
+ ((!auxprop_values[0].name || !auxprop_values[0].values)
+#if defined(OBSOLETE_DIGEST_ATTR)
+ && (!auxprop_values[1].name || !auxprop_values[1].values)
+#endif
+ )) {
+ /* We didn't find this username */
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "no secret in database");
+ result = sparams->transition ? SASL_TRANS : SASL_NOUSER;
+ goto FreeAllMem;
+ }
+
+ if (auxprop_values[0].name && auxprop_values[0].values) {
+ len = strlen(auxprop_values[0].values[0]);
+ if (len == 0) {
+ sparams->utils->seterror(sparams->utils->conn,0,
+ "empty secret");
+ result = SASL_FAIL;
+ goto FreeAllMem;
+ }
+
+ sec = sparams->utils->malloc(sizeof(sasl_secret_t) + len);
+ if (!sec) {
+ SETERROR(sparams->utils, "unable to allocate secret");
+ result = SASL_FAIL;
+ goto FreeAllMem;
+ }
+
+ sec->len = (unsigned) len;
+ strncpy((char *) sec->data, auxprop_values[0].values[0], len + 1);
+
+ /*
+ * Verifying response obtained from client
+ *
+ * H_URP = H({ username-value,":",realm-value,":",passwd}) sec->data
+ * contains H_URP
+ */
+
+ /* Calculate the secret from the plaintext password */
+ {
+ /*
+ * Secret = { H( { username-value, ":", realm-value, ":", passwd } ) }
+ *
+ * (used to build A1)
+ */
+
+ Try_8859_1 = DigestCalcSecret(sparams->utils,
+ (unsigned char *) username,
+ (unsigned char *) realm,
+ sec->data,
+ sec->len,
+ FALSE,
+ Secret);
+ Secret[HASHLEN] = '\0';
+ }
+ if (Try_8859_1) {
+ /*
+ * Secret = { H( { username-value, ":", realm-value, ":", passwd } ) }
+ *
+ * (used to build A1)
+ */
+
+ DigestCalcSecret(sparams->utils,
+ (unsigned char *) username,
+ (unsigned char *) realm,
+ sec->data,
+ sec->len,
+ TRUE,
+ SecretBogus);
+ SecretBogus[HASHLEN] = '\0';
+ }
+
+ /* We're done with sec now. Let's get rid of it */
+ _plug_free_secret(sparams->utils, &sec);
+#if defined(OBSOLETE_DIGEST_ATTR)
+ } else if (auxprop_values[1].name && auxprop_values[1].values) {
+ /* NB: This will most likely fail for clients that
+ choose to ignore server-advertised realm */
+ memcpy(Secret, auxprop_values[1].values[0], HASHLEN);
+ Secret[HASHLEN] = '\0';
+#endif
+ } else {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "Have neither type of secret");
+ return SASL_FAIL;
+ }
+
+ /* erase the plaintext password */
+ sparams->utils->prop_erase(sparams->propctx, password_request[0]);
+
+ /* defaulting qop to "auth" if not specified */
+ if (qop == NULL) {
+ _plug_strdup(sparams->utils, "auth", &qop, NULL);
+ }
+
+ if (oparams->mech_ssf > 1) {
+ /* Remember the old cipher free function (if any).
+ It will be called later, once we are absolutely
+ sure that authentication was successful. */
+ old_cipher_free = text->cipher_free;
+ /* free the old cipher context first */
+ }
+
+ /* check which layer/cipher to use */
+ if ((!strcasecmp(qop, "auth-conf")) && (cipher != NULL)) {
+ /* see what cipher was requested */
+ struct digest_cipher *cptr;
+
+ cptr = available_ciphers;
+ while (cptr->name) {
+ /* find the cipher requested & make sure it's one we're happy
+ with by policy */
+ if (!strcasecmp(cipher, cptr->name) &&
+ stext->requiressf <= cptr->ssf &&
+ stext->limitssf >= cptr->ssf) {
+ /* found it! */
+ break;
+ }
+ cptr++;
+ }
+
+ if (cptr->name) {
+ text->cipher_enc = cptr->cipher_enc;
+ text->cipher_dec = cptr->cipher_dec;
+ text->cipher_init = cptr->cipher_init;
+ text->cipher_free = cptr->cipher_free;
+ oparams->mech_ssf = cptr->ssf;
+ n = cptr->n;
+ } else {
+ /* erg? client requested something we didn't advertise! */
+ sparams->utils->log(sparams->utils->conn, SASL_LOG_WARN,
+ "protocol violation: client requested invalid cipher");
+ SETERROR(sparams->utils, "client requested invalid cipher");
+ /* Mark that we attempted security layer negotiation */
+ oparams->mech_ssf = 2;
+ result = SASL_FAIL;
+ goto FreeAllMem;
+ }
+
+ oparams->encode=&digestmd5_encode;
+ oparams->decode=&digestmd5_decode;
+ } else if (!strcasecmp(qop, "auth-int") &&
+ stext->requiressf <= 1 && stext->limitssf >= 1) {
+ oparams->encode = &digestmd5_encode;
+ oparams->decode = &digestmd5_decode;
+ oparams->mech_ssf = 1;
+ } else if (!strcasecmp(qop, "auth") && stext->requiressf == 0) {
+ oparams->encode = NULL;
+ oparams->decode = NULL;
+ oparams->mech_ssf = 0;
+ } else {
+ SETERROR(sparams->utils,
+ "protocol violation: client requested invalid qop");
+ result = SASL_FAIL;
+ goto FreeAllMem;
+ }
+
+ serverresponse = create_response(text,
+ sparams->utils,
+ nonce,
+ noncecount,
+ cnonce,
+ qop,
+ request,
+ Secret,
+ authorization_id,
+ &text->response_value);
+
+ if (serverresponse == NULL) {
+ SETERROR(sparams->utils, "internal error: unable to create response");
+ result = SASL_NOMEM;
+ goto FreeAllMem;
+ }
+
+ /* if ok verified */
+ if (strcmp(serverresponse, response) != 0) {
+ if (Try_8859_1) {
+ sparams->utils->free(serverresponse);
+ serverresponse = create_response(text,
+ sparams->utils,
+ nonce,
+ noncecount,
+ cnonce,
+ qop,
+ request,
+ SecretBogus,
+ authorization_id,
+ &text->response_value);
+
+ if (serverresponse == NULL) {
+ SETERROR(sparams->utils, "internal error: unable to create response");
+ result = SASL_NOMEM;
+ goto FreeAllMem;
+ }
+
+ /* if ok verified */
+ if (strcmp(serverresponse, response) != 0) {
+ SETERROR(sparams->utils,
+ "client response doesn't match what we generated (tried bogus)");
+ result = SASL_BADAUTH;
+
+ goto FreeAllMem;
+ }
+
+ } else {
+ SETERROR(sparams->utils,
+ "client response doesn't match what we generated");
+ result = SASL_BADAUTH;
+
+ goto FreeAllMem;
+ }
+ }
+
+ /* see if our nonce expired */
+ if (!text->nonce ||
+ (noncecount != text->nonce_count) ||
+ (text->reauth->timeout &&
+ time(0) - stext->timestamp > text->reauth->timeout)) {
+ if (!text->nonce) SETERROR(sparams->utils, "no cached server nonce");
+ else if (noncecount != text->nonce_count)
+ SETERROR(sparams->utils, "incorrect nonce-count");
+ else SETERROR(sparams->utils, "server nonce expired");
+ stext->stale = 1;
+ result = SASL_BADAUTH;
+
+ goto FreeAllMem;
+ }
+
+ /*
+ * nothing more to do; authenticated set oparams information
+ */
+ oparams->doneflag = 1;
+ oparams->maxoutbuf = client_maxbuf - 4;
+ if (oparams->mech_ssf > 1) {
+ /* MAC block (privacy) */
+ oparams->maxoutbuf -= 25;
+ } else if(oparams->mech_ssf == 1) {
+ /* MAC block (integrity) */
+ oparams->maxoutbuf -= 16;
+ }
+
+ oparams->param_version = 0;
+
+ text->seqnum = 0; /* for integrity/privacy */
+ text->rec_seqnum = 0; /* for integrity/privacy */
+ text->utils = sparams->utils;
+
+ /* Free the old security layer, if any */
+ if (old_cipher_free) old_cipher_free(text);
+
+ /* used by layers */
+ _plug_decode_init(&text->decode_context, text->utils,
+ sparams->props.maxbufsize ? sparams->props.maxbufsize :
+ DEFAULT_BUFSIZE);
+
+ if (oparams->mech_ssf > 0) {
+ unsigned char enckey[16];
+ unsigned char deckey[16];
+
+ create_layer_keys(text, sparams->utils,text->HA1,n,enckey,deckey);
+
+ /* initialize cipher if need be */
+ if (text->cipher_init) {
+ if (text->cipher_init(text, enckey, deckey) != SASL_OK) {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "couldn't init cipher");
+ }
+ }
+ }
+
+ /*
+ * The server receives and validates the "digest-response". The server
+ * checks that the nonce-count is "00000001". If it supports subsequent
+ * authentication, it saves the value of the nonce and the nonce-count.
+ */
+
+ /*
+ * The "username-value", "realm-value" and "passwd" are encoded according
+ * to the value of the "charset" directive. If "charset=UTF-8" is
+ * present, and all the characters of either "username-value" or "passwd"
+ * are in the ISO 8859-1 character set, then it must be converted to
+ * UTF-8 before being hashed. A sample implementation of this conversion
+ * is in section 8.
+ */
+
+ /* add to challenge */
+ {
+ unsigned resplen = 0;
+
+ if (add_to_challenge(sparams->utils,
+ &text->out_buf, &text->out_buf_len, &resplen,
+ "rspauth", (unsigned char *) text->response_value,
+ text->http_mode ? TRUE : FALSE) != SASL_OK) {
+ SETERROR(sparams->utils, "internal error: add_to_challenge failed");
+ result = SASL_FAIL;
+ goto FreeAllMem;
+ }
+
+ if (text->http_mode) {
+ /* per RFC 2617 */
+ char ncvalue[10];
+
+ if (add_to_challenge(sparams->utils,
+ &text->out_buf, &text->out_buf_len, &resplen,
+ "cnonce", cnonce, TRUE) != SASL_OK) {
+ result = SASL_FAIL;
+ goto FreeAllMem;
+ }
+ snprintf(ncvalue, sizeof(ncvalue), "%08x", text->nonce_count);
+ if (add_to_challenge(sparams->utils,
+ &text->out_buf, &text->out_buf_len, &resplen,
+ "nc", (unsigned char *) ncvalue, FALSE) != SASL_OK) {
+ result = SASL_FAIL;
+ goto FreeAllMem;
+ }
+ if (add_to_challenge(sparams->utils,
+ &text->out_buf, &text->out_buf_len, &resplen,
+ "qop", (unsigned char *) qop, TRUE) != SASL_OK) {
+ result = SASL_FAIL;
+ goto FreeAllMem;
+ }
+ }
+
+ /* self check */
+ if (strlen(text->out_buf) > 2048) {
+ result = SASL_FAIL;
+ goto FreeAllMem;
+ }
+ }
+
+ *serveroutlen = (unsigned) strlen(text->out_buf);
+ *serverout = text->out_buf;
+
+ result = SASL_OK;
+
+ FreeAllMem:
+ if (clientinlen > 0 &&
+ text->reauth->timeout &&
+ sparams->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
+
+ /* Look for an entry for the nonce value */
+ unsigned val = hash((char *) nonce) % text->reauth->size;
+
+ switch (result) {
+ case SASL_OK:
+ /* successful auth, setup for future reauth */
+ if (text->nonce_count == 1) {
+ /* successful initial auth, create new entry */
+ clear_reauth_entry(&text->reauth->e[val], SERVER, sparams->utils);
+ text->reauth->e[val].authid = username; username = NULL;
+ text->reauth->e[val].realm = text->realm; text->realm = NULL;
+ text->reauth->e[val].nonce = text->nonce; text->nonce = NULL;
+ text->reauth->e[val].cnonce = cnonce; cnonce = NULL;
+ }
+ if (text->nonce_count < text->reauth->e[val].nonce_count) {
+ /* paranoia. prevent replay attacks */
+ clear_reauth_entry(&text->reauth->e[val], SERVER, sparams->utils);
+ }
+ else {
+ text->reauth->e[val].nonce_count = ++text->nonce_count;
+ text->reauth->e[val].u.s.timestamp = time(0);
+ }
+ break;
+ default:
+ if (text->nonce_count > 1) {
+ /* failed reauth, clear entry */
+ clear_reauth_entry(&text->reauth->e[val], SERVER, sparams->utils);
+ }
+ else {
+ /* failed initial auth, leave existing cache */
+ }
+ }
+ sparams->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
+ }
+
+ /* free everything */
+ if (in_start) sparams->utils->free (in_start);
+
+ if (full_username != NULL)
+ sparams->utils->free (full_username);
+ if (username != NULL)
+ sparams->utils->free (username);
+ if (authorization_id != NULL)
+ sparams->utils->free (authorization_id);
+ if (realm != NULL)
+ sparams->utils->free (realm);
+ if (nonce != NULL)
+ sparams->utils->free (nonce);
+ if (cnonce != NULL)
+ sparams->utils->free (cnonce);
+ if (response != NULL)
+ sparams->utils->free (response);
+ if (cipher != NULL)
+ sparams->utils->free (cipher);
+ if (serverresponse != NULL)
+ sparams->utils->free(serverresponse);
+ if (charset != NULL)
+ sparams->utils->free (charset);
+ if (digesturi != NULL)
+ sparams->utils->free (digesturi);
+ if (qop!=NULL)
+ sparams->utils->free (qop);
+ if (sec)
+ _plug_free_secret(sparams->utils, &sec);
+
+ return result;
+}
+
+static int digestmd5_server_mech_step(void *conn_context,
+ sasl_server_params_t *sparams,
+ const char *clientin,
+ unsigned clientinlen,
+ const char **serverout,
+ unsigned *serveroutlen,
+ sasl_out_params_t *oparams)
+{
+ context_t *text = (context_t *) conn_context;
+ server_context_t *stext = (server_context_t *) conn_context;
+
+ *serverout = NULL;
+ *serveroutlen = 0;
+
+ if (clientinlen > 4096) return SASL_BADPROT;
+
+ if (text == NULL) {
+ return SASL_BADPROT;
+ }
+
+ switch (text->state) {
+
+ case 1:
+ /* setup SSF limits */
+ if (!text->http_mode && /* HTTP Digest doesn't need buffer */
+ !sparams->props.maxbufsize) {
+ stext->limitssf = 0;
+ stext->requiressf = 0;
+ } else {
+ if (sparams->props.max_ssf < sparams->external_ssf) {
+ stext->limitssf = 0;
+ } else {
+ stext->limitssf =
+ sparams->props.max_ssf - sparams->external_ssf;
+ }
+ if (sparams->props.min_ssf < sparams->external_ssf) {
+ stext->requiressf = 0;
+ } else {
+ stext->requiressf =
+ sparams->props.min_ssf - sparams->external_ssf;
+ }
+ }
+
+ if (clientin && text->reauth->timeout) {
+ /* here's where we attempt fast reauth if possible */
+ if (digestmd5_server_mech_step2(stext, sparams,
+ clientin, clientinlen,
+ serverout, serveroutlen,
+ oparams) == SASL_OK) {
+ return SASL_OK;
+ }
+
+ sparams->utils->log(NULL, SASL_LOG_WARN,
+ "DIGEST-MD5 reauth failed\n");
+
+ /* re-initialize everything for a fresh start */
+ memset(oparams, 0, sizeof(sasl_out_params_t));
+ if (text->nonce) sparams->utils->free(text->nonce);
+ if (text->realm) sparams->utils->free(text->realm);
+ text->realm = NULL;
+ text->nonce = NULL;
+
+ /* fall through and issue challenge */
+ }
+
+ return digestmd5_server_mech_step1(stext, sparams,
+ clientin, clientinlen,
+ serverout, serveroutlen, oparams);
+
+ case 2:
+ return digestmd5_server_mech_step2(stext, sparams,
+ clientin, clientinlen,
+ serverout, serveroutlen, oparams);
+
+ default:
+ sparams->utils->log(NULL, SASL_LOG_ERR,
+ "Invalid DIGEST-MD5 server step %d\n", text->state);
+ return SASL_FAIL;
+ }
+
+ return SASL_FAIL; /* should never get here */
+}
+
+static void digestmd5_server_mech_dispose(void *conn_context,
+ const sasl_utils_t *utils)
+{
+ server_context_t *stext = (server_context_t *) conn_context;
+
+ if (!stext || !utils) return;
+
+ digestmd5_common_mech_dispose(conn_context, utils);
+}
+
+static sasl_server_plug_t digestmd5_server_plugins[] =
+{
+ {
+ "DIGEST-MD5", /* mech_name */
+#ifdef WITH_RC4
+ 128, /* max_ssf */
+#elif defined(WITH_DES)
+ 112,
+#else
+ 1,
+#endif
+ SASL_SEC_NOPLAINTEXT
+ | SASL_SEC_NOANONYMOUS
+ | SASL_SEC_MUTUAL_AUTH, /* security_flags */
+ SASL_FEAT_ALLOWS_PROXY
+ | SASL_FEAT_SUPPORTS_HTTP, /* features */
+ &server_glob_context, /* glob_context */
+ &digestmd5_server_mech_new, /* mech_new */
+ &digestmd5_server_mech_step, /* mech_step */
+ &digestmd5_server_mech_dispose, /* mech_dispose */
+ &digestmd5_common_mech_free, /* mech_free */
+ NULL, /* setpass */
+ NULL, /* user_query */
+ NULL, /* idle */
+ NULL, /* mech avail */
+ NULL /* spare */
+ }
+};
+
+int digestmd5_server_plug_init(sasl_utils_t *utils,
+ int maxversion,
+ int *out_version,
+ sasl_server_plug_t **pluglist,
+ int *plugcount)
+{
+ reauth_cache_t *reauth_cache;
+ const char *timeout = NULL;
+ unsigned int len;
+
+ if (maxversion < SASL_SERVER_PLUG_VERSION) {
+ return SASL_BADVERS;
+ }
+
+ /* reauth cache */
+ reauth_cache = utils->malloc(sizeof(reauth_cache_t));
+ if (reauth_cache == NULL) {
+ return SASL_NOMEM;
+ }
+ memset(reauth_cache, 0, sizeof(reauth_cache_t));
+ reauth_cache->i_am = SERVER;
+
+ /* fetch and canonify the reauth_timeout */
+ utils->getopt(utils->getopt_context, "DIGEST-MD5", "reauth_timeout",
+ &timeout, &len);
+ if (timeout) {
+ reauth_cache->timeout = (time_t) 60 * strtol(timeout, NULL, 10);
+ }
+ if (reauth_cache->timeout < 0) {
+ reauth_cache->timeout = 0;
+ }
+
+ if (reauth_cache->timeout) {
+ /* mutex */
+ reauth_cache->mutex = utils->mutex_alloc();
+ if (!reauth_cache->mutex) {
+ utils->free(reauth_cache);
+ return SASL_FAIL;
+ }
+
+ /* entries */
+ reauth_cache->size = 100;
+ reauth_cache->e = utils->malloc(reauth_cache->size *
+ sizeof(reauth_entry_t));
+ if (reauth_cache->e == NULL) {
+ utils->mutex_free(reauth_cache->mutex);
+ utils->free(reauth_cache);
+ return SASL_NOMEM;
+ }
+ memset(reauth_cache->e, 0, reauth_cache->size * sizeof(reauth_entry_t));
+ }
+
+ ((digest_glob_context_t *) digestmd5_server_plugins[0].glob_context)->reauth = reauth_cache;
+
+ *out_version = SASL_SERVER_PLUG_VERSION;
+ *pluglist = digestmd5_server_plugins;
+ *plugcount = 1;
+
+ return SASL_OK;
+}
+
+/***************************** Client Section *****************************/
+
+typedef struct client_context {
+ context_t common;
+
+ sasl_secret_t *password; /* user password */
+ unsigned int free_password; /* set if we need to free password */
+
+ int protection;
+ struct digest_cipher *cipher;
+ unsigned long server_maxbuf;
+
+ /* for HTTP mode (RFC 2617) only */
+ char *algorithm;
+ unsigned char *opaque;
+} client_context_t;
+
+static digest_glob_context_t client_glob_context;
+
+/* calculate H(A1) as per spec */
+static void DigestCalcHA1(context_t * text,
+ const sasl_utils_t * utils,
+ char *pszAlg,
+ unsigned char *pszUserName,
+ unsigned char *pszRealm,
+ sasl_secret_t * pszPassword,
+ unsigned char *pszAuthorization_id,
+ unsigned char *pszNonce,
+ unsigned char *pszCNonce,
+ HASHHEX SessionKey)
+{
+ MD5_CTX Md5Ctx;
+ HASH HA1;
+
+ DigestCalcSecret(utils,
+ pszUserName,
+ pszRealm,
+ (unsigned char *) pszPassword->data,
+ pszPassword->len,
+ FALSE,
+ HA1);
+
+ if (!text->http_mode || /* per RFC 2831 */
+ (pszAlg && strcasecmp(pszAlg, "md5-sess") == 0)) { /* per RFC 2617 */
+ /* calculate the session key */
+ utils->MD5Init(&Md5Ctx);
+ if (text->http_mode) {
+ /* per RFC 2617 Errata ID 1649 */
+ HASHHEX HA1Hex;
+
+ CvtHex(HA1, HA1Hex);
+ utils->MD5Update(&Md5Ctx, HA1Hex, HASHHEXLEN);
+ }
+ else {
+ /* per RFC 2831 */
+ utils->MD5Update(&Md5Ctx, HA1, HASHLEN);
+ }
+ utils->MD5Update(&Md5Ctx, COLON, 1);
+ utils->MD5Update(&Md5Ctx, pszNonce, (unsigned) strlen((char *) pszNonce));
+ utils->MD5Update(&Md5Ctx, COLON, 1);
+ utils->MD5Update(&Md5Ctx, pszCNonce, (unsigned) strlen((char *) pszCNonce));
+ if (pszAuthorization_id != NULL) {
+ utils->MD5Update(&Md5Ctx, COLON, 1);
+ utils->MD5Update(&Md5Ctx, pszAuthorization_id,
+ (unsigned) strlen((char *) pszAuthorization_id));
+ }
+ utils->MD5Final(HA1, &Md5Ctx);
+ }
+
+ CvtHex(HA1, SessionKey);
+
+ /* xxx rc-* use different n */
+
+ /* save HA1 because we'll need it for the privacy and integrity keys */
+ memcpy(text->HA1, HA1, sizeof(HASH));
+
+}
+
+static char *calculate_response(context_t * text,
+ const sasl_utils_t * utils,
+ char *algorithm,
+ unsigned char *username,
+ unsigned char *realm,
+ unsigned char *nonce,
+ unsigned int ncvalue,
+ unsigned char *cnonce,
+ char *qop,
+ const sasl_http_request_t *request,
+ sasl_secret_t * passwd,
+ unsigned char *authorization_id,
+ char **response_value)
+{
+ HASHHEX SessionKey;
+ HASH EntityHash;
+ HASHHEX HEntity;
+ HASHHEX Response;
+ char *result;
+
+ /* Verifing that all parameters was defined */
+ if(!username || !cnonce || !nonce || !ncvalue || !request || !passwd) {
+ PARAMERROR( utils );
+ return NULL;
+ }
+
+ if (realm == NULL) {
+ /* a NULL realm is equivalent to the empty string */
+ realm = (unsigned char *) "";
+ }
+
+ if (qop == NULL) {
+ /* default to a qop of just authentication */
+ qop = "auth";
+ }
+
+ DigestCalcHA1(text,
+ utils,
+ algorithm,
+ username,
+ realm,
+ passwd,
+ authorization_id,
+ nonce,
+ cnonce,
+ SessionKey);
+
+ if (text->http_mode) {
+ /* per RFC 2617 */
+ MD5_CTX Md5Ctx;
+
+ utils->MD5Init(&Md5Ctx);
+ utils->MD5Update(&Md5Ctx, request->entity, request->elen);
+ utils->MD5Final(EntityHash, &Md5Ctx);
+ }
+ else {
+ /* per RFC 2831 */
+ memset(EntityHash, 0, HASHLEN);
+ }
+ CvtHex(EntityHash, HEntity);
+
+ DigestCalcResponse(utils,
+ SessionKey,/* HEX(H(A1)) */
+ nonce, /* nonce from server */
+ ncvalue, /* 8 hex digits */
+ cnonce, /* client nonce */
+ (unsigned char *) qop, /* qop-value: "", "auth",
+ * "auth-int" */
+ (unsigned char *) request->uri, /* requested URL */
+ (unsigned char *) request->method,
+ HEntity, /* H(entity body) if qop="auth-int" */
+ Response /* request-digest or response-digest */
+ );
+
+ result = utils->malloc(HASHHEXLEN + 1);
+ memcpy(result, Response, HASHHEXLEN);
+ result[HASHHEXLEN] = 0;
+
+ if (response_value != NULL) {
+ char * new_response_value;
+
+ DigestCalcResponse(utils,
+ SessionKey, /* HEX(H(A1)) */
+ nonce, /* nonce from server */
+ ncvalue, /* 8 hex digits */
+ cnonce, /* client nonce */
+ (unsigned char *) qop, /* qop-value: "", "auth",
+ * "auth-int" */
+ (unsigned char *) request->uri, /* requested URL */
+ NULL,
+ HEntity, /* H(entity body) if qop="auth-int" */
+ Response /* request-digest or response-digest */
+ );
+
+ new_response_value = utils->realloc(*response_value, HASHHEXLEN + 1);
+ if (new_response_value == NULL) {
+ free (*response_value);
+ *response_value = NULL;
+ return NULL;
+ }
+ *response_value = new_response_value;
+
+ memcpy(*response_value, Response, HASHHEXLEN);
+ (*response_value)[HASHHEXLEN] = 0;
+
+ }
+
+ return result;
+}
+
+static int make_client_response(context_t *text,
+ sasl_client_params_t *params,
+ sasl_out_params_t *oparams)
+{
+ client_context_t *ctext = (client_context_t *) text;
+ char *qop = NULL;
+ unsigned nbits = 0;
+ char *digesturi = NULL;
+ bool IsUTF8 = FALSE;
+ char ncvalue[10];
+ char maxbufstr[64];
+ char *response = NULL;
+ unsigned resplen = 0;
+ int result = SASL_OK;
+ cipher_free_t *old_cipher_free = NULL;
+ sasl_http_request_t rfc2831_request;
+ const sasl_http_request_t *request;
+
+ params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
+ "DIGEST-MD5 make_client_response()");
+
+ if (oparams->mech_ssf > 1) {
+ /* Remember the old cipher free function (if any).
+ It will be called later, once we are absolutely
+ sure that authentication was successful. */
+ old_cipher_free = text->cipher_free;
+ /* free the old cipher context first */
+ }
+
+ switch (ctext->protection) {
+ case DIGEST_PRIVACY:
+ qop = "auth-conf";
+ oparams->encode = &digestmd5_encode;
+ oparams->decode = &digestmd5_decode;
+ oparams->mech_ssf = ctext->cipher->ssf;
+
+ nbits = ctext->cipher->n;
+ text->cipher_enc = ctext->cipher->cipher_enc;
+ text->cipher_dec = ctext->cipher->cipher_dec;
+ text->cipher_free = ctext->cipher->cipher_free;
+ text->cipher_init = ctext->cipher->cipher_init;
+ break;
+ case DIGEST_INTEGRITY:
+ qop = "auth-int";
+ oparams->encode = &digestmd5_encode;
+ oparams->decode = &digestmd5_decode;
+ oparams->mech_ssf = 1;
+ break;
+ case DIGEST_NOLAYER:
+ default:
+ qop = "auth";
+ oparams->encode = NULL;
+ oparams->decode = NULL;
+ oparams->mech_ssf = 0;
+ }
+
+ if (text->http_mode) {
+ /* per RFC 2617 (HTTP Request as set by calling application) */
+ request = params->http_request;
+ }
+ else {
+ /* per RFC 2831 */
+ digesturi = params->utils->malloc(strlen(params->service) + 1 +
+ strlen(params->serverFQDN) + 1 +
+ 1);
+ if (digesturi == NULL) {
+ result = SASL_NOMEM;
+ goto FreeAllocatedMem;
+ }
+
+ /* allocated exactly this. safe */
+ strcpy(digesturi, params->service);
+ strcat(digesturi, "/");
+ strcat(digesturi, params->serverFQDN);
+ /*
+ * strcat (digesturi, "/"); strcat (digesturi, params->serverFQDN);
+ */
+
+ rfc2831_request.method = "AUTHENTICATE";
+ rfc2831_request.uri = digesturi;
+ rfc2831_request.entity = NULL;
+ rfc2831_request.elen = 0;
+ rfc2831_request.non_persist = 0;
+ request = &rfc2831_request;
+ }
+
+ /* response */
+ response =
+ calculate_response(text,
+ params->utils,
+ ctext->algorithm,
+ (unsigned char *) oparams->authid,
+ (unsigned char *) text->realm,
+ text->nonce,
+ text->nonce_count,
+ text->cnonce,
+ qop,
+ request,
+ ctext->password,
+ strcmp(oparams->user, oparams->authid) ?
+ (unsigned char *) oparams->user : NULL,
+ &text->response_value);
+
+
+ resplen = 0;
+ if (text->out_buf) params->utils->free(text->out_buf);
+ text->out_buf = NULL;
+ text->out_buf_len = 0;
+ if (add_to_challenge(params->utils,
+ &text->out_buf, &text->out_buf_len, &resplen,
+ "username", (unsigned char *) oparams->authid,
+ TRUE) != SASL_OK) {
+ result = SASL_FAIL;
+ goto FreeAllocatedMem;
+ }
+
+ if (add_to_challenge(params->utils,
+ &text->out_buf, &text->out_buf_len, &resplen,
+ "realm", (unsigned char *) text->realm,
+ TRUE) != SASL_OK) {
+ result = SASL_FAIL;
+ goto FreeAllocatedMem;
+ }
+ if (strcmp(oparams->user, oparams->authid)) {
+ if (add_to_challenge(params->utils,
+ &text->out_buf, &text->out_buf_len, &resplen,
+ "authzid", (unsigned char *) oparams->user, TRUE) != SASL_OK) {
+ result = SASL_FAIL;
+ goto FreeAllocatedMem;
+ }
+ }
+ if (add_to_challenge(params->utils,
+ &text->out_buf, &text->out_buf_len, &resplen,
+ "nonce", text->nonce, TRUE) != SASL_OK) {
+ result = SASL_FAIL;
+ goto FreeAllocatedMem;
+ }
+ if (add_to_challenge(params->utils,
+ &text->out_buf, &text->out_buf_len, &resplen,
+ "cnonce", text->cnonce, TRUE) != SASL_OK) {
+ result = SASL_FAIL;
+ goto FreeAllocatedMem;
+ }
+ snprintf(ncvalue, sizeof(ncvalue), "%08x", text->nonce_count);
+ if (add_to_challenge(params->utils,
+ &text->out_buf, &text->out_buf_len, &resplen,
+ "nc", (unsigned char *) ncvalue, FALSE) != SASL_OK) {
+ result = SASL_FAIL;
+ goto FreeAllocatedMem;
+ }
+ if (add_to_challenge(params->utils,
+ &text->out_buf, &text->out_buf_len, &resplen,
+ "qop", (unsigned char *) qop, FALSE) != SASL_OK) {
+ result = SASL_FAIL;
+ goto FreeAllocatedMem;
+ }
+ if (ctext->cipher != NULL) {
+ if (add_to_challenge(params->utils,
+ &text->out_buf, &text->out_buf_len, &resplen,
+ "cipher",
+ (unsigned char *) ctext->cipher->name,
+ FALSE) != SASL_OK) {
+ result = SASL_FAIL;
+ goto FreeAllocatedMem;
+ }
+ }
+
+ if (params->props.maxbufsize) {
+ snprintf(maxbufstr, sizeof(maxbufstr), "%d", params->props.maxbufsize);
+ if (add_to_challenge(params->utils,
+ &text->out_buf, &text->out_buf_len, &resplen,
+ "maxbuf", (unsigned char *) maxbufstr,
+ FALSE) != SASL_OK) {
+ SETERROR(params->utils,
+ "internal error: add_to_challenge maxbuf failed");
+ goto FreeAllocatedMem;
+ }
+ }
+
+ if (IsUTF8) {
+ if (add_to_challenge(params->utils,
+ &text->out_buf, &text->out_buf_len, &resplen,
+ "charset", (unsigned char *) "utf-8",
+ FALSE) != SASL_OK) {
+ result = SASL_FAIL;
+ goto FreeAllocatedMem;
+ }
+ }
+ if (add_to_challenge(params->utils,
+ &text->out_buf, &text->out_buf_len, &resplen,
+ text->http_mode ? "uri" /* per RFC 2617 */
+ : "digest-uri", /* per RFC 2831 */
+ (unsigned char *) request->uri,
+ TRUE) != SASL_OK) {
+ result = SASL_FAIL;
+ goto FreeAllocatedMem;
+ }
+ if (text->http_mode) {
+ /* per RFC 2617: algorithm & opaque MUST be sent back to server */
+ if (add_to_challenge(params->utils,
+ &text->out_buf, &text->out_buf_len, &resplen,
+ "algorithm", (unsigned char *) ctext->algorithm,
+ FALSE) != SASL_OK) {
+ result = SASL_FAIL;
+ goto FreeAllocatedMem;
+ }
+ if (ctext->opaque) {
+ if (add_to_challenge(params->utils,
+ &text->out_buf, &text->out_buf_len, &resplen,
+ "opaque", ctext->opaque, TRUE) != SASL_OK) {
+ result = SASL_FAIL;
+ goto FreeAllocatedMem;
+ }
+ }
+ }
+ if (add_to_challenge(params->utils,
+ &text->out_buf, &text->out_buf_len, &resplen,
+ "response", (unsigned char *) response,
+ FALSE) != SASL_OK) {
+
+ result = SASL_FAIL;
+ goto FreeAllocatedMem;
+ }
+
+ /* self check */
+ if (strlen(text->out_buf) > 2048) {
+ result = SASL_FAIL;
+ goto FreeAllocatedMem;
+ }
+
+ /* set oparams */
+ oparams->maxoutbuf = ctext->server_maxbuf;
+ if(oparams->mech_ssf > 1) {
+ /* MAC block (privacy) */
+ oparams->maxoutbuf -= 25;
+ } else if(oparams->mech_ssf == 1) {
+ /* MAC block (integrity) */
+ oparams->maxoutbuf -= 16;
+ }
+
+ text->seqnum = 0; /* for integrity/privacy */
+ text->rec_seqnum = 0; /* for integrity/privacy */
+ text->utils = params->utils;
+
+ /* Free the old security layer, if any */
+ if (old_cipher_free) old_cipher_free(text);
+
+ /* used by layers */
+ _plug_decode_init(&text->decode_context, text->utils,
+ params->props.maxbufsize ? params->props.maxbufsize :
+ DEFAULT_BUFSIZE);
+
+ if (oparams->mech_ssf > 0) {
+ unsigned char enckey[16];
+ unsigned char deckey[16];
+
+ create_layer_keys(text, params->utils, text->HA1, nbits,
+ enckey, deckey);
+
+ /* initialize cipher if need be */
+ if (text->cipher_init) {
+ text->cipher_init(text, enckey, deckey);
+ }
+ }
+
+ result = SASL_OK;
+
+ FreeAllocatedMem:
+ if (digesturi) params->utils->free(digesturi);
+ if (response) params->utils->free(response);
+
+ return result;
+}
+
+static int parse_server_challenge(client_context_t *ctext,
+ sasl_client_params_t *params,
+ const char *serverin, unsigned serverinlen,
+ char ***outrealms, int *noutrealm)
+{
+ context_t *text = (context_t *) ctext;
+ int result = SASL_OK;
+ char *in_start = NULL;
+ char *in = NULL;
+ char **realms = NULL;
+ int nrealm = 0;
+ sasl_ssf_t limit, musthave = 0;
+ sasl_ssf_t external;
+ int protection = 0;
+ int saw_qop = 0;
+ int ciphers = 0;
+ int maxbuf_count = 0;
+ int algorithm_count = 0;
+ int opaque_count = 0;
+
+ params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
+ "DIGEST-MD5 parse_server_challenge()");
+
+ if (!serverin || !serverinlen) {
+ params->utils->seterror(params->utils->conn, 0,
+ "no server challenge");
+ return SASL_FAIL;
+ }
+
+ in_start = in = params->utils->malloc(serverinlen + 1);
+ if (in == NULL) return SASL_NOMEM;
+
+ memcpy(in, serverin, serverinlen);
+ in[serverinlen] = 0;
+
+ ctext->server_maxbuf = 65536; /* Default value for maxbuf */
+
+ /* create a new cnonce */
+ text->cnonce = create_nonce(params->utils);
+ if (text->cnonce == NULL) {
+ params->utils->seterror(params->utils->conn, 0,
+ "failed to create cnonce");
+ result = SASL_FAIL;
+ goto FreeAllocatedMem;
+ }
+
+ /* parse the challenge */
+ while (in[0] != '\0') {
+ char *name, *value;
+
+ get_pair(&in, &name, &value);
+
+ /* if parse error */
+ if (name == NULL) {
+ params->utils->seterror(params->utils->conn, 0, "Parse error");
+ result = SASL_BADAUTH;
+ goto FreeAllocatedMem;
+ }
+
+ if (*name == '\0') {
+ break;
+ }
+
+ if (strcasecmp(name, "realm") == 0) {
+ nrealm++;
+
+ if(!realms)
+ realms = params->utils->malloc(sizeof(char *) * (nrealm + 1));
+ else
+ realms = params->utils->realloc(realms,
+ sizeof(char *) * (nrealm + 1));
+
+ if (realms == NULL) {
+ result = SASL_NOMEM;
+ goto FreeAllocatedMem;
+ }
+
+ _plug_strdup(params->utils, value, &realms[nrealm-1], NULL);
+ realms[nrealm] = NULL;
+ } else if (strcasecmp(name, "nonce") == 0) {
+ _plug_strdup(params->utils, value, (char **) &text->nonce,
+ NULL);
+ text->nonce_count = 1;
+ } else if (strcasecmp(name, "qop") == 0) {
+ saw_qop = 1;
+ while (value && *value) {
+ char *comma;
+ char *end_val;
+
+SKIP_SPACES_IN_QOP:
+ /* skipping spaces: */
+ value = skip_lws(value);
+ if (*value == '\0') {
+ break;
+ }
+
+ /* check for an extreme case when there is no data: LWSP ',' */
+ if (*value == ',') {
+ value++;
+ goto SKIP_SPACES_IN_QOP;
+ }
+
+ comma = strchr(value, ',');
+
+ if (comma != NULL) {
+ *comma++ = '\0';
+ }
+
+ /* skip LWSP at the end of the value (if any), skip_r_lws returns pointer to
+ the first LWSP character, NUL (if there were none) or NULL if the value
+ is entirely from LWSP characters */
+ end_val = skip_r_lws (value);
+ if (end_val == NULL) {
+ value = comma;
+ continue;
+ } else {
+ /* strip LWSP */
+ *end_val = '\0';
+ }
+
+ if (strcasecmp(value, "auth-conf") == 0) {
+ protection |= DIGEST_PRIVACY;
+ } else if (strcasecmp(value, "auth-int") == 0) {
+ protection |= DIGEST_INTEGRITY;
+ } else if (strcasecmp(value, "auth") == 0) {
+ protection |= DIGEST_NOLAYER;
+ } else {
+ params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
+ "Server supports unknown layer: %s\n",
+ value);
+ }
+
+ value = comma;
+ }
+ } else if (strcasecmp(name, "cipher") == 0) {
+ while (value && *value) {
+ struct digest_cipher *cipher = available_ciphers;
+ char *comma;
+ char *end_val;
+
+SKIP_SPACES_IN_CIPHER:
+ /* skipping spaces: */
+ value = skip_lws(value);
+ if (*value == '\0') {
+ break;
+ }
+
+ /* check for an extreme case when there is no data: LWSP ',' */
+ if (*value == ',') {
+ value++;
+ goto SKIP_SPACES_IN_CIPHER;
+ }
+
+ comma = strchr(value, ',');
+
+ if (comma != NULL) {
+ *comma++ = '\0';
+ }
+
+ /* skip LWSP at the end of the value, skip_r_lws returns pointer to
+ the first LWSP character or NULL */
+ end_val = skip_r_lws (value);
+ if (end_val == NULL) {
+ value = comma;
+ continue;
+ } else {
+ /* strip LWSP */
+ *end_val = '\0';
+ }
+
+ /* do we support this cipher? */
+ while (cipher->name) {
+ if (!strcasecmp(value, cipher->name)) break;
+ cipher++;
+ }
+ if (cipher->name) {
+ ciphers |= cipher->flag;
+ } else {
+ params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
+ "Server supports unknown cipher: %s\n",
+ value);
+ }
+
+ value = comma;
+ }
+ } else if (strcasecmp(name, "stale") == 0 && ctext->password) {
+ /* clear any cached password */
+ if (ctext->free_password)
+ _plug_free_secret(params->utils, &ctext->password);
+ ctext->password = NULL;
+ } else if (strcasecmp(name, "maxbuf") == 0) {
+ /* maxbuf A number indicating the size of the largest
+ * buffer the server is able to receive when using
+ * "auth-int". If this directive is missing, the default
+ * value is 65536. This directive may appear at most once;
+ * if multiple instances are present, the client should
+ * abort the authentication exchange.
+ */
+ maxbuf_count++;
+
+ if (maxbuf_count != 1) {
+ result = SASL_BADAUTH;
+ params->utils->seterror(params->utils->conn, 0,
+ "At least two maxbuf directives found. Authentication aborted");
+ goto FreeAllocatedMem;
+ }
+
+ if (str2ul32 (value, &ctext->server_maxbuf) == FALSE) {
+ result = SASL_BADAUTH;
+ params->utils->seterror(params->utils->conn, 0,
+ "Invalid maxbuf parameter received from server (%s)", value);
+ goto FreeAllocatedMem;
+ }
+
+ if (ctext->server_maxbuf <= 16) {
+ result = SASL_BADAUTH;
+ params->utils->seterror(params->utils->conn, 0,
+ "Invalid maxbuf parameter received from server (too small: %s)", value);
+ goto FreeAllocatedMem;
+ }
+
+ if (ctext->server_maxbuf > MAX_SASL_BUFSIZE) {
+ result = SASL_BADAUTH;
+ params->utils->seterror(params->utils->conn, 0,
+ "Invalid maxbuf parameter received from server (too big: %s)", value);
+ goto FreeAllocatedMem;
+ }
+ } else if (strcasecmp(name, "charset") == 0) {
+ if (strcasecmp(value, "utf-8") != 0) {
+ result = SASL_BADAUTH;
+ params->utils->seterror(params->utils->conn, 0,
+ "Charset must be UTF-8");
+ goto FreeAllocatedMem;
+ }
+ } else if (strcasecmp(name,"algorithm")==0) {
+ if (text->http_mode && strcasecmp(value, "md5") == 0) {
+ /* per RFC 2617: need to support both "md5" and "md5-sess" */
+ }
+ else if (strcasecmp(value, "md5-sess") != 0)
+ {
+ params->utils->seterror(params->utils->conn, 0,
+ "'algorithm' isn't 'md5-sess'");
+ result = SASL_FAIL;
+ goto FreeAllocatedMem;
+ }
+
+ if (text->http_mode) {
+ /* per RFC 2617: algorithm MUST be saved */
+ _plug_strdup(params->utils, value, (char **) &ctext->algorithm,
+ NULL);
+ }
+ algorithm_count++;
+ if (algorithm_count > 1)
+ {
+ params->utils->seterror(params->utils->conn, 0,
+ "Must see 'algorithm' only once");
+ result = SASL_FAIL;
+ goto FreeAllocatedMem;
+ }
+ } else if (strcasecmp(name,"opaque")==0) {
+ /* per RFC 2831: opaque MUST be ignored if received */
+ if (text->http_mode) {
+ /* per RFC 2617: opaque MUST be saved */
+ _plug_strdup(params->utils, value, (char **) &ctext->opaque,
+ NULL);
+ opaque_count++;
+ if (opaque_count > 1)
+ {
+ params->utils->seterror(params->utils->conn, 0,
+ "Must see 'opaque' only once");
+ result = SASL_FAIL;
+ goto FreeAllocatedMem;
+ }
+ }
+ } else {
+ params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
+ "DIGEST-MD5 unrecognized pair %s/%s: ignoring",
+ name, value);
+ }
+ }
+
+ if (protection == 0) {
+ /* From RFC 2831[bis]:
+ This directive is optional; if not present it defaults to "auth". */
+ if (saw_qop == 0) {
+ protection = DIGEST_NOLAYER;
+ } else {
+ result = SASL_BADAUTH;
+ params->utils->seterror(params->utils->conn, 0,
+ "Server doesn't support any known qop level");
+ goto FreeAllocatedMem;
+ }
+ }
+
+ if (algorithm_count != 1) {
+ params->utils->seterror(params->utils->conn, 0,
+ "Must see 'algorithm' once. Didn't see at all");
+ result = SASL_FAIL;
+ goto FreeAllocatedMem;
+ }
+
+ /* make sure we have everything we require */
+ if (text->nonce == NULL) {
+ params->utils->seterror(params->utils->conn, 0,
+ "Don't have nonce.");
+ result = SASL_FAIL;
+ goto FreeAllocatedMem;
+ }
+
+ /* get requested ssf */
+ external = params->external_ssf;
+
+ /* what do we _need_? how much is too much? */
+ if (!text->http_mode && /* HTTP Digest doesn't need buffer */
+ params->props.maxbufsize == 0) {
+ musthave = 0;
+ limit = 0;
+ } else {
+ if (params->props.max_ssf > external) {
+ limit = params->props.max_ssf - external;
+ } else {
+ limit = 0;
+ }
+ if (params->props.min_ssf > external) {
+ musthave = params->props.min_ssf - external;
+ } else {
+ musthave = 0;
+ }
+ }
+
+ /* we now go searching for an option that gives us at least "musthave"
+ and at most "limit" bits of ssf. */
+ if ((limit > 1) && (protection & DIGEST_PRIVACY)) {
+ struct digest_cipher *cipher;
+
+ /* let's find an encryption scheme that we like */
+ cipher = available_ciphers;
+ while (cipher->name) {
+ /* examine each cipher we support, see if it meets our security
+ requirements, and see if the server supports it.
+ choose the best one of these */
+ if ((limit >= cipher->ssf) && (musthave <= cipher->ssf) &&
+ (ciphers & cipher->flag) &&
+ (!ctext->cipher || (cipher->ssf > ctext->cipher->ssf))) {
+ ctext->cipher = cipher;
+ }
+ cipher++;
+ }
+
+ if (ctext->cipher) {
+ /* we found a cipher we like */
+ ctext->protection = DIGEST_PRIVACY;
+ } else {
+ /* we didn't find any ciphers we like */
+ params->utils->seterror(params->utils->conn, 0,
+ "No good privacy layers");
+ }
+ }
+
+ if (ctext->cipher == NULL) {
+ /* we failed to find an encryption layer we liked;
+ can we use integrity or nothing? */
+
+ if ((limit >= 1) && (musthave <= 1)
+ && (protection & DIGEST_INTEGRITY)) {
+ /* integrity */
+ ctext->protection = DIGEST_INTEGRITY;
+ } else if (musthave <= 0) {
+ /* no layer */
+ ctext->protection = DIGEST_NOLAYER;
+
+ /* See if server supports not having a layer */
+ if ((protection & DIGEST_NOLAYER) != DIGEST_NOLAYER) {
+ params->utils->seterror(params->utils->conn, 0,
+ "Server doesn't support \"no layer\"");
+ result = SASL_FAIL;
+ goto FreeAllocatedMem;
+ }
+ } else {
+ params->utils->seterror(params->utils->conn, 0,
+ "Can't find an acceptable layer");
+ result = SASL_TOOWEAK;
+ goto FreeAllocatedMem;
+ }
+ }
+
+ *outrealms = realms;
+ *noutrealm = nrealm;
+
+ FreeAllocatedMem:
+ if (in_start) params->utils->free(in_start);
+
+ if (result != SASL_OK && realms) {
+ int lup;
+
+ /* need to free all the realms */
+ for (lup = 0;lup < nrealm; lup++)
+ params->utils->free(realms[lup]);
+
+ params->utils->free(realms);
+ }
+
+ return result;
+}
+
+static int ask_user_info(client_context_t *ctext,
+ sasl_client_params_t *params,
+ char **realms, int nrealm,
+ sasl_interact_t **prompt_need,
+ sasl_out_params_t *oparams)
+{
+ context_t *text = (context_t *) ctext;
+ int result = SASL_OK;
+ const char *authid = NULL, *userid = NULL, *realm = NULL;
+ char *realm_chal = NULL;
+ int user_result = SASL_OK;
+ int auth_result = SASL_OK;
+ int pass_result = SASL_OK;
+ int realm_result = SASL_FAIL;
+ int i;
+ size_t len;
+
+ params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
+ "DIGEST-MD5 ask_user_info()");
+
+ /* try to get the authid */
+ if (oparams->authid == NULL) {
+ auth_result = _plug_get_authid(params->utils, &authid, prompt_need);
+
+ if ((auth_result != SASL_OK) && (auth_result != SASL_INTERACT)) {
+ return auth_result;
+ }
+ }
+
+ /* try to get the userid */
+ if (oparams->user == NULL) {
+ user_result = _plug_get_userid(params->utils, &userid, prompt_need);
+
+ if ((user_result != SASL_OK) && (user_result != SASL_INTERACT)) {
+ return user_result;
+ }
+ }
+
+ /* try to get the password */
+ if (ctext->password == NULL) {
+ pass_result = _plug_get_password(params->utils, &ctext->password,
+ &ctext->free_password, prompt_need);
+ if ((pass_result != SASL_OK) && (pass_result != SASL_INTERACT)) {
+ return pass_result;
+ }
+ }
+
+ /* try to get the realm */
+ if (text->realm == NULL) {
+ if (realms) {
+ if(nrealm == 1) {
+ /* only one choice */
+ realm = realms[0];
+ realm_result = SASL_OK;
+ } else {
+ /* ask the user */
+ realm_result = _plug_get_realm(params->utils,
+ (const char **) realms,
+ (const char **) &realm,
+ prompt_need);
+ }
+ }
+
+ /* fake the realm if we must */
+ if ((realm_result != SASL_OK) && (realm_result != SASL_INTERACT)) {
+ if (params->serverFQDN) {
+ realm = params->serverFQDN;
+ } else {
+ return realm_result;
+ }
+ }
+ }
+
+ /* free prompts we got */
+ if (prompt_need && *prompt_need) {
+ params->utils->free(*prompt_need);
+ *prompt_need = NULL;
+ }
+
+ /* if there are prompts not filled in */
+ if ((user_result == SASL_INTERACT) || (auth_result == SASL_INTERACT) ||
+ (pass_result == SASL_INTERACT) || (realm_result == SASL_INTERACT)) {
+
+ /* make our default realm */
+ if (realm_result == SASL_INTERACT) {
+ if (realms) {
+ len = strlen(REALM_CHAL_PREFIX);
+ for (i = 0; i < nrealm; i++) {
+ len += strlen(realms[i]) + 4 /* " {}," */;
+ }
+ realm_chal = params->utils->malloc(len + 1);
+ strcpy (realm_chal, REALM_CHAL_PREFIX);
+ for (i = 0; i < nrealm; i++) {
+ strcat (realm_chal, " {");
+ strcat (realm_chal, realms[i]);
+ strcat (realm_chal, "},");
+ }
+ /* Replace the terminating comma with dot */
+ realm_chal[len-1] = '.';
+
+ } else if (params->serverFQDN) {
+ realm_chal = params->utils->malloc(3+strlen(params->serverFQDN));
+ if (realm_chal) {
+ sprintf(realm_chal, "{%s}", params->serverFQDN);
+ } else {
+ return SASL_NOMEM;
+ }
+ }
+ }
+
+ /* make the prompt list */
+ result =
+ _plug_make_prompts(params->utils, prompt_need,
+ user_result == SASL_INTERACT ?
+ "Please enter your authorization name" : NULL,
+ NULL,
+ auth_result == SASL_INTERACT ?
+ "Please enter your authentication name" : NULL,
+ NULL,
+ pass_result == SASL_INTERACT ?
+ "Please enter your password" : NULL, NULL,
+ NULL, NULL, NULL,
+ realm_chal ? realm_chal : "{}",
+ realm_result == SASL_INTERACT ?
+ "Please enter your realm" : NULL,
+ params->serverFQDN ? params->serverFQDN : NULL);
+
+ if (result == SASL_OK) return SASL_INTERACT;
+
+ return result;
+ }
+
+ if (oparams->authid == NULL) {
+ if (!userid || !*userid) {
+ result = params->canon_user(params->utils->conn, authid, 0,
+ SASL_CU_AUTHID | SASL_CU_AUTHZID,
+ oparams);
+ }
+ else {
+ result = params->canon_user(params->utils->conn,
+ authid, 0, SASL_CU_AUTHID, oparams);
+ if (result != SASL_OK) return result;
+
+ result = params->canon_user(params->utils->conn,
+ userid, 0, SASL_CU_AUTHZID, oparams);
+ }
+ if (result != SASL_OK) return result;
+ }
+
+ /* Get an allocated version of the realm into the structure */
+ if (realm && text->realm == NULL) {
+ _plug_strdup(params->utils, realm, (char **) &text->realm, NULL);
+ }
+
+ return result;
+}
+
+static int digestmd5_client_mech_new(void *glob_context,
+ sasl_client_params_t * params,
+ void **conn_context)
+{
+ context_t *text;
+
+ if ((params->flags & SASL_NEED_HTTP) && !params->http_request) {
+ SETERROR(params->utils,
+ "DIGEST-MD5 unavailable due to lack of HTTP request");
+ return SASL_BADPARAM;
+ }
+
+ /* holds state are in -- allocate client size */
+ text = params->utils->malloc(sizeof(client_context_t));
+ if (text == NULL)
+ return SASL_NOMEM;
+ memset((client_context_t *)text, 0, sizeof(client_context_t));
+
+ text->state = 1;
+ text->i_am = CLIENT;
+ text->http_mode = (params->flags & SASL_NEED_HTTP);
+ text->reauth = ((digest_glob_context_t *) glob_context)->reauth;
+
+ *conn_context = text;
+
+ return SASL_OK;
+}
+
+static int
+digestmd5_client_mech_step1(client_context_t *ctext,
+ sasl_client_params_t *params,
+ const char *serverin __attribute__((unused)),
+ unsigned serverinlen __attribute__((unused)),
+ sasl_interact_t **prompt_need,
+ const char **clientout,
+ unsigned *clientoutlen,
+ sasl_out_params_t *oparams)
+{
+ context_t *text = (context_t *) ctext;
+ int result = SASL_FAIL;
+ unsigned val;
+
+ params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
+ "DIGEST-MD5 client step 1");
+
+ result = ask_user_info(ctext, params, NULL, 0, prompt_need, oparams);
+ if (result != SASL_OK) return result;
+
+ /* check if we have cached info for this user on this server */
+ val = hash(params->serverFQDN) % text->reauth->size;
+ if (params->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
+ if (text->reauth->e[val].u.c.serverFQDN &&
+ !strcasecmp(text->reauth->e[val].u.c.serverFQDN,
+ params->serverFQDN) &&
+ !strcmp(text->reauth->e[val].authid, oparams->authid)) {
+
+ /* we have info, so use it */
+ if (text->realm) params->utils->free(text->realm);
+ _plug_strdup(params->utils, text->reauth->e[val].realm,
+ &text->realm, NULL);
+ _plug_strdup(params->utils, (char *) text->reauth->e[val].nonce,
+ (char **) &text->nonce, NULL);
+ text->nonce_count = ++text->reauth->e[val].nonce_count;
+ _plug_strdup(params->utils, (char *) text->reauth->e[val].cnonce,
+ (char **) &text->cnonce, NULL);
+ if (text->http_mode) {
+ /* per RFC 2617: algorithm & opaque MUST be sent back to server */
+ _plug_strdup(params->utils,
+ (char *) text->reauth->e[val].u.c.algorithm,
+ (char **) &ctext->algorithm, NULL);
+ if (text->reauth->e[val].u.c.opaque) {
+ _plug_strdup(params->utils,
+ (char *) text->reauth->e[val].u.c.opaque,
+ (char **) &ctext->opaque, NULL);
+ }
+ }
+ ctext->protection = text->reauth->e[val].u.c.protection;
+ ctext->cipher = text->reauth->e[val].u.c.cipher;
+ ctext->server_maxbuf = text->reauth->e[val].u.c.server_maxbuf;
+ }
+ params->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
+ }
+
+ if (!text->nonce) {
+ /* we don't have any reauth info, so just return
+ * that there is no initial client send */
+ text->state = 2;
+ return SASL_CONTINUE;
+ }
+
+ /*
+ * (username | realm | nonce | cnonce | nonce-count | qop digest-uri |
+ * response | maxbuf | charset | auth-param )
+ */
+
+ result = make_client_response(text, params, oparams);
+ if (result != SASL_OK) return result;
+
+ *clientoutlen = (unsigned) strlen(text->out_buf);
+ *clientout = text->out_buf;
+
+ /* check for next state (2 or 3) is done in digestmd5_client_mech_step() */
+ return SASL_CONTINUE;
+}
+
+static int digestmd5_client_mech_step2(client_context_t *ctext,
+ sasl_client_params_t *params,
+ const char *serverin,
+ unsigned serverinlen,
+ sasl_interact_t **prompt_need,
+ const char **clientout,
+ unsigned *clientoutlen,
+ sasl_out_params_t *oparams)
+{
+ context_t *text = (context_t *) ctext;
+ int result = SASL_FAIL;
+ char **realms = NULL;
+ int nrealm = 0;
+
+ params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
+ "DIGEST-MD5 client step 2");
+
+ if (params->props.min_ssf > params->props.max_ssf) {
+ return SASL_BADPARAM;
+ }
+
+ /* don't bother parsing the challenge more than once */
+ if (text->nonce == NULL) {
+ result = parse_server_challenge(ctext, params, serverin, serverinlen,
+ &realms, &nrealm);
+ if (result != SASL_OK) goto FreeAllocatedMem;
+
+ if (nrealm == 1) {
+ /* only one choice! */
+ if (text->realm) params->utils->free(text->realm);
+ text->realm = realms[0];
+
+ /* free realms */
+ params->utils->free(realms);
+ realms = NULL;
+ } else {
+ /* Save realms for later use */
+ text->realms = realms;
+ text->realm_cnt = nrealm;
+ }
+ } else {
+ /* Restore the list of realms */
+ realms = text->realms;
+ nrealm = text->realm_cnt;
+ }
+
+ result = ask_user_info(ctext, params, realms, nrealm,
+ prompt_need, oparams);
+ if (result != SASL_OK) goto FreeAllocatedMem;
+
+ /*
+ * (username | realm | nonce | cnonce | nonce-count | qop | digest-uri |
+ * response | maxbuf | charset | auth-param )
+ */
+
+ result = make_client_response(text, params, oparams);
+ if (result != SASL_OK) goto FreeAllocatedMem;
+
+ *clientoutlen = (unsigned) strlen(text->out_buf);
+ *clientout = text->out_buf;
+
+ text->state = 3;
+
+ result = SASL_CONTINUE;
+
+ FreeAllocatedMem:
+ return result;
+}
+
+static int
+digestmd5_client_mech_step3(client_context_t *ctext,
+ sasl_client_params_t *params,
+ const char *serverin,
+ unsigned serverinlen,
+ sasl_interact_t **prompt_need __attribute__((unused)),
+ const char **clientout __attribute__((unused)),
+ unsigned *clientoutlen __attribute__((unused)),
+ sasl_out_params_t *oparams)
+{
+ context_t *text = (context_t *) ctext;
+ char *in = NULL;
+ char *in_start;
+ int result = SASL_FAIL;
+
+ params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
+ "DIGEST-MD5 client step 3");
+
+ /* Verify that server is really what he claims to be */
+ in_start = in = params->utils->malloc(serverinlen + 1);
+ if (in == NULL) return SASL_NOMEM;
+
+ memcpy(in, serverin, serverinlen);
+ in[serverinlen] = 0;
+
+ /* parse the response */
+ while (in[0] != '\0') {
+ char *name, *value;
+ get_pair(&in, &name, &value);
+
+ if (name == NULL) {
+ params->utils->seterror(params->utils->conn, 0,
+ "DIGEST-MD5 Received Garbage");
+ result = SASL_BADAUTH;
+ break;
+ }
+
+ if (*name == '\0') {
+ break;
+ }
+
+ if (strcasecmp(name, "rspauth") == 0) {
+
+ if (strcmp(text->response_value, value) != 0) {
+ params->utils->seterror(params->utils->conn, 0,
+ "DIGEST-MD5: This server wants us to believe that he knows shared secret");
+ result = SASL_BADSERV;
+ } else {
+ oparams->doneflag = 1;
+ oparams->param_version = 0;
+
+ result = SASL_OK;
+ }
+ break;
+ } else {
+ params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
+ "DIGEST-MD5 unrecognized pair %s/%s: ignoring",
+ name, value);
+ }
+ }
+
+ params->utils->free(in_start);
+
+ if (params->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
+ unsigned val = hash(params->serverFQDN) % text->reauth->size;
+ switch (result) {
+ case SASL_OK:
+ if (text->nonce_count == 1) {
+ /* successful initial auth, setup for future reauth */
+ clear_reauth_entry(&text->reauth->e[val], CLIENT, params->utils);
+ _plug_strdup(params->utils, oparams->authid,
+ &text->reauth->e[val].authid, NULL);
+ text->reauth->e[val].realm = text->realm; text->realm = NULL;
+ text->reauth->e[val].nonce = text->nonce; text->nonce = NULL;
+ text->reauth->e[val].nonce_count = text->nonce_count;
+ text->reauth->e[val].cnonce = text->cnonce; text->cnonce = NULL;
+ _plug_strdup(params->utils, params->serverFQDN,
+ &text->reauth->e[val].u.c.serverFQDN, NULL);
+ if (text->http_mode) {
+ /* per RFC 2617: algorithm & opaque MUST be saved */
+ text->reauth->e[val].u.c.algorithm = ctext->algorithm;
+ ctext->algorithm = NULL;
+ text->reauth->e[val].u.c.opaque = ctext->opaque;
+ ctext->opaque = NULL;
+ }
+ text->reauth->e[val].u.c.protection = ctext->protection;
+ text->reauth->e[val].u.c.cipher = ctext->cipher;
+ text->reauth->e[val].u.c.server_maxbuf = ctext->server_maxbuf;
+ }
+ else {
+ /* reauth, we already incremented nonce_count */
+ }
+ break;
+ default:
+ if (text->nonce_count > 1) {
+ /* failed reauth, clear cache */
+ clear_reauth_entry(&text->reauth->e[val], CLIENT, params->utils);
+ }
+ else {
+ /* failed initial auth, leave existing cache */
+ }
+ }
+ params->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
+ }
+
+ return result;
+}
+
+static int digestmd5_client_mech_step(void *conn_context,
+ sasl_client_params_t *params,
+ const char *serverin,
+ unsigned serverinlen,
+ sasl_interact_t **prompt_need,
+ const char **clientout,
+ unsigned *clientoutlen,
+ sasl_out_params_t *oparams)
+{
+ context_t *text = (context_t *) conn_context;
+ client_context_t *ctext = (client_context_t *) conn_context;
+ unsigned val = hash(params->serverFQDN) % text->reauth->size;
+
+ if (serverinlen > 2048) return SASL_BADPROT;
+
+ *clientout = NULL;
+ *clientoutlen = 0;
+
+ switch (text->state) {
+
+ case 1:
+ if (!serverin) {
+ /* here's where we attempt fast reauth if possible */
+ int reauth = 0;
+
+ /* check if we have saved info for this server */
+ if (params->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
+ reauth = text->reauth->e[val].u.c.serverFQDN &&
+ !strcasecmp(text->reauth->e[val].u.c.serverFQDN,
+ params->serverFQDN);
+ params->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
+ }
+ if (reauth) {
+ return digestmd5_client_mech_step1(ctext, params,
+ serverin, serverinlen,
+ prompt_need,
+ clientout, clientoutlen,
+ oparams);
+ }
+ else {
+ /* we don't have any reauth info, so just return
+ * that there is no initial client send */
+ text->state = 2;
+ return SASL_CONTINUE;
+ }
+ }
+ else if (!strncasecmp(serverin, "rspauth=", 8)) {
+ /* server accepted fast reauth */
+ text->state = 3;
+ goto step3;
+ }
+
+ /* fall through and respond to challenge */
+ text->state = 2;
+
+ /* cleanup after a failed reauth attempt */
+ if (params->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
+ clear_reauth_entry(&text->reauth->e[val], CLIENT, params->utils);
+
+ params->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
+ }
+
+ if (text->realm) params->utils->free(text->realm);
+ if (text->nonce) params->utils->free(text->nonce);
+ if (text->cnonce) params->utils->free(text->cnonce);
+ text->realm = NULL;
+ text->nonce = text->cnonce = NULL;
+ ctext->cipher = NULL;
+
+ GCC_FALLTHROUGH
+
+ case 2:
+ return digestmd5_client_mech_step2(ctext, params,
+ serverin, serverinlen,
+ prompt_need,
+ clientout, clientoutlen,
+ oparams);
+
+ case 3:
+ step3:
+ return digestmd5_client_mech_step3(ctext, params,
+ serverin, serverinlen,
+ prompt_need,
+ clientout, clientoutlen,
+ oparams);
+
+ default:
+ params->utils->log(NULL, SASL_LOG_ERR,
+ "Invalid DIGEST-MD5 client step %d\n", text->state);
+ return SASL_FAIL;
+ }
+
+ return SASL_FAIL; /* should never get here */
+}
+
+static void digestmd5_client_mech_dispose(void *conn_context,
+ const sasl_utils_t *utils)
+{
+ client_context_t *ctext = (client_context_t *) conn_context;
+
+ if (!ctext || !utils) return;
+
+ utils->log(utils->conn, SASL_LOG_DEBUG,
+ "DIGEST-MD5 client mech dispose");
+
+ if (ctext->free_password) _plug_free_secret(utils, &ctext->password);
+ if (ctext->algorithm) utils->free(ctext->algorithm);
+ if (ctext->opaque) utils->free(ctext->opaque);
+
+ digestmd5_common_mech_dispose(conn_context, utils);
+}
+
+static sasl_client_plug_t digestmd5_client_plugins[] =
+{
+ {
+ "DIGEST-MD5",
+#ifdef WITH_RC4 /* mech_name */
+ 128, /* max ssf */
+#elif defined(WITH_DES)
+ 112,
+#else
+ 1,
+#endif
+ SASL_SEC_NOPLAINTEXT
+ | SASL_SEC_NOANONYMOUS
+ | SASL_SEC_MUTUAL_AUTH, /* security_flags */
+ SASL_FEAT_NEEDSERVERFQDN
+ | SASL_FEAT_ALLOWS_PROXY
+ | SASL_FEAT_SUPPORTS_HTTP, /* features */
+ NULL, /* required_prompts */
+ &client_glob_context, /* glob_context */
+ &digestmd5_client_mech_new, /* mech_new */
+ &digestmd5_client_mech_step, /* mech_step */
+ &digestmd5_client_mech_dispose, /* mech_dispose */
+ &digestmd5_common_mech_free, /* mech_free */
+ NULL, /* idle */
+ NULL, /* spare1 */
+ NULL /* spare2 */
+ }
+};
+
+int digestmd5_client_plug_init(sasl_utils_t *utils,
+ int maxversion,
+ int *out_version,
+ sasl_client_plug_t **pluglist,
+ int *plugcount)
+{
+ reauth_cache_t *reauth_cache;
+
+ if (maxversion < SASL_CLIENT_PLUG_VERSION)
+ return SASL_BADVERS;
+
+ /* reauth cache */
+ reauth_cache = utils->malloc(sizeof(reauth_cache_t));
+ if (reauth_cache == NULL)
+ return SASL_NOMEM;
+ memset(reauth_cache, 0, sizeof(reauth_cache_t));
+ reauth_cache->i_am = CLIENT;
+
+ /* mutex */
+ reauth_cache->mutex = utils->mutex_alloc();
+ if (!reauth_cache->mutex)
+ return SASL_FAIL;
+
+ /* entries */
+ reauth_cache->size = 10;
+ reauth_cache->e = utils->malloc(reauth_cache->size *
+ sizeof(reauth_entry_t));
+ if (reauth_cache->e == NULL)
+ return SASL_NOMEM;
+ memset(reauth_cache->e, 0, reauth_cache->size * sizeof(reauth_entry_t));
+
+ ((digest_glob_context_t *) digestmd5_client_plugins[0].glob_context)->reauth = reauth_cache;
+
+ *out_version = SASL_CLIENT_PLUG_VERSION;
+ *pluglist = digestmd5_client_plugins;
+ *plugcount = 1;
+
+ return SASL_OK;
+}
diff --git a/contrib/libs/sasl/plugins/otp.c b/contrib/libs/sasl/plugins/otp.c
new file mode 100644
index 0000000000..28d1f51fc2
--- /dev/null
+++ b/contrib/libs/sasl/plugins/otp.c
@@ -0,0 +1,1895 @@
+/* OTP SASL plugin
+ * Ken Murchison
+ */
+/*
+ * Copyright (c) 1998-2016 Carnegie Mellon University. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For permission or any other legal
+ * details, please contact
+ * Carnegie Mellon University
+ * Center for Technology Transfer and Enterprise Creation
+ * 4615 Forbes Avenue
+ * Suite 302
+ * Pittsburgh, PA 15213
+ * (412) 268-7393, fax: (412) 268-7395
+ * innovation@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Computing Services
+ * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include <openssl/evp.h>
+#include <openssl/md5.h> /* XXX hack for OpenBSD/OpenSSL cruftiness */
+
+#include <sasl.h>
+#define MD5_H /* suppress internal MD5 */
+#include <saslplug.h>
+
+#include "plugin_common.h"
+
+#ifdef macintosh
+#error #include <sasl_otp_plugin_decl.h>
+#endif
+
+/***************************** Common Section *****************************/
+
+#define OTP_SEQUENCE_MAX 9999
+#define OTP_SEQUENCE_DEFAULT 499
+#define OTP_SEQUENCE_REINIT 490
+#define OTP_SEED_MIN 1
+#define OTP_SEED_MAX 16
+#define OTP_HASH_SIZE 8 /* 64 bits */
+#define OTP_CHALLENGE_MAX 100
+#define OTP_RESPONSE_MAX 100
+#define OTP_HEX_TYPE "hex:"
+#define OTP_WORD_TYPE "word:"
+#define OTP_INIT_HEX_TYPE "init-hex:"
+#define OTP_INIT_WORD_TYPE "init-word:"
+
+typedef struct algorithm_option_s {
+ const char *name; /* name used in challenge/response */
+ int swab; /* number of bytes to swab (0, 1, 2, 4, 8) */
+ const char *evp_name; /* name used for lookup in EVP table */
+} algorithm_option_t;
+
+static algorithm_option_t algorithm_options[] = {
+ {"md4", 0, "md4"},
+ {"md5", 0, "md5"},
+ {"sha1", 4, "sha1"},
+ {NULL, 0, NULL}
+};
+
+static EVP_MD_CTX *_plug_EVP_MD_CTX_new(const sasl_utils_t *utils)
+{
+ utils->log(NULL, SASL_LOG_DEBUG, "_plug_EVP_MD_CTX_new()");
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ return EVP_MD_CTX_new();
+#else
+ return utils->malloc(sizeof(EVP_MD_CTX));
+#endif
+}
+
+static void _plug_EVP_MD_CTX_free(EVP_MD_CTX *ctx, const sasl_utils_t *utils)
+{
+ utils->log(NULL, SASL_LOG_DEBUG, "_plug_EVP_MD_CTX_free()");
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ EVP_MD_CTX_free(ctx);
+#else
+ utils->free(ctx);
+#endif
+}
+
+/* Convert the binary data into ASCII hex */
+void bin2hex(unsigned char *bin, int binlen, char *hex)
+{
+ int i;
+ unsigned char c;
+
+ for (i = 0; i < binlen; i++) {
+ c = (bin[i] >> 4) & 0xf;
+ hex[i*2] = (c > 9) ? ('a' + c - 10) : ('0' + c);
+ c = bin[i] & 0xf;
+ hex[i*2+1] = (c > 9) ? ('a' + c - 10) : ('0' + c);
+ }
+ hex[i*2] = '\0';
+}
+
+/*
+ * Hash the data using the given algorithm and fold it into 64 bits,
+ * swabbing bytes if necessary.
+ */
+static void otp_hash(const EVP_MD *md, char *in, size_t inlen,
+ unsigned char *out, int swab, EVP_MD_CTX *mdctx)
+{
+ unsigned char hash[EVP_MAX_MD_SIZE];
+ unsigned int i;
+ int j;
+ unsigned hashlen;
+
+ EVP_DigestInit(mdctx, md);
+ EVP_DigestUpdate(mdctx, in, inlen);
+ EVP_DigestFinal(mdctx, hash, &hashlen);
+
+ /* Fold the result into 64 bits */
+ for (i = OTP_HASH_SIZE; i < hashlen; i++) {
+ hash[i % OTP_HASH_SIZE] ^= hash[i];
+ }
+
+ /* Swab bytes */
+ if (swab) {
+ for (i = 0; i < OTP_HASH_SIZE;) {
+ for (j = swab-1; j > -swab; i++, j-=2)
+ out[i] = hash[i+j];
+ }
+ }
+ else
+ memcpy(out, hash, OTP_HASH_SIZE);
+}
+
+static int generate_otp(const sasl_utils_t *utils,
+ algorithm_option_t *alg, unsigned seq, char *seed,
+ unsigned char *secret, unsigned secret_len,
+ unsigned char *otp)
+{
+ const EVP_MD *md;
+ EVP_MD_CTX *mdctx = NULL;
+ char *key = NULL;
+ int r = SASL_OK;
+
+ if (!(md = EVP_get_digestbyname(alg->evp_name))) {
+ utils->seterror(utils->conn, 0,
+ "OTP algorithm %s is not available", alg->evp_name);
+ return SASL_FAIL;
+ }
+
+ if ((mdctx = _plug_EVP_MD_CTX_new(utils)) == NULL) {
+ SETERROR(utils, "cannot allocate MD CTX");
+ r = SASL_NOMEM;
+ goto done;
+ }
+
+ if ((key = utils->malloc(strlen(seed) + secret_len + 1)) == NULL) {
+ SETERROR(utils, "cannot allocate OTP key");
+ r = SASL_NOMEM;
+ goto done;
+ }
+
+ /* initial step */
+ sprintf(key, "%s%.*s", seed, secret_len, secret);
+ otp_hash(md, key, strlen(key), otp, alg->swab, mdctx);
+
+ /* computation step */
+ while (seq-- > 0)
+ otp_hash(md, (char *) otp, OTP_HASH_SIZE, otp, alg->swab, mdctx);
+
+done:
+ if (key) utils->free(key);
+ if (mdctx) _plug_EVP_MD_CTX_free(mdctx, utils);
+
+ return r;
+}
+
+static int parse_challenge(const sasl_utils_t *utils,
+ char *chal, algorithm_option_t **alg,
+ unsigned *seq, char *seed, int is_init)
+{
+ char *c;
+ algorithm_option_t *opt;
+ int n;
+
+ c = chal;
+
+ /* eat leading whitespace */
+ while (*c && isspace((int) *c)) c++;
+
+ if (!is_init) {
+ /* check the prefix */
+ if (!*c || strncmp(c, "otp-", 4)) {
+ SETERROR(utils, "not an OTP challenge");
+ return SASL_BADPROT;
+ }
+
+ /* skip the prefix */
+ c += 4;
+ }
+
+ /* find the algorithm */
+ opt = algorithm_options;
+ while (opt->name) {
+ if (!strncmp(c, opt->name, strlen(opt->name))) {
+ break;
+ }
+ opt++;
+ }
+
+ /* didn't find the algorithm in our list */
+ if (!opt->name) {
+ utils->seterror(utils->conn, 0, "OTP algorithm '%s' not supported", c);
+ return SASL_BADPROT;
+ }
+
+ /* skip algorithm name */
+ c += strlen(opt->name);
+ *alg = opt;
+
+ /* eat whitespace */
+ if (!isspace((int) *c)) {
+ SETERROR(utils, "no whitespace between OTP algorithm and sequence");
+ return SASL_BADPROT;
+ }
+ while (*c && isspace((int) *c)) c++;
+
+ /* grab the sequence */
+ if ((*seq = strtoul(c, &c, 10)) > OTP_SEQUENCE_MAX) {
+ utils->seterror(utils->conn, 0, "sequence > %u", OTP_SEQUENCE_MAX);
+ return SASL_BADPROT;
+ }
+
+ /* eat whitespace */
+ if (!isspace((int) *c)) {
+ SETERROR(utils, "no whitespace between OTP sequence and seed");
+ return SASL_BADPROT;
+ }
+ while (*c && isspace((int) *c)) c++;
+
+ /* grab the seed, converting to lowercase as we go */
+ n = 0;
+ while (*c && isalnum((int) *c) && (n < OTP_SEED_MAX))
+ seed[n++] = tolower((int) *c++);
+ if (n > OTP_SEED_MAX) {
+ utils->seterror(utils->conn, 0, "OTP seed length > %u", OTP_SEED_MAX);
+ return SASL_BADPROT;
+ }
+ else if (n < OTP_SEED_MIN) {
+ utils->seterror(utils->conn, 0, "OTP seed length < %u", OTP_SEED_MIN);
+ return SASL_BADPROT;
+ }
+ seed[n] = '\0';
+
+ if (!is_init) {
+ /* eat whitespace */
+ if (!isspace((int) *c)) {
+ SETERROR(utils, "no whitespace between OTP seed and extensions");
+ return SASL_BADPROT;
+ }
+ while (*c && isspace((int) *c)) c++;
+
+ /* make sure this is an extended challenge */
+ if (strncmp(c, "ext", 3) ||
+ (*(c+=3) &&
+ !(isspace((int) *c) || (*c == ',') ||
+ (*c == '\r') || (*c == '\n')))) {
+ SETERROR(utils, "not an OTP extended challenge");
+ return SASL_BADPROT;
+ }
+ }
+
+ return SASL_OK;
+}
+
+static void
+otp_common_mech_free(void *global_context __attribute__((unused)),
+ const sasl_utils_t *utils __attribute__((unused)))
+{
+ /* Don't call EVP_cleanup(); here, as this might confuse the calling
+ application if it also uses OpenSSL */
+}
+
+/***************************** Server Section *****************************/
+
+#ifdef HAVE_OPIE
+#include <opie.h>
+#endif
+
+typedef struct server_context {
+ int state;
+
+ char *authid;
+ int locked; /* is the user's secret locked? */
+ algorithm_option_t *alg;
+#ifdef HAVE_OPIE
+ struct opie opie;
+#else
+ char *realm;
+ unsigned seq;
+ char seed[OTP_SEED_MAX+1];
+ unsigned char otp[OTP_HASH_SIZE];
+ time_t timestamp; /* time we locked the secret */
+#endif /* HAVE_OPIE */
+
+ char *out_buf;
+ unsigned out_buf_len;
+} server_context_t;
+
+static int otp_server_mech_new(void *glob_context __attribute__((unused)),
+ sasl_server_params_t *sparams,
+ const char *challenge __attribute__((unused)),
+ unsigned challen __attribute__((unused)),
+ void **conn_context)
+{
+ server_context_t *text;
+
+ /* holds state are in */
+ text = sparams->utils->malloc(sizeof(server_context_t));
+ if (text == NULL) {
+ MEMERROR(sparams->utils);
+ return SASL_NOMEM;
+ }
+
+ memset(text, 0, sizeof(server_context_t));
+
+ text->state = 1;
+
+ *conn_context = text;
+
+ return SASL_OK;
+}
+
+#ifdef HAVE_OPIE
+
+#ifndef OPIE_KEYFILE
+#define OPIE_KEYFILE "/etc/opiekeys"
+#endif
+
+static int opie_server_mech_step(void *conn_context,
+ sasl_server_params_t *params,
+ const char *clientin,
+ unsigned clientinlen,
+ const char **serverout,
+ unsigned *serveroutlen,
+ sasl_out_params_t *oparams)
+{
+ server_context_t *text = (server_context_t *) conn_context;
+
+ *serverout = NULL;
+ *serveroutlen = 0;
+
+ if (text == NULL) {
+ return SASL_BADPROT;
+ }
+
+ switch (text->state) {
+
+ case 1: {
+ const char *authzid;
+ const char *authid;
+ size_t authid_len;
+ unsigned lup = 0;
+ int result;
+
+ /* should have received authzid NUL authid */
+
+ /* get authzid */
+ authzid = clientin;
+ while ((lup < clientinlen) && (clientin[lup] != 0)) ++lup;
+
+ if (lup >= clientinlen) {
+ SETERROR(params->utils, "Can only find OTP authzid (no authid)");
+ return SASL_BADPROT;
+ }
+
+ /* get authid */
+ ++lup;
+ authid = clientin + lup;
+ while ((lup < clientinlen) && (clientin[lup] != 0)) ++lup;
+
+ authid_len = clientin + lup - authid;
+
+ if (lup != clientinlen) {
+ SETERROR(params->utils,
+ "Got more data than we were expecting in the OTP plugin\n");
+ return SASL_BADPROT;
+ }
+
+ text->authid = params->utils->malloc(authid_len + 1);
+ if (text->authid == NULL) {
+ MEMERROR(params->utils);
+ return SASL_NOMEM;
+ }
+
+ /* we can't assume that authen is null-terminated */
+ strncpy(text->authid, authid, authid_len);
+ text->authid[authid_len] = '\0';
+
+ result = params->canon_user(params->utils->conn, text->authid, 0,
+ SASL_CU_AUTHID, oparams);
+ if (result != SASL_OK) return result;
+
+ result = params->canon_user(params->utils->conn,
+ strlen(authzid) ? authzid : text->authid,
+ 0, SASL_CU_AUTHZID, oparams);
+ if (result != SASL_OK) return result;
+
+ result = _plug_buf_alloc(params->utils, &(text->out_buf),
+ &(text->out_buf_len), OTP_CHALLENGE_MAX+1);
+ if (result != SASL_OK) return result;
+
+ /* create challenge - return sasl_continue on success */
+ result = opiechallenge(&text->opie, text->authid, text->out_buf);
+
+ switch (result) {
+ case 0:
+ text->locked = 1;
+
+ *serverout = text->out_buf;
+ *serveroutlen = strlen(text->out_buf);
+
+ text->state = 2;
+ return SASL_CONTINUE;
+
+ case 1:
+ SETERROR(params->utils, "opiechallenge: user not found or locked");
+ return SASL_NOUSER;
+
+ default:
+ SETERROR(params->utils,
+ "opiechallenge: system error (file, memory, I/O)");
+ return SASL_FAIL;
+ }
+ }
+
+ case 2: {
+ char response[OPIE_RESPONSE_MAX+1];
+ int result;
+
+ /* should have received extended response,
+ but we'll take anything that we can verify */
+
+ if (clientinlen > OPIE_RESPONSE_MAX) {
+ SETERROR(params->utils, "response too long");
+ return SASL_BADPROT;
+ }
+
+ /* we can't assume that the response is null-terminated */
+ strncpy(response, clientin, clientinlen);
+ response[clientinlen] = '\0';
+
+ /* verify response */
+ result = opieverify(&text->opie, response);
+ text->locked = 0;
+
+ switch (result) {
+ case 0:
+ /* set oparams */
+ oparams->doneflag = 1;
+ oparams->mech_ssf = 0;
+ oparams->maxoutbuf = 0;
+ oparams->encode_context = NULL;
+ oparams->encode = NULL;
+ oparams->decode_context = NULL;
+ oparams->decode = NULL;
+ oparams->param_version = 0;
+
+ return SASL_OK;
+
+ case 1:
+ SETERROR(params->utils, "opieverify: invalid/incorrect response");
+ return SASL_BADAUTH;
+
+ default:
+ SETERROR(params->utils,
+ "opieverify: system error (file, memory, I/O)");
+ return SASL_FAIL;
+ }
+ }
+
+ default:
+ params->utils->log(NULL, SASL_LOG_ERR,
+ "Invalid OTP server step %d\n", text->state);
+ return SASL_FAIL;
+ }
+
+ return SASL_FAIL; /* should never get here */
+}
+
+static void opie_server_mech_dispose(void *conn_context,
+ const sasl_utils_t *utils)
+{
+ server_context_t *text = (server_context_t *) conn_context;
+
+ if (!text) return;
+
+ /* if we created a challenge, but bailed before the verification of the
+ response, do a verify here to release the lock on the user key */
+ if (text->locked) opieverify(&text->opie, "");
+
+ if (text->authid) _plug_free_string(utils, &(text->authid));
+
+ if (text->out_buf) utils->free(text->out_buf);
+
+ utils->free(text);
+}
+
+static int opie_mech_avail(void *glob_context __attribute__((unused)),
+ sasl_server_params_t *sparams,
+ void **conn_context __attribute__((unused)))
+{
+ const char *fname;
+ unsigned int len;
+
+ sparams->utils->getopt(sparams->utils->getopt_context,
+ "OTP", "opiekeys", &fname, &len);
+
+ if (!fname) fname = OPIE_KEYFILE;
+
+ if (access(fname, R_OK|W_OK) != 0) {
+ sparams->utils->log(NULL, SASL_LOG_ERR,
+ "OTP unavailable because "
+ "can't read/write key database %s: %m",
+ fname, errno);
+ return SASL_NOMECH;
+ }
+
+ return SASL_OK;
+}
+
+static sasl_server_plug_t otp_server_plugins[] =
+{
+ {
+ "OTP",
+ 0,
+ SASL_SEC_NOPLAINTEXT
+ | SASL_SEC_NOANONYMOUS
+ | SASL_SEC_FORWARD_SECRECY,
+ SASL_FEAT_WANT_CLIENT_FIRST
+ | SASL_FEAT_DONTUSE_USERPASSWD
+ | SASL_FEAT_ALLOWS_PROXY,
+ NULL,
+ &otp_server_mech_new,
+ &opie_server_mech_step,
+ &opie_server_mech_dispose,
+ &otp_common_mech_free,
+ NULL,
+ NULL,
+ NULL,
+ &opie_mech_avail,
+ NULL
+ }
+};
+#else /* HAVE_OPIE */
+
+#include "otp.h"
+
+#define OTP_MDA_DEFAULT "md5"
+#define OTP_LOCK_TIMEOUT 5 * 60 /* 5 minutes */
+
+/* Convert the ASCII hex into binary data */
+int hex2bin(char *hex, unsigned char *bin, int binlen)
+{
+ int i;
+ char *c;
+ unsigned char msn, lsn;
+
+ memset(bin, 0, binlen);
+
+ for (c = hex, i = 0; i < binlen; c++) {
+ /* whitespace */
+ if (isspace((int) *c))
+ continue;
+ /* end of string, or non-hex char */
+ if (!*c || !*(c+1) || !isxdigit((int) *c))
+ break;
+
+ msn = (*c > '9') ? tolower((int) *c) - 'a' + 10 : *c - '0';
+ c++;
+ lsn = (*c > '9') ? tolower((int) *c) - 'a' + 10 : *c - '0';
+
+ bin[i++] = (unsigned char) (msn << 4) | lsn;
+ }
+
+ return (i < binlen) ? SASL_BADAUTH : SASL_OK;
+}
+
+static int make_secret(const sasl_utils_t *utils, const char *alg,
+ unsigned seq, char *seed, unsigned char *otp,
+ time_t timeout, sasl_secret_t **secret)
+{
+ size_t sec_len;
+ char *data;
+ char buf[2*OTP_HASH_SIZE+1];
+
+ /*
+ * secret is stored as:
+ *
+ * <alg> \t <seq> \t <seed> \t <otp> \t <timeout> \0
+ *
+ * <timeout> is used as a "lock" when an auth is in progress
+ * we just set it to zero here (no lock)
+ */
+ sec_len = strlen(alg)+1+4+1+strlen(seed)+1+2*OTP_HASH_SIZE+1+20+1;
+ *secret = utils->malloc(sizeof(sasl_secret_t)+sec_len);
+ if (!*secret) {
+ return SASL_NOMEM;
+ }
+
+ (*secret)->len = (unsigned) sec_len;
+ data = (char *) (*secret)->data;
+
+ bin2hex(otp, OTP_HASH_SIZE, buf);
+ buf[2*OTP_HASH_SIZE] = '\0';
+
+ sprintf(data, "%s\t%04d\t%s\t%s\t%020ld",
+ alg, seq, seed, buf, timeout);
+
+ return SASL_OK;
+}
+
+static int parse_secret(const sasl_utils_t *utils,
+ char *secret, size_t seclen,
+ char *alg, unsigned *seq, char *seed,
+ unsigned char *otp,
+ time_t *timeout)
+{
+ if (strlen(secret) < seclen) {
+ char *c;
+
+ /*
+ * old-style (binary) secret is stored as:
+ *
+ * <alg> \0 <seq> \0 <seed> \0 <otp> <timeout>
+ *
+ */
+
+ if (seclen < (3+1+1+1+OTP_SEED_MIN+1+OTP_HASH_SIZE+sizeof(time_t))) {
+ SETERROR(utils, "OTP secret too short");
+ return SASL_FAIL;
+ }
+
+ c = secret;
+
+ strcpy(alg, (char*) c);
+ c += strlen(alg)+1;
+
+ *seq = strtoul(c, NULL, 10);
+ c += 5;
+
+ strcpy(seed, (char*) c);
+ c += strlen(seed)+1;
+
+ memcpy(otp, c, OTP_HASH_SIZE);
+ c += OTP_HASH_SIZE;
+
+ memcpy(timeout, c, sizeof(time_t));
+
+ return SASL_OK;
+ }
+
+ else {
+ char buf[2*OTP_HASH_SIZE+1];
+
+ /*
+ * new-style (ASCII) secret is stored as:
+ *
+ * <alg> \t <seq> \t <seed> \t <otp> \t <timeout> \0
+ *
+ */
+
+ if (seclen < (3+1+1+1+OTP_SEED_MIN+1+2*OTP_HASH_SIZE+1+20)) {
+ SETERROR(utils, "OTP secret too short");
+ return SASL_FAIL;
+ }
+
+ sscanf(secret, "%s\t%04d\t%s\t%s\t%020ld",
+ alg, seq, seed, buf, timeout);
+
+ hex2bin(buf, otp, OTP_HASH_SIZE);
+
+ return SASL_OK;
+ }
+}
+
+/* Compare two string pointers */
+static int strptrcasecmp(const void *arg1, const void *arg2)
+{
+ return (strcasecmp(*((char**) arg1), *((char**) arg2)));
+}
+
+/* Convert the 6 words into binary data */
+static int word2bin(const sasl_utils_t *utils,
+ char *words, unsigned char *bin, const EVP_MD *md,
+ EVP_MD_CTX *mdctx)
+{
+ int i, j;
+ char *c, *word, buf[OTP_RESPONSE_MAX+1];
+ void *base;
+ int nmemb;
+ unsigned long x = 0;
+ unsigned char bits[OTP_HASH_SIZE+1]; /* 1 for checksum */
+ unsigned char chksum;
+ int bit, fbyte, lbyte;
+ const char **str_ptr;
+ int alt_dict = 0;
+
+ /* this is a destructive operation, so make a work copy */
+ strcpy(buf, words);
+ memset(bits, 0, 9);
+
+ for (c = buf, bit = 0, i = 0; i < 6; i++, c++, bit+=11) {
+ while (*c && isspace((int) *c)) c++;
+ word = c;
+ while (*c && isalpha((int) *c)) c++;
+ if (!*c && i < 5) break;
+ *c = '\0';
+ if (strlen(word) < 1 || strlen(word) > 4) {
+ utils->log(NULL, SASL_LOG_DEBUG,
+ "incorrect word length '%s'", word);
+ return SASL_BADAUTH;
+ }
+
+ /* standard dictionary */
+ if (!alt_dict) {
+ if (strlen(word) < 4) {
+ base = otp_std_dict;
+ nmemb = OTP_4LETTER_OFFSET;
+ }
+ else {
+ base = otp_std_dict + OTP_4LETTER_OFFSET;
+ nmemb = OTP_STD_DICT_SIZE - OTP_4LETTER_OFFSET;
+ }
+
+ str_ptr = (const char**) bsearch((void*) &word, base, nmemb,
+ sizeof(const char*),
+ strptrcasecmp);
+ if (str_ptr) {
+ x = (unsigned long) (str_ptr - otp_std_dict);
+ }
+ else if (i == 0) {
+ /* couldn't find first word, try alternate dictionary */
+ alt_dict = 1;
+ }
+ else {
+ utils->log(NULL, SASL_LOG_DEBUG,
+ "word '%s' not found in dictionary", word);
+ return SASL_BADAUTH;
+ }
+ }
+
+ /* alternate dictionary */
+ if (alt_dict) {
+ unsigned char hash[EVP_MAX_MD_SIZE];
+ unsigned hashlen;
+
+ EVP_DigestInit(mdctx, md);
+ EVP_DigestUpdate(mdctx, word, strlen(word));
+ EVP_DigestFinal(mdctx, hash, &hashlen);
+
+ /* use lowest 11 bits */
+ x = ((hash[hashlen-2] & 0x7) << 8) | hash[hashlen-1];
+ }
+
+ /* left align 11 bits on byte boundary */
+ x <<= (8 - ((bit+11) % 8));
+ /* first output byte containing some of our 11 bits */
+ fbyte = bit / 8;
+ /* last output byte containing some of our 11 bits */
+ lbyte = (bit+11) / 8;
+ /* populate the output bytes with the 11 bits */
+ for (j = lbyte; j >= fbyte; j--, x >>= 8)
+ bits[j] |= (unsigned char) (x & 0xff);
+ }
+
+ if (i < 6) {
+ utils->log(NULL, SASL_LOG_DEBUG, "not enough words (%d)", i);
+ return SASL_BADAUTH;
+ }
+
+ /* see if the 2-bit checksum is correct */
+ for (chksum = 0, i = 0; i < 8; i++) {
+ for (j = 0; j < 4; j++) {
+ chksum += ((bits[i] >> (2 * j)) & 0x3);
+ }
+ }
+ chksum <<= 6;
+
+ if (chksum != bits[8]) {
+ utils->log(NULL, SASL_LOG_DEBUG, "incorrect parity");
+ return SASL_BADAUTH;
+ }
+
+ memcpy(bin, bits, OTP_HASH_SIZE);
+
+ return SASL_OK;
+}
+
+static int verify_response(server_context_t *text, const sasl_utils_t *utils,
+ char *response)
+{
+ const EVP_MD *md;
+ EVP_MD_CTX *mdctx = NULL;
+ char *c;
+ int do_init = 0;
+ unsigned char cur_otp[OTP_HASH_SIZE], prev_otp[OTP_HASH_SIZE];
+ int r;
+
+ /* find the MDA */
+ if (!(md = EVP_get_digestbyname(text->alg->evp_name))) {
+ utils->seterror(utils->conn, 0,
+ "OTP algorithm %s is not available",
+ text->alg->evp_name);
+ return SASL_FAIL;
+ }
+
+ if ((mdctx = _plug_EVP_MD_CTX_new(utils)) == NULL) {
+ SETERROR(utils, "cannot allocate MD CTX");
+ return SASL_NOMEM;
+ }
+
+ /* eat leading whitespace */
+ c = response;
+ while (isspace((int) *c)) c++;
+
+ if (strchr(c, ':')) {
+ if (!strncasecmp(c, OTP_HEX_TYPE, strlen(OTP_HEX_TYPE))) {
+ r = hex2bin(c+strlen(OTP_HEX_TYPE), cur_otp, OTP_HASH_SIZE);
+ }
+ else if (!strncasecmp(c, OTP_WORD_TYPE, strlen(OTP_WORD_TYPE))) {
+ r = word2bin(utils, c+strlen(OTP_WORD_TYPE), cur_otp, md, mdctx);
+ }
+ else if (!strncasecmp(c, OTP_INIT_HEX_TYPE,
+ strlen(OTP_INIT_HEX_TYPE))) {
+ do_init = 1;
+ r = hex2bin(c+strlen(OTP_INIT_HEX_TYPE), cur_otp, OTP_HASH_SIZE);
+ }
+ else if (!strncasecmp(c, OTP_INIT_WORD_TYPE,
+ strlen(OTP_INIT_WORD_TYPE))) {
+ do_init = 1;
+ r = word2bin(utils, c+strlen(OTP_INIT_WORD_TYPE), cur_otp, md, mdctx);
+ }
+ else {
+ SETERROR(utils, "unknown OTP extended response type");
+ r = SASL_BADAUTH;
+ }
+ }
+ else {
+ /* standard response, try word first, and then hex */
+ r = word2bin(utils, c, cur_otp, md, mdctx);
+ if (r != SASL_OK)
+ r = hex2bin(c, cur_otp, OTP_HASH_SIZE);
+ }
+
+ if (r == SASL_OK) {
+ /* do one more hash (previous otp) and compare to stored otp */
+ otp_hash(md, (char *) cur_otp, OTP_HASH_SIZE,
+ prev_otp, text->alg->swab, mdctx);
+
+ if (!memcmp(prev_otp, text->otp, OTP_HASH_SIZE)) {
+ /* update the secret with this seq/otp */
+ memcpy(text->otp, cur_otp, OTP_HASH_SIZE);
+ text->seq--;
+ r = SASL_OK;
+ }
+ else
+ r = SASL_BADAUTH;
+ }
+
+ /* if this is an init- attempt, let's check it out */
+ if (r == SASL_OK && do_init) {
+ char *new_chal = NULL, *new_resp = NULL;
+ algorithm_option_t *alg;
+ unsigned seq;
+ char seed[OTP_SEED_MAX+1];
+ unsigned char new_otp[OTP_HASH_SIZE];
+
+ /* find the challenge and response fields */
+ new_chal = strchr(c+strlen(OTP_INIT_WORD_TYPE), ':');
+ if (new_chal) {
+ *new_chal++ = '\0';
+ new_resp = strchr(new_chal, ':');
+ if (new_resp)
+ *new_resp++ = '\0';
+ }
+
+ if (!(new_chal && new_resp)) {
+ r = SASL_BADAUTH;
+ goto done;
+ }
+
+ if ((r = parse_challenge(utils, new_chal, &alg, &seq, seed, 1))
+ != SASL_OK) {
+ goto done;
+ }
+
+ if (seq < 1 || !strcasecmp(seed, text->seed)) {
+ r = SASL_BADAUTH;
+ goto done;
+ }
+
+ /* find the MDA */
+ if (!(md = EVP_get_digestbyname(alg->evp_name))) {
+ utils->seterror(utils->conn, 0,
+ "OTP algorithm %s is not available",
+ alg->evp_name);
+ r = SASL_BADAUTH;
+ goto done;
+ }
+
+ if (!strncasecmp(c, OTP_INIT_HEX_TYPE, strlen(OTP_INIT_HEX_TYPE))) {
+ r = hex2bin(new_resp, new_otp, OTP_HASH_SIZE);
+ }
+ else if (!strncasecmp(c, OTP_INIT_WORD_TYPE,
+ strlen(OTP_INIT_WORD_TYPE))) {
+ r = word2bin(utils, new_resp, new_otp, md, mdctx);
+ }
+
+ if (r == SASL_OK) {
+ /* setup for new secret */
+ text->alg = alg;
+ text->seq = seq;
+ strcpy(text->seed, seed);
+ memcpy(text->otp, new_otp, OTP_HASH_SIZE);
+ }
+ }
+
+ done:
+ if (mdctx) _plug_EVP_MD_CTX_free(mdctx, utils);
+
+ return r;
+}
+
+static int otp_server_mech_step1(server_context_t *text,
+ sasl_server_params_t *params,
+ const char *clientin,
+ unsigned clientinlen,
+ const char **serverout,
+ unsigned *serveroutlen,
+ sasl_out_params_t *oparams)
+{
+ const char *authzid;
+ const char *authidp;
+ size_t authid_len;
+ unsigned lup = 0;
+ int result, n;
+ const char *lookup_request[] = { "*cmusaslsecretOTP",
+ NULL };
+ const char *store_request[] = { "cmusaslsecretOTP",
+ NULL };
+ struct propval auxprop_values[2];
+ char mda[10];
+ time_t timeout;
+ sasl_secret_t *sec = NULL;
+ struct propctx *propctx = NULL;
+
+ /* should have received authzid NUL authid */
+
+ /* get authzid */
+ authzid = clientin;
+ while ((lup < clientinlen) && (clientin[lup] != 0)) ++lup;
+
+ if (lup >= clientinlen) {
+ SETERROR(params->utils, "Can only find OTP authzid (no authid)");
+ return SASL_BADPROT;
+ }
+
+ /* get authid */
+ ++lup;
+ authidp = clientin + lup;
+ while ((lup < clientinlen) && (clientin[lup] != 0)) ++lup;
+
+ authid_len = clientin + lup - authidp;
+
+ if (lup != clientinlen) {
+ SETERROR(params->utils,
+ "Got more data than we were expecting in the OTP plugin\n");
+ return SASL_BADPROT;
+ }
+
+ text->authid = params->utils->malloc(authid_len + 1);
+ if (text->authid == NULL) {
+ MEMERROR(params->utils);
+ return SASL_NOMEM;
+ }
+
+ /* we can't assume that authid is null-terminated */
+ strncpy(text->authid, authidp, authid_len);
+ text->authid[authid_len] = '\0';
+
+ n = 0;
+ do {
+ /* Get user secret */
+ result = params->utils->prop_request(params->propctx,
+ lookup_request);
+ if (result != SASL_OK) return result;
+
+ /* this will trigger the getting of the aux properties.
+ Must use the fully qualified authid here */
+ result = params->canon_user(params->utils->conn, text->authid, 0,
+ SASL_CU_AUTHID, oparams);
+ if (result != SASL_OK) return result;
+
+ result = params->canon_user(params->utils->conn,
+ strlen(authzid) ? authzid : text->authid,
+ 0, SASL_CU_AUTHZID, oparams);
+ if (result != SASL_OK) return result;
+
+ result = params->utils->prop_getnames(params->propctx,
+ lookup_request,
+ auxprop_values);
+ if (result < 0 ||
+ (!auxprop_values[0].name || !auxprop_values[0].values)) {
+ /* We didn't find this username */
+ SETERROR(params->utils, "no OTP secret in database");
+ result = params->transition ? SASL_TRANS : SASL_NOUSER;
+ return (result);
+ }
+
+ if (auxprop_values[0].name && auxprop_values[0].values) {
+ result = parse_secret(params->utils,
+ (char*) auxprop_values[0].values[0],
+ auxprop_values[0].valsize,
+ mda, &text->seq, text->seed, text->otp,
+ &timeout);
+
+ if (result != SASL_OK) return result;
+ } else {
+ SETERROR(params->utils, "don't have an OTP secret");
+ return SASL_FAIL;
+ }
+
+ text->timestamp = time(0);
+ }
+ /*
+ * check lock timeout
+ *
+ * we try 10 times in 1 second intervals in order to give the other
+ * auth attempt time to finish
+ */
+ while ((text->timestamp < timeout) && (n++ < 10) && !sleep(1));
+
+ if (text->timestamp < timeout) {
+ SETERROR(params->utils,
+ "simultaneous OTP authentications not permitted");
+ return SASL_TRYAGAIN;
+ }
+
+ /* check sequence number */
+ if (text->seq <= 1) {
+ SETERROR(params->utils, "OTP has expired (sequence <= 1)");
+ return SASL_EXPIRED;
+ }
+
+ /* find algorithm */
+ text->alg = algorithm_options;
+ while (text->alg->name) {
+ if (!strcasecmp(text->alg->name, mda))
+ break;
+
+ text->alg++;
+ }
+
+ if (!text->alg->name) {
+ params->utils->seterror(params->utils->conn, 0,
+ "unknown OTP algorithm '%s'", mda);
+ return SASL_FAIL;
+ }
+
+ /* remake the secret with a timeout */
+ result = make_secret(params->utils, text->alg->name, text->seq,
+ text->seed, text->otp,
+ text->timestamp + OTP_LOCK_TIMEOUT, &sec);
+ if (result != SASL_OK) {
+ SETERROR(params->utils, "error making OTP secret");
+ return result;
+ }
+
+ /* do the store */
+ propctx = params->utils->prop_new(0);
+ if (!propctx)
+ result = SASL_FAIL;
+ if (result == SASL_OK)
+ result = params->utils->prop_request(propctx, store_request);
+ if (result == SASL_OK)
+ result = params->utils->prop_set(propctx, "cmusaslsecretOTP",
+ (char *) sec->data, sec->len);
+ if (result == SASL_OK)
+ result = params->utils->auxprop_store(params->utils->conn,
+ propctx, text->authid);
+ if (propctx)
+ params->utils->prop_dispose(&propctx);
+
+ if (sec) params->utils->free(sec);
+
+ if (result != SASL_OK) {
+ SETERROR(params->utils, "Error putting OTP secret");
+ return result;
+ }
+
+ text->locked = 1;
+
+ result = _plug_buf_alloc(params->utils, &(text->out_buf),
+ &(text->out_buf_len), OTP_CHALLENGE_MAX+1);
+ if (result != SASL_OK) return result;
+
+ /* create challenge */
+ sprintf(text->out_buf, "otp-%s %u %s ext",
+ text->alg->name, text->seq-1, text->seed);
+
+ *serverout = text->out_buf;
+ *serveroutlen = (unsigned) strlen(text->out_buf);
+
+ text->state = 2;
+
+ return SASL_CONTINUE;
+}
+
+static int
+otp_server_mech_step2(server_context_t *text,
+ sasl_server_params_t *params,
+ const char *clientin,
+ unsigned clientinlen,
+ const char **serverout __attribute__((unused)),
+ unsigned *serveroutlen __attribute__((unused)),
+ sasl_out_params_t *oparams)
+{
+ char response[OTP_RESPONSE_MAX+1];
+ int result;
+ sasl_secret_t *sec = NULL;
+ struct propctx *propctx = NULL;
+ const char *store_request[] = { "cmusaslsecretOTP",
+ NULL };
+
+ if (clientinlen > OTP_RESPONSE_MAX) {
+ SETERROR(params->utils, "OTP response too long");
+ return SASL_BADPROT;
+ }
+
+ /* we can't assume that the response is null-terminated */
+ strncpy(response, clientin, clientinlen);
+ response[clientinlen] = '\0';
+
+ /* check timeout */
+ if (time(0) > text->timestamp + OTP_LOCK_TIMEOUT) {
+ SETERROR(params->utils, "OTP: server timed out");
+ return SASL_UNAVAIL;
+ }
+
+ /* verify response */
+ result = verify_response(text, params->utils, response);
+ if (result != SASL_OK) return result;
+
+ /* make the new secret */
+ result = make_secret(params->utils, text->alg->name, text->seq,
+ text->seed, text->otp, 0, &sec);
+ if (result != SASL_OK) {
+ SETERROR(params->utils, "error making OTP secret");
+ }
+
+ /* do the store */
+ propctx = params->utils->prop_new(0);
+ if (!propctx)
+ result = SASL_FAIL;
+ if (result == SASL_OK)
+ result = params->utils->prop_request(propctx, store_request);
+ if (result == SASL_OK)
+ result = params->utils->prop_set(propctx, "cmusaslsecretOTP",
+ (char *) sec->data, sec->len);
+ if (result == SASL_OK)
+ result = params->utils->auxprop_store(params->utils->conn,
+ propctx, text->authid);
+ if (propctx)
+ params->utils->prop_dispose(&propctx);
+
+ if (result) {
+ SETERROR(params->utils, "Error putting OTP secret");
+ }
+
+ text->locked = 0;
+
+ if (sec) _plug_free_secret(params->utils, &sec);
+
+ /* set oparams */
+ oparams->doneflag = 1;
+ oparams->mech_ssf = 0;
+ oparams->maxoutbuf = 0;
+ oparams->encode_context = NULL;
+ oparams->encode = NULL;
+ oparams->decode_context = NULL;
+ oparams->decode = NULL;
+ oparams->param_version = 0;
+
+ return result;
+}
+
+static int otp_server_mech_step(void *conn_context,
+ sasl_server_params_t *params,
+ const char *clientin,
+ unsigned clientinlen,
+ const char **serverout,
+ unsigned *serveroutlen,
+ sasl_out_params_t *oparams)
+{
+ server_context_t *text = (server_context_t *) conn_context;
+
+ *serverout = NULL;
+ *serveroutlen = 0;
+
+ switch (text->state) {
+
+ case 1:
+ return otp_server_mech_step1(text, params, clientin, clientinlen,
+ serverout, serveroutlen, oparams);
+
+ case 2:
+ return otp_server_mech_step2(text, params, clientin, clientinlen,
+ serverout, serveroutlen, oparams);
+
+ default:
+ params->utils->log(NULL, SASL_LOG_ERR,
+ "Invalid OTP server step %d\n", text->state);
+ return SASL_FAIL;
+ }
+
+ return SASL_FAIL; /* should never get here */
+}
+
+static void otp_server_mech_dispose(void *conn_context,
+ const sasl_utils_t *utils)
+{
+ server_context_t *text = (server_context_t *) conn_context;
+ sasl_secret_t *sec;
+ struct propctx *propctx = NULL;
+ const char *store_request[] = { "cmusaslsecretOTP",
+ NULL };
+ int r;
+
+ if (!text) return;
+
+ /* if we created a challenge, but bailed before the verification of the
+ response, release the lock on the user key */
+ if (text->locked && (time(0) < text->timestamp + OTP_LOCK_TIMEOUT)) {
+ r = make_secret(utils, text->alg->name, text->seq,
+ text->seed, text->otp, 0, &sec);
+ if (r != SASL_OK) {
+ SETERROR(utils, "error making OTP secret");
+ if (sec) utils->free(sec);
+ sec = NULL;
+ }
+
+ /* do the store */
+ propctx = utils->prop_new(0);
+ if (!propctx)
+ r = SASL_FAIL;
+ if (!r)
+ r = utils->prop_request(propctx, store_request);
+ if (!r)
+ r = utils->prop_set(propctx, "cmusaslsecretOTP",
+ (sec ? (char *) sec->data : NULL),
+ (sec ? sec->len : 0));
+ if (!r)
+ r = utils->auxprop_store(utils->conn, propctx, text->authid);
+ if (propctx)
+ utils->prop_dispose(&propctx);
+
+ if (r) {
+ SETERROR(utils, "Error putting OTP secret");
+ }
+
+ if (sec) _plug_free_secret(utils, &sec);
+ }
+
+ if (text->authid) _plug_free_string(utils, &(text->authid));
+ if (text->realm) _plug_free_string(utils, &(text->realm));
+
+ if (text->out_buf) utils->free(text->out_buf);
+
+ utils->free(text);
+}
+
+static int otp_setpass(void *glob_context __attribute__((unused)),
+ sasl_server_params_t *sparams,
+ const char *userstr,
+ const char *pass, unsigned passlen,
+ const char *oldpass __attribute__((unused)),
+ unsigned oldpasslen __attribute__((unused)),
+ unsigned flags)
+{
+ int r;
+ char *user = NULL;
+ char *user_only = NULL;
+ char *realm = NULL;
+ sasl_secret_t *sec;
+ struct propctx *propctx = NULL;
+ const char *store_request[] = { "cmusaslsecretOTP",
+ NULL };
+
+ /* Do we have a backend that can store properties? */
+ if (!sparams->utils->auxprop_store ||
+ sparams->utils->auxprop_store(NULL, NULL, NULL) != SASL_OK) {
+ SETERROR(sparams->utils, "OTP: auxprop backend can't store properties");
+ return SASL_NOMECH;
+ }
+
+ r = _plug_parseuser(sparams->utils,
+ &user_only,
+ &realm,
+ sparams->user_realm,
+ sparams->serverFQDN,
+ userstr);
+ if (r) {
+ SETERROR(sparams->utils, "OTP: Error parsing user");
+ return r;
+ }
+
+ r = _plug_make_fulluser(sparams->utils, &user, user_only, realm);
+ if (r) {
+ goto cleanup;
+ }
+
+ if ((flags & SASL_SET_DISABLE) || pass == NULL) {
+ sec = NULL;
+ } else {
+ algorithm_option_t *algs;
+ const char *mda;
+ unsigned int len;
+ unsigned short randnum;
+ char seed[OTP_SEED_MAX+1];
+ unsigned char otp[OTP_HASH_SIZE];
+
+ sparams->utils->getopt(sparams->utils->getopt_context,
+ "OTP", "otp_mda", &mda, &len);
+ if (!mda) mda = OTP_MDA_DEFAULT;
+
+ algs = algorithm_options;
+ while (algs->name) {
+ if (!strcasecmp(algs->name, mda) ||
+ !strcasecmp(algs->evp_name, mda))
+ break;
+
+ algs++;
+ }
+
+ if (!algs->name) {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "unknown OTP algorithm '%s'", mda);
+ r = SASL_FAIL;
+ goto cleanup;
+ }
+
+ sparams->utils->rand(sparams->utils->rpool,
+ (char*) &randnum, sizeof(randnum));
+ sprintf(seed, "%.2s%04u", sparams->serverFQDN, (randnum % 9999) + 1);
+
+ r = generate_otp(sparams->utils, algs, OTP_SEQUENCE_DEFAULT,
+ seed, (unsigned char *) pass, passlen, otp);
+ if (r != SASL_OK) {
+ /* generate_otp() takes care of error message */
+ goto cleanup;
+ }
+
+ r = make_secret(sparams->utils, algs->name, OTP_SEQUENCE_DEFAULT,
+ seed, otp, 0, &sec);
+ if (r != SASL_OK) {
+ SETERROR(sparams->utils, "error making OTP secret");
+ goto cleanup;
+ }
+ }
+
+ /* do the store */
+ propctx = sparams->utils->prop_new(0);
+ if (!propctx)
+ r = SASL_FAIL;
+ if (!r)
+ r = sparams->utils->prop_request(propctx, store_request);
+ if (!r)
+ r = sparams->utils->prop_set(propctx, "cmusaslsecretOTP",
+ (sec ? (char *) sec->data : NULL),
+ (sec ? sec->len : 0));
+ if (!r)
+ r = sparams->utils->auxprop_store(sparams->utils->conn, propctx, user);
+ if (propctx)
+ sparams->utils->prop_dispose(&propctx);
+
+ if (r) {
+ SETERROR(sparams->utils, "Error putting OTP secret");
+ goto cleanup;
+ }
+
+ sparams->utils->log(NULL, SASL_LOG_DEBUG, "Setpass for OTP successful\n");
+
+ cleanup:
+
+ if (user) _plug_free_string(sparams->utils, &user);
+ if (user_only) _plug_free_string(sparams->utils, &user_only);
+ if (realm) _plug_free_string(sparams->utils, &realm);
+ if (sec) _plug_free_secret(sparams->utils, &sec);
+
+ return r;
+}
+
+static int otp_mech_avail(void *glob_context __attribute__((unused)),
+ sasl_server_params_t *sparams,
+ void **conn_context __attribute__((unused)))
+{
+ /* Do we have a backend that can store properties? */
+ if (!sparams->utils->auxprop_store ||
+ sparams->utils->auxprop_store(NULL, NULL, NULL) != SASL_OK) {
+ sparams->utils->log(NULL,
+ SASL_LOG_DEBUG,
+ "OTP: auxprop backend can't store properties");
+ return SASL_NOMECH;
+ }
+
+ return SASL_OK;
+}
+
+static sasl_server_plug_t otp_server_plugins[] =
+{
+ {
+ "OTP", /* mech_name */
+ 0, /* max_ssf */
+ SASL_SEC_NOPLAINTEXT
+ | SASL_SEC_NOANONYMOUS
+ | SASL_SEC_FORWARD_SECRECY, /* security_flags */
+ SASL_FEAT_WANT_CLIENT_FIRST
+ | SASL_FEAT_ALLOWS_PROXY, /* features */
+ NULL, /* glob_context */
+ &otp_server_mech_new, /* mech_new */
+ &otp_server_mech_step, /* mech_step */
+ &otp_server_mech_dispose, /* mech_dispose */
+ &otp_common_mech_free, /* mech_free */
+ &otp_setpass, /* setpass */
+ NULL, /* user_query */
+ NULL, /* idle */
+ &otp_mech_avail, /* mech avail */
+ NULL /* spare */
+ }
+};
+#endif /* HAVE_OPIE */
+
+int otp_server_plug_init(const sasl_utils_t *utils,
+ int maxversion,
+ int *out_version,
+ sasl_server_plug_t **pluglist,
+ int *plugcount)
+{
+ if (maxversion < SASL_SERVER_PLUG_VERSION) {
+ SETERROR(utils, "OTP version mismatch");
+ return SASL_BADVERS;
+ }
+
+ *out_version = SASL_SERVER_PLUG_VERSION;
+ *pluglist = otp_server_plugins;
+ *plugcount = 1;
+
+ /* Add all digests */
+ OpenSSL_add_all_digests();
+
+ return SASL_OK;
+}
+
+/***************************** Client Section *****************************/
+
+typedef struct client_context {
+ int state;
+
+ sasl_secret_t *password;
+ unsigned int free_password; /* set if we need to free password */
+
+ const char *otpassword;
+
+ char *out_buf;
+ unsigned out_buf_len;
+
+ char challenge[OTP_CHALLENGE_MAX+1];
+} client_context_t;
+
+static int otp_client_mech_new(void *glob_context __attribute__((unused)),
+ sasl_client_params_t *params,
+ void **conn_context)
+{
+ client_context_t *text;
+
+ /* holds state are in */
+ text = params->utils->malloc(sizeof(client_context_t));
+ if (text == NULL) {
+ MEMERROR( params->utils );
+ return SASL_NOMEM;
+ }
+
+ memset(text, 0, sizeof(client_context_t));
+
+ text->state = 1;
+
+ *conn_context = text;
+
+ return SASL_OK;
+}
+
+static int otp_client_mech_step1(client_context_t *text,
+ sasl_client_params_t *params,
+ const char *serverin __attribute__((unused)),
+ unsigned serverinlen __attribute__((unused)),
+ sasl_interact_t **prompt_need,
+ const char **clientout,
+ unsigned *clientoutlen,
+ sasl_out_params_t *oparams)
+{
+ const char *user = NULL, *authid = NULL;
+ int user_result = SASL_OK;
+ int auth_result = SASL_OK;
+ int pass_result = SASL_OK;
+ sasl_chalprompt_t *echo_cb;
+ void *echo_context;
+ int result;
+
+ /* check if sec layer strong enough */
+ if (params->props.min_ssf > params->external_ssf) {
+ SETERROR( params->utils, "SSF requested of OTP plugin");
+ return SASL_TOOWEAK;
+ }
+
+ /* try to get the authid */
+ if (oparams->authid == NULL) {
+ auth_result = _plug_get_authid(params->utils, &authid, prompt_need);
+
+ if ((auth_result != SASL_OK) && (auth_result != SASL_INTERACT))
+ return auth_result;
+ }
+
+ /* try to get the userid */
+ if (oparams->user == NULL) {
+ user_result = _plug_get_userid(params->utils, &user, prompt_need);
+
+ if ((user_result != SASL_OK) && (user_result != SASL_INTERACT))
+ return user_result;
+ }
+
+ /* try to get the secret pass-phrase if we don't have a chalprompt */
+ if ((params->utils->getcallback(params->utils->conn, SASL_CB_ECHOPROMPT,
+ (sasl_callback_ft *)&echo_cb, &echo_context) == SASL_FAIL) &&
+ (text->password == NULL)) {
+ pass_result = _plug_get_password(params->utils, &text->password,
+ &text->free_password, prompt_need);
+
+ if ((pass_result != SASL_OK) && (pass_result != SASL_INTERACT))
+ return pass_result;
+ }
+
+ /* free prompts we got */
+ if (prompt_need && *prompt_need) {
+ params->utils->free(*prompt_need);
+ *prompt_need = NULL;
+ }
+
+ /* if there are prompts not filled in */
+ if ((user_result == SASL_INTERACT) || (auth_result == SASL_INTERACT) ||
+ (pass_result == SASL_INTERACT)) {
+ /* make the prompt list */
+ result =
+ _plug_make_prompts(params->utils, prompt_need,
+ user_result == SASL_INTERACT ?
+ "Please enter your authorization name" : NULL,
+ NULL,
+ auth_result == SASL_INTERACT ?
+ "Please enter your authentication name" : NULL,
+ NULL,
+ pass_result == SASL_INTERACT ?
+ "Please enter your secret pass-phrase" : NULL,
+ NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL);
+ if (result != SASL_OK) return result;
+
+ return SASL_INTERACT;
+ }
+
+ if (!user || !*user) {
+ result = params->canon_user(params->utils->conn, authid, 0,
+ SASL_CU_AUTHID | SASL_CU_AUTHZID, oparams);
+ }
+ else {
+ result = params->canon_user(params->utils->conn, user, 0,
+ SASL_CU_AUTHZID, oparams);
+ if (result != SASL_OK) return result;
+
+ result = params->canon_user(params->utils->conn, authid, 0,
+ SASL_CU_AUTHID, oparams);
+ }
+ if (result != SASL_OK) return result;
+
+ /* send authorized id NUL authentication id */
+ *clientoutlen = oparams->ulen + 1 + oparams->alen;
+
+ /* remember the extra NUL on the end for stupid clients */
+ result = _plug_buf_alloc(params->utils, &(text->out_buf),
+ &(text->out_buf_len), *clientoutlen + 1);
+ if (result != SASL_OK) return result;
+
+ memset(text->out_buf, 0, *clientoutlen + 1);
+ memcpy(text->out_buf, oparams->user, oparams->ulen);
+ memcpy(text->out_buf+oparams->ulen+1, oparams->authid, oparams->alen);
+ *clientout = text->out_buf;
+
+ text->state = 2;
+
+ return SASL_CONTINUE;
+}
+
+static int otp_client_mech_step2(client_context_t *text,
+ sasl_client_params_t *params,
+ const char *serverin,
+ unsigned serverinlen,
+ sasl_interact_t **prompt_need,
+ const char **clientout,
+ unsigned *clientoutlen,
+ sasl_out_params_t *oparams)
+{
+ int echo_result = SASL_OK;
+ int result;
+
+ if (serverinlen > OTP_CHALLENGE_MAX) {
+ SETERROR(params->utils, "OTP challenge too long");
+ return SASL_BADPROT;
+ }
+
+ /* we can't assume that challenge is null-terminated */
+ strncpy(text->challenge, serverin, serverinlen);
+ text->challenge[serverinlen] = '\0';
+
+ /* try to get the one-time password if we don't have the secret */
+ if ((text->password == NULL) && (text->otpassword == NULL)) {
+ echo_result = _plug_challenge_prompt(params->utils,
+ SASL_CB_ECHOPROMPT,
+ text->challenge,
+ "Please enter your one-time password",
+ &text->otpassword,
+ prompt_need);
+
+ if ((echo_result != SASL_OK) && (echo_result != SASL_INTERACT))
+ return echo_result;
+ }
+
+ /* free prompts we got */
+ if (prompt_need && *prompt_need) {
+ params->utils->free(*prompt_need);
+ *prompt_need = NULL;
+ }
+
+ /* if there are prompts not filled in */
+ if (echo_result == SASL_INTERACT) {
+ /* make the prompt list */
+ result =
+ _plug_make_prompts(params->utils,
+ prompt_need,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ text->challenge,
+ "Please enter your one-time password",
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ if (result != SASL_OK) return result;
+
+ return SASL_INTERACT;
+ }
+
+ /* the application provided us with a one-time password so use it */
+ if (text->otpassword) {
+ *clientout = text->otpassword;
+ *clientoutlen = (unsigned) strlen(text->otpassword);
+ }
+ /* generate our own response using the user's secret pass-phrase */
+ else {
+ algorithm_option_t *alg;
+ unsigned seq;
+ char seed[OTP_SEED_MAX+1];
+ unsigned char otp[OTP_HASH_SIZE];
+ int init_done = 0;
+
+ /* parse challenge */
+ result = parse_challenge(params->utils,
+ text->challenge,
+ &alg,
+ &seq,
+ seed,
+ 0);
+ if (result != SASL_OK) return result;
+
+ if (!text->password) {
+ PARAMERROR(params->utils);
+ return SASL_BADPARAM;
+ }
+
+ if (seq < 1) {
+ SETERROR(params->utils, "OTP has expired (sequence < 1)");
+ return SASL_EXPIRED;
+ }
+
+ /* generate otp */
+ result = generate_otp(params->utils, alg, seq, seed,
+ text->password->data, text->password->len, otp);
+ if (result != SASL_OK) return result;
+
+ result = _plug_buf_alloc(params->utils, &(text->out_buf),
+ &(text->out_buf_len), OTP_RESPONSE_MAX+1);
+ if (result != SASL_OK) return result;
+
+ if (seq < OTP_SEQUENCE_REINIT) {
+ unsigned short randnum;
+ char new_seed[OTP_SEED_MAX+1];
+ unsigned char new_otp[OTP_HASH_SIZE];
+
+ /* try to reinitialize */
+
+ /* make sure we have a different seed */
+ do {
+ params->utils->rand(params->utils->rpool,
+ (char*) &randnum, sizeof(randnum));
+ sprintf(new_seed, "%.2s%04u", params->serverFQDN,
+ (randnum % 9999) + 1);
+ } while (!strcasecmp(seed, new_seed));
+
+ result = generate_otp(params->utils, alg, OTP_SEQUENCE_DEFAULT,
+ new_seed, text->password->data, text->password->len, new_otp);
+
+ if (result == SASL_OK) {
+ /* create an init-hex response */
+ strcpy(text->out_buf, OTP_INIT_HEX_TYPE);
+ bin2hex(otp, OTP_HASH_SIZE,
+ text->out_buf+strlen(text->out_buf));
+ sprintf(text->out_buf+strlen(text->out_buf), ":%s %u %s:",
+ alg->name, OTP_SEQUENCE_DEFAULT, new_seed);
+ bin2hex(new_otp, OTP_HASH_SIZE,
+ text->out_buf+strlen(text->out_buf));
+ init_done = 1;
+ }
+ else {
+ /* just do a regular response */
+ }
+ }
+
+ if (!init_done) {
+ /* created hex response */
+ strcpy(text->out_buf, OTP_HEX_TYPE);
+ bin2hex(otp, OTP_HASH_SIZE, text->out_buf+strlen(text->out_buf));
+ }
+
+ *clientout = text->out_buf;
+ *clientoutlen = (unsigned) strlen(text->out_buf);
+ }
+
+ /* set oparams */
+ oparams->doneflag = 1;
+ oparams->mech_ssf = 0;
+ oparams->maxoutbuf = 0;
+ oparams->encode_context = NULL;
+ oparams->encode = NULL;
+ oparams->decode_context = NULL;
+ oparams->decode = NULL;
+ oparams->param_version = 0;
+
+ return SASL_OK;
+}
+
+static int otp_client_mech_step(void *conn_context,
+ sasl_client_params_t *params,
+ const char *serverin,
+ unsigned serverinlen,
+ sasl_interact_t **prompt_need,
+ const char **clientout,
+ unsigned *clientoutlen,
+ sasl_out_params_t *oparams)
+{
+ client_context_t *text = (client_context_t *) conn_context;
+
+ *clientout = NULL;
+ *clientoutlen = 0;
+
+ switch (text->state) {
+
+ case 1:
+ return otp_client_mech_step1(text, params, serverin, serverinlen,
+ prompt_need, clientout, clientoutlen,
+ oparams);
+
+ case 2:
+ return otp_client_mech_step2(text, params, serverin, serverinlen,
+ prompt_need, clientout, clientoutlen,
+ oparams);
+
+ default:
+ params->utils->log(NULL, SASL_LOG_ERR,
+ "Invalid OTP client step %d\n", text->state);
+ return SASL_FAIL;
+ }
+
+ return SASL_FAIL; /* should never get here */
+}
+
+static void otp_client_mech_dispose(void *conn_context,
+ const sasl_utils_t *utils)
+{
+ client_context_t *text = (client_context_t *) conn_context;
+
+ if (!text) return;
+
+ if (text->free_password) _plug_free_secret(utils, &(text->password));
+
+ if (text->out_buf) utils->free(text->out_buf);
+
+ utils->free(text);
+}
+
+static sasl_client_plug_t otp_client_plugins[] =
+{
+ {
+ "OTP", /* mech_name */
+ 0, /* max_ssf */
+ SASL_SEC_NOPLAINTEXT
+ | SASL_SEC_NOANONYMOUS
+ | SASL_SEC_FORWARD_SECRECY, /* security_flags */
+ SASL_FEAT_WANT_CLIENT_FIRST
+ | SASL_FEAT_ALLOWS_PROXY, /* features */
+ NULL, /* required_prompts */
+ NULL, /* glob_context */
+ &otp_client_mech_new, /* mech_new */
+ &otp_client_mech_step, /* mech_step */
+ &otp_client_mech_dispose, /* mech_dispose */
+ &otp_common_mech_free, /* mech_free */
+ NULL, /* idle */
+ NULL, /* spare */
+ NULL /* spare */
+ }
+};
+
+int otp_client_plug_init(sasl_utils_t *utils,
+ int maxversion,
+ int *out_version,
+ sasl_client_plug_t **pluglist,
+ int *plugcount)
+{
+ if (maxversion < SASL_CLIENT_PLUG_VERSION) {
+ SETERROR(utils, "OTP version mismatch");
+ return SASL_BADVERS;
+ }
+
+ *out_version = SASL_CLIENT_PLUG_VERSION;
+ *pluglist = otp_client_plugins;
+ *plugcount = 1;
+
+ /* Add all digests */
+ OpenSSL_add_all_digests();
+
+ return SASL_OK;
+}
diff --git a/contrib/libs/sasl/plugins/otp.h b/contrib/libs/sasl/plugins/otp.h
new file mode 100644
index 0000000000..06ad32c5c6
--- /dev/null
+++ b/contrib/libs/sasl/plugins/otp.h
@@ -0,0 +1,311 @@
+/* OTP SASL plugin
+ * Ken Murchison
+ */
+/*
+ * Copyright (c) 1998-2016 Carnegie Mellon University. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For permission or any other legal
+ * details, please contact
+ * Carnegie Mellon University
+ * Center for Technology Transfer and Enterprise Creation
+ * 4615 Forbes Avenue
+ * Suite 302
+ * Pittsburgh, PA 15213
+ * (412) 268-7393, fax: (412) 268-7395
+ * innovation@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Computing Services
+ * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _OTP_H_
+#define _OTP_H_
+
+/* Standard dictionary from RFC2289 */
+#define OTP_STD_DICT_SIZE 2048
+#define OTP_4LETTER_OFFSET 571
+
+static const char *otp_std_dict[OTP_STD_DICT_SIZE] =
+{ "A", "ABE", "ACE", "ACT", "AD", "ADA", "ADD",
+"AGO", "AID", "AIM", "AIR", "ALL", "ALP", "AM", "AMY",
+"AN", "ANA", "AND", "ANN", "ANT", "ANY", "APE", "APS",
+"APT", "ARC", "ARE", "ARK", "ARM", "ART", "AS", "ASH",
+"ASK", "AT", "ATE", "AUG", "AUK", "AVE", "AWE", "AWK",
+"AWL", "AWN", "AX", "AYE", "BAD", "BAG", "BAH", "BAM",
+"BAN", "BAR", "BAT", "BAY", "BE", "BED", "BEE", "BEG",
+"BEN", "BET", "BEY", "BIB", "BID", "BIG", "BIN", "BIT",
+"BOB", "BOG", "BON", "BOO", "BOP", "BOW", "BOY", "BUB",
+"BUD", "BUG", "BUM", "BUN", "BUS", "BUT", "BUY", "BY",
+"BYE", "CAB", "CAL", "CAM", "CAN", "CAP", "CAR", "CAT",
+"CAW", "COD", "COG", "COL", "CON", "COO", "COP", "COT",
+"COW", "COY", "CRY", "CUB", "CUE", "CUP", "CUR", "CUT",
+"DAB", "DAD", "DAM", "DAN", "DAR", "DAY", "DEE", "DEL",
+"DEN", "DES", "DEW", "DID", "DIE", "DIG", "DIN", "DIP",
+"DO", "DOE", "DOG", "DON", "DOT", "DOW", "DRY", "DUB",
+"DUD", "DUE", "DUG", "DUN", "EAR", "EAT", "ED", "EEL",
+"EGG", "EGO", "ELI", "ELK", "ELM", "ELY", "EM", "END",
+"EST", "ETC", "EVA", "EVE", "EWE", "EYE", "FAD", "FAN",
+"FAR", "FAT", "FAY", "FED", "FEE", "FEW", "FIB", "FIG",
+"FIN", "FIR", "FIT", "FLO", "FLY", "FOE", "FOG", "FOR",
+"FRY", "FUM", "FUN", "FUR", "GAB", "GAD", "GAG", "GAL",
+"GAM", "GAP", "GAS", "GAY", "GEE", "GEL", "GEM", "GET",
+"GIG", "GIL", "GIN", "GO", "GOT", "GUM", "GUN", "GUS",
+"GUT", "GUY", "GYM", "GYP", "HA", "HAD", "HAL", "HAM",
+"HAN", "HAP", "HAS", "HAT", "HAW", "HAY", "HE", "HEM",
+"HEN", "HER", "HEW", "HEY", "HI", "HID", "HIM", "HIP",
+"HIS", "HIT", "HO", "HOB", "HOC", "HOE", "HOG", "HOP",
+"HOT", "HOW", "HUB", "HUE", "HUG", "HUH", "HUM", "HUT",
+"I", "ICY", "IDA", "IF", "IKE", "ILL", "INK", "INN",
+"IO", "ION", "IQ", "IRA", "IRE", "IRK", "IS", "IT",
+"ITS", "IVY", "JAB", "JAG", "JAM", "JAN", "JAR", "JAW",
+"JAY", "JET", "JIG", "JIM", "JO", "JOB", "JOE", "JOG",
+"JOT", "JOY", "JUG", "JUT", "KAY", "KEG", "KEN", "KEY",
+"KID", "KIM", "KIN", "KIT", "LA", "LAB", "LAC", "LAD",
+"LAG", "LAM", "LAP", "LAW", "LAY", "LEA", "LED", "LEE",
+"LEG", "LEN", "LEO", "LET", "LEW", "LID", "LIE", "LIN",
+"LIP", "LIT", "LO", "LOB", "LOG", "LOP", "LOS", "LOT",
+"LOU", "LOW", "LOY", "LUG", "LYE", "MA", "MAC", "MAD",
+"MAE", "MAN", "MAO", "MAP", "MAT", "MAW", "MAY", "ME",
+"MEG", "MEL", "MEN", "MET", "MEW", "MID", "MIN", "MIT",
+"MOB", "MOD", "MOE", "MOO", "MOP", "MOS", "MOT", "MOW",
+"MUD", "MUG", "MUM", "MY", "NAB", "NAG", "NAN", "NAP",
+"NAT", "NAY", "NE", "NED", "NEE", "NET", "NEW", "NIB",
+"NIL", "NIP", "NIT", "NO", "NOB", "NOD", "NON", "NOR",
+"NOT", "NOV", "NOW", "NU", "NUN", "NUT", "O", "OAF",
+"OAK", "OAR", "OAT", "ODD", "ODE", "OF", "OFF", "OFT",
+"OH", "OIL", "OK", "OLD", "ON", "ONE", "OR", "ORB",
+"ORE", "ORR", "OS", "OTT", "OUR", "OUT", "OVA", "OW",
+"OWE", "OWL", "OWN", "OX", "PA", "PAD", "PAL", "PAM",
+"PAN", "PAP", "PAR", "PAT", "PAW", "PAY", "PEA", "PEG",
+"PEN", "PEP", "PER", "PET", "PEW", "PHI", "PI", "PIE",
+"PIN", "PIT", "PLY", "PO", "POD", "POE", "POP", "POT",
+"POW", "PRO", "PRY", "PUB", "PUG", "PUN", "PUP", "PUT",
+"QUO", "RAG", "RAM", "RAN", "RAP", "RAT", "RAW", "RAY",
+"REB", "RED", "REP", "RET", "RIB", "RID", "RIG", "RIM",
+"RIO", "RIP", "ROB", "ROD", "ROE", "RON", "ROT", "ROW",
+"ROY", "RUB", "RUE", "RUG", "RUM", "RUN", "RYE", "SAC",
+"SAD", "SAG", "SAL", "SAM", "SAN", "SAP", "SAT", "SAW",
+"SAY", "SEA", "SEC", "SEE", "SEN", "SET", "SEW", "SHE",
+"SHY", "SIN", "SIP", "SIR", "SIS", "SIT", "SKI", "SKY",
+"SLY", "SO", "SOB", "SOD", "SON", "SOP", "SOW", "SOY",
+"SPA", "SPY", "SUB", "SUD", "SUE", "SUM", "SUN", "SUP",
+"TAB", "TAD", "TAG", "TAN", "TAP", "TAR", "TEA", "TED",
+"TEE", "TEN", "THE", "THY", "TIC", "TIE", "TIM", "TIN",
+"TIP", "TO", "TOE", "TOG", "TOM", "TON", "TOO", "TOP",
+"TOW", "TOY", "TRY", "TUB", "TUG", "TUM", "TUN", "TWO",
+"UN", "UP", "US", "USE", "VAN", "VAT", "VET", "VIE",
+"WAD", "WAG", "WAR", "WAS", "WAY", "WE", "WEB", "WED",
+"WEE", "WET", "WHO", "WHY", "WIN", "WIT", "WOK", "WON",
+"WOO", "WOW", "WRY", "WU", "YAM", "YAP", "YAW", "YE",
+"YEA", "YES", "YET", "YOU", "ABED", "ABEL", "ABET", "ABLE",
+"ABUT", "ACHE", "ACID", "ACME", "ACRE", "ACTA", "ACTS", "ADAM",
+"ADDS", "ADEN", "AFAR", "AFRO", "AGEE", "AHEM", "AHOY", "AIDA",
+"AIDE", "AIDS", "AIRY", "AJAR", "AKIN", "ALAN", "ALEC", "ALGA",
+"ALIA", "ALLY", "ALMA", "ALOE", "ALSO", "ALTO", "ALUM", "ALVA",
+"AMEN", "AMES", "AMID", "AMMO", "AMOK", "AMOS", "AMRA", "ANDY",
+"ANEW", "ANNA", "ANNE", "ANTE", "ANTI", "AQUA", "ARAB", "ARCH",
+"AREA", "ARGO", "ARID", "ARMY", "ARTS", "ARTY", "ASIA", "ASKS",
+"ATOM", "AUNT", "AURA", "AUTO", "AVER", "AVID", "AVIS", "AVON",
+"AVOW", "AWAY", "AWRY", "BABE", "BABY", "BACH", "BACK", "BADE",
+"BAIL", "BAIT", "BAKE", "BALD", "BALE", "BALI", "BALK", "BALL",
+"BALM", "BAND", "BANE", "BANG", "BANK", "BARB", "BARD", "BARE",
+"BARK", "BARN", "BARR", "BASE", "BASH", "BASK", "BASS", "BATE",
+"BATH", "BAWD", "BAWL", "BEAD", "BEAK", "BEAM", "BEAN", "BEAR",
+"BEAT", "BEAU", "BECK", "BEEF", "BEEN", "BEER", "BEET", "BELA",
+"BELL", "BELT", "BEND", "BENT", "BERG", "BERN", "BERT", "BESS",
+"BEST", "BETA", "BETH", "BHOY", "BIAS", "BIDE", "BIEN", "BILE",
+"BILK", "BILL", "BIND", "BING", "BIRD", "BITE", "BITS", "BLAB",
+"BLAT", "BLED", "BLEW", "BLOB", "BLOC", "BLOT", "BLOW", "BLUE",
+"BLUM", "BLUR", "BOAR", "BOAT", "BOCA", "BOCK", "BODE", "BODY",
+"BOGY", "BOHR", "BOIL", "BOLD", "BOLO", "BOLT", "BOMB", "BONA",
+"BOND", "BONE", "BONG", "BONN", "BONY", "BOOK", "BOOM", "BOON",
+"BOOT", "BORE", "BORG", "BORN", "BOSE", "BOSS", "BOTH", "BOUT",
+"BOWL", "BOYD", "BRAD", "BRAE", "BRAG", "BRAN", "BRAY", "BRED",
+"BREW", "BRIG", "BRIM", "BROW", "BUCK", "BUDD", "BUFF", "BULB",
+"BULK", "BULL", "BUNK", "BUNT", "BUOY", "BURG", "BURL", "BURN",
+"BURR", "BURT", "BURY", "BUSH", "BUSS", "BUST", "BUSY", "BYTE",
+"CADY", "CAFE", "CAGE", "CAIN", "CAKE", "CALF", "CALL", "CALM",
+"CAME", "CANE", "CANT", "CARD", "CARE", "CARL", "CARR", "CART",
+"CASE", "CASH", "CASK", "CAST", "CAVE", "CEIL", "CELL", "CENT",
+"CERN", "CHAD", "CHAR", "CHAT", "CHAW", "CHEF", "CHEN", "CHEW",
+"CHIC", "CHIN", "CHOU", "CHOW", "CHUB", "CHUG", "CHUM", "CITE",
+"CITY", "CLAD", "CLAM", "CLAN", "CLAW", "CLAY", "CLOD", "CLOG",
+"CLOT", "CLUB", "CLUE", "COAL", "COAT", "COCA", "COCK", "COCO",
+"CODA", "CODE", "CODY", "COED", "COIL", "COIN", "COKE", "COLA",
+"COLD", "COLT", "COMA", "COMB", "COME", "COOK", "COOL", "COON",
+"COOT", "CORD", "CORE", "CORK", "CORN", "COST", "COVE", "COWL",
+"CRAB", "CRAG", "CRAM", "CRAY", "CREW", "CRIB", "CROW", "CRUD",
+"CUBA", "CUBE", "CUFF", "CULL", "CULT", "CUNY", "CURB", "CURD",
+"CURE", "CURL", "CURT", "CUTS", "DADE", "DALE", "DAME", "DANA",
+"DANE", "DANG", "DANK", "DARE", "DARK", "DARN", "DART", "DASH",
+"DATA", "DATE", "DAVE", "DAVY", "DAWN", "DAYS", "DEAD", "DEAF",
+"DEAL", "DEAN", "DEAR", "DEBT", "DECK", "DEED", "DEEM", "DEER",
+"DEFT", "DEFY", "DELL", "DENT", "DENY", "DESK", "DIAL", "DICE",
+"DIED", "DIET", "DIME", "DINE", "DING", "DINT", "DIRE", "DIRT",
+"DISC", "DISH", "DISK", "DIVE", "DOCK", "DOES", "DOLE", "DOLL",
+"DOLT", "DOME", "DONE", "DOOM", "DOOR", "DORA", "DOSE", "DOTE",
+"DOUG", "DOUR", "DOVE", "DOWN", "DRAB", "DRAG", "DRAM", "DRAW",
+"DREW", "DRUB", "DRUG", "DRUM", "DUAL", "DUCK", "DUCT", "DUEL",
+"DUET", "DUKE", "DULL", "DUMB", "DUNE", "DUNK", "DUSK", "DUST",
+"DUTY", "EACH", "EARL", "EARN", "EASE", "EAST", "EASY", "EBEN",
+"ECHO", "EDDY", "EDEN", "EDGE", "EDGY", "EDIT", "EDNA", "EGAN",
+"ELAN", "ELBA", "ELLA", "ELSE", "EMIL", "EMIT", "EMMA", "ENDS",
+"ERIC", "EROS", "EVEN", "EVER", "EVIL", "EYED", "FACE", "FACT",
+"FADE", "FAIL", "FAIN", "FAIR", "FAKE", "FALL", "FAME", "FANG",
+"FARM", "FAST", "FATE", "FAWN", "FEAR", "FEAT", "FEED", "FEEL",
+"FEET", "FELL", "FELT", "FEND", "FERN", "FEST", "FEUD", "FIEF",
+"FIGS", "FILE", "FILL", "FILM", "FIND", "FINE", "FINK", "FIRE",
+"FIRM", "FISH", "FISK", "FIST", "FITS", "FIVE", "FLAG", "FLAK",
+"FLAM", "FLAT", "FLAW", "FLEA", "FLED", "FLEW", "FLIT", "FLOC",
+"FLOG", "FLOW", "FLUB", "FLUE", "FOAL", "FOAM", "FOGY", "FOIL",
+"FOLD", "FOLK", "FOND", "FONT", "FOOD", "FOOL", "FOOT", "FORD",
+"FORE", "FORK", "FORM", "FORT", "FOSS", "FOUL", "FOUR", "FOWL",
+"FRAU", "FRAY", "FRED", "FREE", "FRET", "FREY", "FROG", "FROM",
+"FUEL", "FULL", "FUME", "FUND", "FUNK", "FURY", "FUSE", "FUSS",
+"GAFF", "GAGE", "GAIL", "GAIN", "GAIT", "GALA", "GALE", "GALL",
+"GALT", "GAME", "GANG", "GARB", "GARY", "GASH", "GATE", "GAUL",
+"GAUR", "GAVE", "GAWK", "GEAR", "GELD", "GENE", "GENT", "GERM",
+"GETS", "GIBE", "GIFT", "GILD", "GILL", "GILT", "GINA", "GIRD",
+"GIRL", "GIST", "GIVE", "GLAD", "GLEE", "GLEN", "GLIB", "GLOB",
+"GLOM", "GLOW", "GLUE", "GLUM", "GLUT", "GOAD", "GOAL", "GOAT",
+"GOER", "GOES", "GOLD", "GOLF", "GONE", "GONG", "GOOD", "GOOF",
+"GORE", "GORY", "GOSH", "GOUT", "GOWN", "GRAB", "GRAD", "GRAY",
+"GREG", "GREW", "GREY", "GRID", "GRIM", "GRIN", "GRIT", "GROW",
+"GRUB", "GULF", "GULL", "GUNK", "GURU", "GUSH", "GUST", "GWEN",
+"GWYN", "HAAG", "HAAS", "HACK", "HAIL", "HAIR", "HALE", "HALF",
+"HALL", "HALO", "HALT", "HAND", "HANG", "HANK", "HANS", "HARD",
+"HARK", "HARM", "HART", "HASH", "HAST", "HATE", "HATH", "HAUL",
+"HAVE", "HAWK", "HAYS", "HEAD", "HEAL", "HEAR", "HEAT", "HEBE",
+"HECK", "HEED", "HEEL", "HEFT", "HELD", "HELL", "HELM", "HERB",
+"HERD", "HERE", "HERO", "HERS", "HESS", "HEWN", "HICK", "HIDE",
+"HIGH", "HIKE", "HILL", "HILT", "HIND", "HINT", "HIRE", "HISS",
+"HIVE", "HOBO", "HOCK", "HOFF", "HOLD", "HOLE", "HOLM", "HOLT",
+"HOME", "HONE", "HONK", "HOOD", "HOOF", "HOOK", "HOOT", "HORN",
+"HOSE", "HOST", "HOUR", "HOVE", "HOWE", "HOWL", "HOYT", "HUCK",
+"HUED", "HUFF", "HUGE", "HUGH", "HUGO", "HULK", "HULL", "HUNK",
+"HUNT", "HURD", "HURL", "HURT", "HUSH", "HYDE", "HYMN", "IBIS",
+"ICON", "IDEA", "IDLE", "IFFY", "INCA", "INCH", "INTO", "IONS",
+"IOTA", "IOWA", "IRIS", "IRMA", "IRON", "ISLE", "ITCH", "ITEM",
+"IVAN", "JACK", "JADE", "JAIL", "JAKE", "JANE", "JAVA", "JEAN",
+"JEFF", "JERK", "JESS", "JEST", "JIBE", "JILL", "JILT", "JIVE",
+"JOAN", "JOBS", "JOCK", "JOEL", "JOEY", "JOHN", "JOIN", "JOKE",
+"JOLT", "JOVE", "JUDD", "JUDE", "JUDO", "JUDY", "JUJU", "JUKE",
+"JULY", "JUNE", "JUNK", "JUNO", "JURY", "JUST", "JUTE", "KAHN",
+"KALE", "KANE", "KANT", "KARL", "KATE", "KEEL", "KEEN", "KENO",
+"KENT", "KERN", "KERR", "KEYS", "KICK", "KILL", "KIND", "KING",
+"KIRK", "KISS", "KITE", "KLAN", "KNEE", "KNEW", "KNIT", "KNOB",
+"KNOT", "KNOW", "KOCH", "KONG", "KUDO", "KURD", "KURT", "KYLE",
+"LACE", "LACK", "LACY", "LADY", "LAID", "LAIN", "LAIR", "LAKE",
+"LAMB", "LAME", "LAND", "LANE", "LANG", "LARD", "LARK", "LASS",
+"LAST", "LATE", "LAUD", "LAVA", "LAWN", "LAWS", "LAYS", "LEAD",
+"LEAF", "LEAK", "LEAN", "LEAR", "LEEK", "LEER", "LEFT", "LEND",
+"LENS", "LENT", "LEON", "LESK", "LESS", "LEST", "LETS", "LIAR",
+"LICE", "LICK", "LIED", "LIEN", "LIES", "LIEU", "LIFE", "LIFT",
+"LIKE", "LILA", "LILT", "LILY", "LIMA", "LIMB", "LIME", "LIND",
+"LINE", "LINK", "LINT", "LION", "LISA", "LIST", "LIVE", "LOAD",
+"LOAF", "LOAM", "LOAN", "LOCK", "LOFT", "LOGE", "LOIS", "LOLA",
+"LONE", "LONG", "LOOK", "LOON", "LOOT", "LORD", "LORE", "LOSE",
+"LOSS", "LOST", "LOUD", "LOVE", "LOWE", "LUCK", "LUCY", "LUGE",
+"LUKE", "LULU", "LUND", "LUNG", "LURA", "LURE", "LURK", "LUSH",
+"LUST", "LYLE", "LYNN", "LYON", "LYRA", "MACE", "MADE", "MAGI",
+"MAID", "MAIL", "MAIN", "MAKE", "MALE", "MALI", "MALL", "MALT",
+"MANA", "MANN", "MANY", "MARC", "MARE", "MARK", "MARS", "MART",
+"MARY", "MASH", "MASK", "MASS", "MAST", "MATE", "MATH", "MAUL",
+"MAYO", "MEAD", "MEAL", "MEAN", "MEAT", "MEEK", "MEET", "MELD",
+"MELT", "MEMO", "MEND", "MENU", "MERT", "MESH", "MESS", "MICE",
+"MIKE", "MILD", "MILE", "MILK", "MILL", "MILT", "MIMI", "MIND",
+"MINE", "MINI", "MINK", "MINT", "MIRE", "MISS", "MIST", "MITE",
+"MITT", "MOAN", "MOAT", "MOCK", "MODE", "MOLD", "MOLE", "MOLL",
+"MOLT", "MONA", "MONK", "MONT", "MOOD", "MOON", "MOOR", "MOOT",
+"MORE", "MORN", "MORT", "MOSS", "MOST", "MOTH", "MOVE", "MUCH",
+"MUCK", "MUDD", "MUFF", "MULE", "MULL", "MURK", "MUSH", "MUST",
+"MUTE", "MUTT", "MYRA", "MYTH", "NAGY", "NAIL", "NAIR", "NAME",
+"NARY", "NASH", "NAVE", "NAVY", "NEAL", "NEAR", "NEAT", "NECK",
+"NEED", "NEIL", "NELL", "NEON", "NERO", "NESS", "NEST", "NEWS",
+"NEWT", "NIBS", "NICE", "NICK", "NILE", "NINA", "NINE", "NOAH",
+"NODE", "NOEL", "NOLL", "NONE", "NOOK", "NOON", "NORM", "NOSE",
+"NOTE", "NOUN", "NOVA", "NUDE", "NULL", "NUMB", "OATH", "OBEY",
+"OBOE", "ODIN", "OHIO", "OILY", "OINT", "OKAY", "OLAF", "OLDY",
+"OLGA", "OLIN", "OMAN", "OMEN", "OMIT", "ONCE", "ONES", "ONLY",
+"ONTO", "ONUS", "ORAL", "ORGY", "OSLO", "OTIS", "OTTO", "OUCH",
+"OUST", "OUTS", "OVAL", "OVEN", "OVER", "OWLY", "OWNS", "QUAD",
+"QUIT", "QUOD", "RACE", "RACK", "RACY", "RAFT", "RAGE", "RAID",
+"RAIL", "RAIN", "RAKE", "RANK", "RANT", "RARE", "RASH", "RATE",
+"RAVE", "RAYS", "READ", "REAL", "REAM", "REAR", "RECK", "REED",
+"REEF", "REEK", "REEL", "REID", "REIN", "RENA", "REND", "RENT",
+"REST", "RICE", "RICH", "RICK", "RIDE", "RIFT", "RILL", "RIME",
+"RING", "RINK", "RISE", "RISK", "RITE", "ROAD", "ROAM", "ROAR",
+"ROBE", "ROCK", "RODE", "ROIL", "ROLL", "ROME", "ROOD", "ROOF",
+"ROOK", "ROOM", "ROOT", "ROSA", "ROSE", "ROSS", "ROSY", "ROTH",
+"ROUT", "ROVE", "ROWE", "ROWS", "RUBE", "RUBY", "RUDE", "RUDY",
+"RUIN", "RULE", "RUNG", "RUNS", "RUNT", "RUSE", "RUSH", "RUSK",
+"RUSS", "RUST", "RUTH", "SACK", "SAFE", "SAGE", "SAID", "SAIL",
+"SALE", "SALK", "SALT", "SAME", "SAND", "SANE", "SANG", "SANK",
+"SARA", "SAUL", "SAVE", "SAYS", "SCAN", "SCAR", "SCAT", "SCOT",
+"SEAL", "SEAM", "SEAR", "SEAT", "SEED", "SEEK", "SEEM", "SEEN",
+"SEES", "SELF", "SELL", "SEND", "SENT", "SETS", "SEWN", "SHAG",
+"SHAM", "SHAW", "SHAY", "SHED", "SHIM", "SHIN", "SHOD", "SHOE",
+"SHOT", "SHOW", "SHUN", "SHUT", "SICK", "SIDE", "SIFT", "SIGH",
+"SIGN", "SILK", "SILL", "SILO", "SILT", "SINE", "SING", "SINK",
+"SIRE", "SITE", "SITS", "SITU", "SKAT", "SKEW", "SKID", "SKIM",
+"SKIN", "SKIT", "SLAB", "SLAM", "SLAT", "SLAY", "SLED", "SLEW",
+"SLID", "SLIM", "SLIT", "SLOB", "SLOG", "SLOT", "SLOW", "SLUG",
+"SLUM", "SLUR", "SMOG", "SMUG", "SNAG", "SNOB", "SNOW", "SNUB",
+"SNUG", "SOAK", "SOAR", "SOCK", "SODA", "SOFA", "SOFT", "SOIL",
+"SOLD", "SOME", "SONG", "SOON", "SOOT", "SORE", "SORT", "SOUL",
+"SOUR", "SOWN", "STAB", "STAG", "STAN", "STAR", "STAY", "STEM",
+"STEW", "STIR", "STOW", "STUB", "STUN", "SUCH", "SUDS", "SUIT",
+"SULK", "SUMS", "SUNG", "SUNK", "SURE", "SURF", "SWAB", "SWAG",
+"SWAM", "SWAN", "SWAT", "SWAY", "SWIM", "SWUM", "TACK", "TACT",
+"TAIL", "TAKE", "TALE", "TALK", "TALL", "TANK", "TASK", "TATE",
+"TAUT", "TEAL", "TEAM", "TEAR", "TECH", "TEEM", "TEEN", "TEET",
+"TELL", "TEND", "TENT", "TERM", "TERN", "TESS", "TEST", "THAN",
+"THAT", "THEE", "THEM", "THEN", "THEY", "THIN", "THIS", "THUD",
+"THUG", "TICK", "TIDE", "TIDY", "TIED", "TIER", "TILE", "TILL",
+"TILT", "TIME", "TINA", "TINE", "TINT", "TINY", "TIRE", "TOAD",
+"TOGO", "TOIL", "TOLD", "TOLL", "TONE", "TONG", "TONY", "TOOK",
+"TOOL", "TOOT", "TORE", "TORN", "TOTE", "TOUR", "TOUT", "TOWN",
+"TRAG", "TRAM", "TRAY", "TREE", "TREK", "TRIG", "TRIM", "TRIO",
+"TROD", "TROT", "TROY", "TRUE", "TUBA", "TUBE", "TUCK", "TUFT",
+"TUNA", "TUNE", "TUNG", "TURF", "TURN", "TUSK", "TWIG", "TWIN",
+"TWIT", "ULAN", "UNIT", "URGE", "USED", "USER", "USES", "UTAH",
+"VAIL", "VAIN", "VALE", "VARY", "VASE", "VAST", "VEAL", "VEDA",
+"VEIL", "VEIN", "VEND", "VENT", "VERB", "VERY", "VETO", "VICE",
+"VIEW", "VINE", "VISE", "VOID", "VOLT", "VOTE", "WACK", "WADE",
+"WAGE", "WAIL", "WAIT", "WAKE", "WALE", "WALK", "WALL", "WALT",
+"WAND", "WANE", "WANG", "WANT", "WARD", "WARM", "WARN", "WART",
+"WASH", "WAST", "WATS", "WATT", "WAVE", "WAVY", "WAYS", "WEAK",
+"WEAL", "WEAN", "WEAR", "WEED", "WEEK", "WEIR", "WELD", "WELL",
+"WELT", "WENT", "WERE", "WERT", "WEST", "WHAM", "WHAT", "WHEE",
+"WHEN", "WHET", "WHOA", "WHOM", "WICK", "WIFE", "WILD", "WILL",
+"WIND", "WINE", "WING", "WINK", "WINO", "WIRE", "WISE", "WISH",
+"WITH", "WOLF", "WONT", "WOOD", "WOOL", "WORD", "WORE", "WORK",
+"WORM", "WORN", "WOVE", "WRIT", "WYNN", "YALE", "YANG", "YANK",
+"YARD", "YARN", "YAWL", "YAWN", "YEAH", "YEAR", "YELL", "YOGA",
+"YOKE" };
+
+#endif /* _OTP_H_ */
diff --git a/contrib/libs/sasl/plugins/plain.c b/contrib/libs/sasl/plugins/plain.c
new file mode 100644
index 0000000000..eb48687032
--- /dev/null
+++ b/contrib/libs/sasl/plugins/plain.c
@@ -0,0 +1,489 @@
+/* Plain SASL plugin
+ * Rob Siemborski
+ * Tim Martin
+ */
+/*
+ * Copyright (c) 1998-2016 Carnegie Mellon University. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For permission or any other legal
+ * details, please contact
+ * Carnegie Mellon University
+ * Center for Technology Transfer and Enterprise Creation
+ * 4615 Forbes Avenue
+ * Suite 302
+ * Pittsburgh, PA 15213
+ * (412) 268-7393, fax: (412) 268-7395
+ * innovation@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Computing Services
+ * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+#include <sasl.h>
+#include <saslplug.h>
+
+#include "plugin_common.h"
+
+#ifdef macintosh
+#error #include <sasl_plain_plugin_decl.h>
+#endif
+
+/***************************** Common Section *****************************/
+
+/***************************** Server Section *****************************/
+
+static int plain_server_mech_new(void *glob_context __attribute__((unused)),
+ sasl_server_params_t *sparams,
+ const char *challenge __attribute__((unused)),
+ unsigned challen __attribute__((unused)),
+ void **conn_context)
+{
+ /* holds state are in */
+ if (!conn_context) {
+ PARAMERROR( sparams->utils );
+ return SASL_BADPARAM;
+ }
+
+ *conn_context = NULL;
+
+ return SASL_OK;
+}
+
+static int plain_server_mech_step(void *conn_context __attribute__((unused)),
+ sasl_server_params_t *params,
+ const char *clientin,
+ unsigned clientinlen,
+ const char **serverout,
+ unsigned *serveroutlen,
+ sasl_out_params_t *oparams)
+{
+ const char *author;
+ const char *authen;
+ const char *password;
+ unsigned password_len;
+ unsigned lup = 0;
+ int result;
+ char *passcopy;
+ unsigned canon_flags = 0;
+
+ *serverout = NULL;
+ *serveroutlen = 0;
+
+ /* should have received author-id NUL authen-id NUL password */
+
+ /* get author */
+ author = clientin;
+ while ((lup < clientinlen) && (clientin[lup] != 0)) ++lup;
+
+ if (lup >= clientinlen) {
+ SETERROR(params->utils, "Can only find author (no password)");
+ return SASL_BADPROT;
+ }
+
+ /* get authen */
+ ++lup;
+ authen = clientin + lup;
+ while ((lup < clientinlen) && (clientin[lup] != 0)) ++lup;
+
+ if (lup >= clientinlen) {
+ params->utils->seterror(params->utils->conn, 0,
+ "Can only find author/en (no password)");
+ return SASL_BADPROT;
+ }
+
+ /* get password */
+ lup++;
+ password = clientin + lup;
+ while ((lup < clientinlen) && (clientin[lup] != 0)) ++lup;
+
+ password_len = (unsigned) (clientin + lup - password);
+
+ if (lup != clientinlen) {
+ SETERROR(params->utils,
+ "Got more data than we were expecting in the PLAIN plugin\n");
+ return SASL_BADPROT;
+ }
+
+ /* this kinda sucks. we need password to be null terminated
+ but we can't assume there is an allocated byte at the end
+ of password so we have to copy it */
+ passcopy = params->utils->malloc(password_len + 1);
+ if (passcopy == NULL) {
+ MEMERROR(params->utils);
+ return SASL_NOMEM;
+ }
+
+ strncpy(passcopy, password, password_len);
+ passcopy[password_len] = '\0';
+
+ /* Canonicalize userid first, so that password verification is only
+ * against the canonical id */
+ if (!author || !*author) {
+ author = authen;
+ canon_flags = SASL_CU_AUTHZID;
+ } else if (strcmp(author, authen) == 0) {
+ /* While this isn't going to find out that <user> and <user>@<defaultdomain>
+ are the same thing, this is good enough for many cases */
+ canon_flags = SASL_CU_AUTHZID;
+ }
+
+ result = params->canon_user(params->utils->conn,
+ authen,
+ 0,
+ SASL_CU_AUTHID | canon_flags | SASL_CU_EXTERNALLY_VERIFIED,
+ oparams);
+ if (result != SASL_OK) {
+ _plug_free_string(params->utils, &passcopy);
+ return result;
+ }
+
+ /* verify password (and possibly fetch both authentication and
+ authorization identity related properties) - return SASL_OK
+ on success */
+ result = params->utils->checkpass(params->utils->conn,
+ oparams->authid,
+ oparams->alen,
+ passcopy,
+ password_len);
+
+ _plug_free_string(params->utils, &passcopy);
+
+ if (result != SASL_OK) {
+ params->utils->seterror(params->utils->conn, 0,
+ "Password verification failed");
+ return result;
+ }
+
+ /* Canonicalize and store the authorization ID */
+ /* We need to do this after calling verify_user just in case verify_user
+ * needed to get auxprops itself */
+ if (canon_flags == 0) {
+ const struct propval *pr;
+ int i;
+
+ pr = params->utils->prop_get(params->propctx);
+ if (!pr) {
+ return SASL_FAIL;
+ }
+
+ /* params->utils->checkpass() might have fetched authorization identity related properties
+ for the wrong user name. Free these values. */
+ for (i = 0; pr[i].name; i++) {
+ if (pr[i].name[0] == '*') {
+ continue;
+ }
+
+ if (pr[i].values) {
+ params->utils->prop_erase(params->propctx, pr[i].name);
+ }
+ }
+
+ result = params->canon_user(params->utils->conn,
+ author,
+ 0,
+ SASL_CU_AUTHZID,
+ oparams);
+ if (result != SASL_OK) {
+ return result;
+ }
+ }
+
+ /* set oparams */
+ oparams->doneflag = 1;
+ oparams->mech_ssf = 0;
+ oparams->maxoutbuf = 0;
+ oparams->encode_context = NULL;
+ oparams->encode = NULL;
+ oparams->decode_context = NULL;
+ oparams->decode = NULL;
+ oparams->param_version = 0;
+
+ return SASL_OK;
+}
+
+static sasl_server_plug_t plain_server_plugins[] =
+{
+ {
+ "PLAIN", /* mech_name */
+ 0, /* max_ssf */
+ SASL_SEC_NOANONYMOUS
+ | SASL_SEC_PASS_CREDENTIALS, /* security_flags */
+ SASL_FEAT_WANT_CLIENT_FIRST
+ | SASL_FEAT_ALLOWS_PROXY, /* features */
+ NULL, /* glob_context */
+ &plain_server_mech_new, /* mech_new */
+ &plain_server_mech_step, /* mech_step */
+ NULL, /* mech_dispose */
+ NULL, /* mech_free */
+ NULL, /* setpass */
+ NULL, /* user_query */
+ NULL, /* idle */
+ NULL, /* mech_avail */
+ NULL /* spare */
+ }
+};
+
+int plain_server_plug_init(const sasl_utils_t *utils,
+ int maxversion,
+ int *out_version,
+ sasl_server_plug_t **pluglist,
+ int *plugcount)
+{
+ if (maxversion < SASL_SERVER_PLUG_VERSION) {
+ SETERROR(utils, "PLAIN version mismatch");
+ return SASL_BADVERS;
+ }
+
+ *out_version = SASL_SERVER_PLUG_VERSION;
+ *pluglist = plain_server_plugins;
+ *plugcount = 1;
+
+ return SASL_OK;
+}
+
+/***************************** Client Section *****************************/
+
+typedef struct client_context {
+ char *out_buf;
+ unsigned out_buf_len;
+} client_context_t;
+
+static int plain_client_mech_new(void *glob_context __attribute__((unused)),
+ sasl_client_params_t *params,
+ void **conn_context)
+{
+ client_context_t *text;
+
+ /* holds state are in */
+ text = params->utils->malloc(sizeof(client_context_t));
+ if (text == NULL) {
+ MEMERROR( params->utils );
+ return SASL_NOMEM;
+ }
+
+ memset(text, 0, sizeof(client_context_t));
+
+ *conn_context = text;
+
+ return SASL_OK;
+}
+
+static int plain_client_mech_step(void *conn_context,
+ sasl_client_params_t *params,
+ const char *serverin __attribute__((unused)),
+ unsigned serverinlen __attribute__((unused)),
+ sasl_interact_t **prompt_need,
+ const char **clientout,
+ unsigned *clientoutlen,
+ sasl_out_params_t *oparams)
+{
+ client_context_t *text = (client_context_t *) conn_context;
+ const char *user = NULL, *authid = NULL;
+ sasl_secret_t *password = NULL;
+ unsigned int free_password = 0; /* set if we need to free password */
+ int user_result = SASL_OK;
+ int auth_result = SASL_OK;
+ int pass_result = SASL_OK;
+ int result;
+ char *p;
+
+ *clientout = NULL;
+ *clientoutlen = 0;
+
+ /* doesn't really matter how the server responds */
+
+ /* check if sec layer strong enough */
+ if (params->props.min_ssf > params->external_ssf) {
+ SETERROR( params->utils, "SSF requested of PLAIN plugin");
+ return SASL_TOOWEAK;
+ }
+
+ /* try to get the authid */
+ if (oparams->authid == NULL) {
+ auth_result = _plug_get_authid(params->utils, &authid, prompt_need);
+
+ if ((auth_result != SASL_OK) && (auth_result != SASL_INTERACT))
+ return auth_result;
+ }
+
+ /* try to get the userid */
+ if (oparams->user == NULL) {
+ user_result = _plug_get_userid(params->utils, &user, prompt_need);
+
+ if ((user_result != SASL_OK) && (user_result != SASL_INTERACT))
+ return user_result;
+ }
+
+ /* try to get the password */
+ if (password == NULL) {
+ pass_result = _plug_get_password(params->utils, &password,
+ &free_password, prompt_need);
+
+ if ((pass_result != SASL_OK) && (pass_result != SASL_INTERACT))
+ return pass_result;
+ }
+
+ /* free prompts we got */
+ if (prompt_need && *prompt_need) {
+ params->utils->free(*prompt_need);
+ *prompt_need = NULL;
+ }
+
+ /* if there are prompts not filled in */
+ if ((user_result == SASL_INTERACT) || (auth_result == SASL_INTERACT) ||
+ (pass_result == SASL_INTERACT)) {
+ /* make the prompt list */
+ result =
+ _plug_make_prompts(params->utils, prompt_need,
+ user_result == SASL_INTERACT ?
+ "Please enter your authorization name" : NULL,
+ NULL,
+ auth_result == SASL_INTERACT ?
+ "Please enter your authentication name" : NULL,
+ NULL,
+ pass_result == SASL_INTERACT ?
+ "Please enter your password" : NULL, NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL);
+ if (result != SASL_OK) goto cleanup;
+
+ return SASL_INTERACT;
+ }
+
+ if (!password) {
+ PARAMERROR(params->utils);
+ return SASL_BADPARAM;
+ }
+
+ if (!user || !*user) {
+ result = params->canon_user(params->utils->conn, authid, 0,
+ SASL_CU_AUTHID | SASL_CU_AUTHZID, oparams);
+ }
+ else {
+ result = params->canon_user(params->utils->conn, user, 0,
+ SASL_CU_AUTHZID, oparams);
+ if (result != SASL_OK) goto cleanup;
+
+ result = params->canon_user(params->utils->conn, authid, 0,
+ SASL_CU_AUTHID, oparams);
+ }
+ if (result != SASL_OK) goto cleanup;
+
+ /* send authorized id NUL authentication id NUL password */
+ *clientoutlen = ((user && *user ? oparams->ulen : 0) +
+ 1 + oparams->alen +
+ 1 + password->len);
+
+ /* remember the extra NUL on the end for stupid clients */
+ result = _plug_buf_alloc(params->utils, &(text->out_buf),
+ &(text->out_buf_len), *clientoutlen + 1);
+ if (result != SASL_OK) goto cleanup;
+
+ memset(text->out_buf, 0, *clientoutlen + 1);
+ p = text->out_buf;
+ if (user && *user) {
+ memcpy(p, oparams->user, oparams->ulen);
+ p += oparams->ulen;
+ }
+ memcpy(++p, oparams->authid, oparams->alen);
+ p += oparams->alen;
+ memcpy(++p, password->data, password->len);
+
+ *clientout = text->out_buf;
+
+ /* set oparams */
+ oparams->doneflag = 1;
+ oparams->mech_ssf = 0;
+ oparams->maxoutbuf = 0;
+ oparams->encode_context = NULL;
+ oparams->encode = NULL;
+ oparams->decode_context = NULL;
+ oparams->decode = NULL;
+ oparams->param_version = 0;
+
+ result = SASL_OK;
+
+ cleanup:
+ /* free sensitive info */
+ if (free_password) _plug_free_secret(params->utils, &password);
+
+ return result;
+}
+
+static void plain_client_mech_dispose(void *conn_context,
+ const sasl_utils_t *utils)
+{
+ client_context_t *text = (client_context_t *) conn_context;
+
+ if (!text) return;
+
+ if (text->out_buf) utils->free(text->out_buf);
+
+ utils->free(text);
+}
+
+static sasl_client_plug_t plain_client_plugins[] =
+{
+ {
+ "PLAIN", /* mech_name */
+ 0, /* max_ssf */
+ SASL_SEC_NOANONYMOUS
+ | SASL_SEC_PASS_CREDENTIALS, /* security_flags */
+ SASL_FEAT_WANT_CLIENT_FIRST
+ | SASL_FEAT_ALLOWS_PROXY, /* features */
+ NULL, /* required_prompts */
+ NULL, /* glob_context */
+ &plain_client_mech_new, /* mech_new */
+ &plain_client_mech_step, /* mech_step */
+ &plain_client_mech_dispose, /* mech_dispose */
+ NULL, /* mech_free */
+ NULL, /* idle */
+ NULL, /* spare */
+ NULL /* spare */
+ }
+};
+
+int plain_client_plug_init(sasl_utils_t *utils,
+ int maxversion,
+ int *out_version,
+ sasl_client_plug_t **pluglist,
+ int *plugcount)
+{
+ if (maxversion < SASL_CLIENT_PLUG_VERSION) {
+ SETERROR(utils, "PLAIN version mismatch");
+ return SASL_BADVERS;
+ }
+
+ *out_version = SASL_CLIENT_PLUG_VERSION;
+ *pluglist = plain_client_plugins;
+ *plugcount = 1;
+
+ return SASL_OK;
+}
diff --git a/contrib/libs/sasl/plugins/sasldb.c b/contrib/libs/sasl/plugins/sasldb.c
new file mode 100644
index 0000000000..f4e5412b17
--- /dev/null
+++ b/contrib/libs/sasl/plugins/sasldb.c
@@ -0,0 +1,317 @@
+/* SASL server API implementation
+ * Rob Siemborski
+ * Tim Martin
+ */
+/*
+ * Copyright (c) 1998-2016 Carnegie Mellon University. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For permission or any other legal
+ * details, please contact
+ * Carnegie Mellon University
+ * Center for Technology Transfer and Enterprise Creation
+ * 4615 Forbes Avenue
+ * Suite 302
+ * Pittsburgh, PA 15213
+ * (412) 268-7393, fax: (412) 268-7395
+ * innovation@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Computing Services
+ * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+/* sasldb stuff */
+
+#include <stdio.h>
+
+#include "sasl.h"
+#include "saslutil.h"
+#include "saslplug.h"
+#include "../sasldb/sasldb.h"
+
+#include "plugin_common.h"
+
+static int sasldb_auxprop_lookup(void *glob_context __attribute__((unused)),
+ sasl_server_params_t *sparams,
+ unsigned flags,
+ const char *user,
+ unsigned ulen)
+{
+ char *userid = NULL;
+ char *realm = NULL;
+ const char *user_realm = NULL;
+ int ret;
+ const struct propval *to_fetch, *cur;
+ char value[8192];
+ size_t value_len;
+ char *user_buf;
+ int verify_against_hashed_password;
+ int saw_user_password = 0;
+
+ if (!sparams || !user) return SASL_BADPARAM;
+
+ user_buf = sparams->utils->malloc(ulen + 1);
+ if(!user_buf) {
+ ret = SASL_NOMEM;
+ goto done;
+ }
+
+ memcpy(user_buf, user, ulen);
+ user_buf[ulen] = '\0';
+
+ if(sparams->user_realm) {
+ user_realm = sparams->user_realm;
+ } else {
+ user_realm = sparams->serverFQDN;
+ }
+
+ ret = _plug_parseuser(sparams->utils, &userid, &realm, user_realm,
+ sparams->serverFQDN, user_buf);
+ if(ret != SASL_OK) goto done;
+
+ to_fetch = sparams->utils->prop_get(sparams->propctx);
+ if (!to_fetch) {
+ ret = SASL_NOMEM;
+ goto done;
+ }
+
+ verify_against_hashed_password = flags & SASL_AUXPROP_VERIFY_AGAINST_HASH;
+
+ /* Use a fake value to signal that we have no property to lookup */
+ ret = SASL_CONTINUE;
+ for(cur = to_fetch; cur->name; cur++) {
+ int cur_ret;
+ const char *realname = cur->name;
+
+ /* Only look up properties that apply to this lookup! */
+ if(cur->name[0] == '*' && (flags & SASL_AUXPROP_AUTHZID)) continue;
+ if(!(flags & SASL_AUXPROP_AUTHZID)) {
+ if(cur->name[0] != '*') continue;
+ else realname = cur->name + 1;
+ }
+
+ /* If it's there already, we want to see if it needs to be
+ * overridden. userPassword is a special case, because it's value
+ is always present if SASL_AUXPROP_VERIFY_AGAINST_HASH is specified.
+ When SASL_AUXPROP_VERIFY_AGAINST_HASH is set, we just clear userPassword. */
+ if (cur->values && !(flags & SASL_AUXPROP_OVERRIDE) &&
+ (verify_against_hashed_password == 0 ||
+ strcasecmp(realname, SASL_AUX_PASSWORD_PROP) != 0)) {
+ continue;
+ } else if (cur->values) {
+ sparams->utils->prop_erase(sparams->propctx, cur->name);
+ }
+
+ if (strcasecmp(realname, SASL_AUX_PASSWORD_PROP) == 0) {
+ saw_user_password = 1;
+ }
+
+ cur_ret = _sasldb_getdata(sparams->utils,
+ sparams->utils->conn, userid, realm,
+ realname, value, sizeof(value), &value_len);
+
+ /* Assumption: cur_ret is never SASL_CONTINUE */
+
+ /* If this is the first property we've tried to fetch ==>
+ always set the global error code.
+ If we had SASL_NOUSER ==> any other error code overrides it
+ (including SASL_NOUSER). */
+ if (ret == SASL_CONTINUE || ret == SASL_NOUSER) {
+ ret = cur_ret;
+ } else if (ret == SASL_OK) {
+ /* Any error code other than SASL_NOUSER overrides SASL_OK.
+ (And SASL_OK overrides SASL_OK as well) */
+ if (cur_ret != SASL_NOUSER) {
+ ret = cur_ret;
+ }
+ }
+ /* Any other global error code is left as is */
+
+ if (cur_ret != SASL_OK) {
+ if (cur_ret != SASL_NOUSER) {
+ /* No point in continuing if we hit any serious error */
+ break;
+ }
+ /* We didn't find it, leave it as not found */
+ continue;
+ }
+
+ sparams->utils->prop_set(sparams->propctx, cur->name,
+ value, (unsigned) value_len);
+ }
+
+ /* [Keep in sync with LDAPDB, SQL]
+ If ret is SASL_CONTINUE, it means that no properties were requested
+ (or maybe some were requested, but they already have values and
+ SASL_AUXPROP_OVERRIDE flag is not set).
+ Always return SASL_OK in this case. */
+ if (ret == SASL_CONTINUE) {
+ ret = SASL_OK;
+ }
+
+ if (flags & SASL_AUXPROP_AUTHZID) {
+ /* This is a lie, but the caller can't handle
+ when we return SASL_NOUSER for authorization identity lookup. */
+ if (ret == SASL_NOUSER) {
+ ret = SASL_OK;
+ }
+ } else {
+ if (ret == SASL_NOUSER && saw_user_password == 0) {
+ /* Verify user existence by checking presence of
+ the userPassword attribute */
+ ret = _sasldb_getdata(sparams->utils,
+ sparams->utils->conn,
+ userid,
+ realm,
+ SASL_AUX_PASSWORD_PROP,
+ value,
+ sizeof(value),
+ &value_len);
+ }
+ }
+
+ done:
+ if (userid) sparams->utils->free(userid);
+ if (realm) sparams->utils->free(realm);
+ if (user_buf) sparams->utils->free(user_buf);
+
+ return ret;
+}
+
+static int sasldb_auxprop_store(void *glob_context __attribute__((unused)),
+ sasl_server_params_t *sparams,
+ struct propctx *ctx,
+ const char *user,
+ unsigned ulen)
+{
+ char *userid = NULL;
+ char *realm = NULL;
+ const char *user_realm = NULL;
+ int ret = SASL_FAIL;
+ const struct propval *to_store, *cur;
+ char *user_buf;
+
+ /* just checking if we are enabled */
+ if(!ctx) return SASL_OK;
+
+ if(!sparams || !user) return SASL_BADPARAM;
+
+ user_buf = sparams->utils->malloc(ulen + 1);
+ if(!user_buf) {
+ ret = SASL_NOMEM;
+ goto done;
+ }
+
+ memcpy(user_buf, user, ulen);
+ user_buf[ulen] = '\0';
+
+ if(sparams->user_realm) {
+ user_realm = sparams->user_realm;
+ } else {
+ user_realm = sparams->serverFQDN;
+ }
+
+ ret = _plug_parseuser(sparams->utils, &userid, &realm, user_realm,
+ sparams->serverFQDN, user_buf);
+ if(ret != SASL_OK) goto done;
+
+ to_store = sparams->utils->prop_get(ctx);
+ if(!to_store) {
+ ret = SASL_BADPARAM;
+ goto done;
+ }
+
+ ret = SASL_OK;
+ for (cur = to_store; cur->name; cur++) {
+ const char *value = (cur->values && cur->values[0]) ? cur->values[0] : NULL;
+
+ if (cur->name[0] == '*') {
+ continue;
+ }
+
+ /* WARN: We only support one value right now. */
+ ret = _sasldb_putdata(sparams->utils,
+ sparams->utils->conn,
+ userid,
+ realm,
+ cur->name,
+ value,
+ value ? strlen(value) : 0);
+
+ if (value == NULL && ret == SASL_NOUSER) {
+ /* Deleting something which is not there is not an error */
+ ret = SASL_OK;
+ }
+
+ if (ret != SASL_OK) {
+ /* We've already failed, no point in continuing */
+ break;
+ }
+ }
+
+ done:
+ if (userid) sparams->utils->free(userid);
+ if (realm) sparams->utils->free(realm);
+ if (user_buf) sparams->utils->free(user_buf);
+
+ return ret;
+}
+
+static sasl_auxprop_plug_t sasldb_auxprop_plugin = {
+ 0, /* Features */
+ 0, /* spare */
+ NULL, /* glob_context */
+ sasldb_auxprop_free, /* auxprop_free */
+ sasldb_auxprop_lookup, /* auxprop_lookup */
+ "sasldb", /* name */
+ sasldb_auxprop_store /* auxprop_store */
+};
+
+int sasldb_auxprop_plug_init(const sasl_utils_t *utils,
+ int max_version,
+ int *out_version,
+ sasl_auxprop_plug_t **plug,
+ const char *plugname __attribute__((unused)))
+{
+ if(!out_version || !plug) return SASL_BADPARAM;
+
+ /* Do we have database support? */
+ /* Note that we can use a NULL sasl_conn_t because our
+ * sasl_utils_t is "blessed" with the global callbacks */
+ if(_sasl_check_db(utils, NULL) != SASL_OK)
+ return SASL_NOMECH;
+
+ /* Check if libsasl API is older than ours. If it is, fail */
+ if(max_version < SASL_AUXPROP_PLUG_VERSION) return SASL_BADVERS;
+
+ *out_version = SASL_AUXPROP_PLUG_VERSION;
+
+ *plug = &sasldb_auxprop_plugin;
+
+ return SASL_OK;
+}
diff --git a/contrib/libs/sasl/plugins/scram.c b/contrib/libs/sasl/plugins/scram.c
new file mode 100644
index 0000000000..36f61086b8
--- /dev/null
+++ b/contrib/libs/sasl/plugins/scram.c
@@ -0,0 +1,3087 @@
+/* SCRAM-SHA-1/SHA-2 SASL plugin
+ * Alexey Melnikov
+ */
+/*
+ * Copyright (c) 2009-2016 Carnegie Mellon University. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For permission or any other legal
+ * details, please contact
+ * Carnegie Mellon University
+ * Center for Technology Transfer and Enterprise Creation
+ * 4615 Forbes Avenue
+ * Suite 302
+ * Pittsburgh, PA 15213
+ * (412) 268-7393, fax: (412) 268-7395
+ * innovation@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Computing Services
+ * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#ifndef macintosh
+#include <sys/stat.h>
+#endif
+#include <fcntl.h>
+#include <errno.h>
+
+#include <sasl.h>
+#include <saslplug.h>
+#include <saslutil.h>
+
+#include "plugin_common.h"
+
+#ifdef macintosh
+#error #include <sasl_scram_plugin_decl.h>
+#endif
+
+#include <openssl/sha.h>
+#include <openssl/evp.h>
+#include <openssl/hmac.h>
+
+/***************************** Common Section *****************************/
+
+#define NONCE_SIZE (32) /* arbitrary */
+#define SALT_SIZE (16) /* arbitrary */
+
+/* TODO: make this a configurable option? */
+#define DEFAULT_ITERATION_COUNTER 4096
+#define MIN_ITERATION_COUNTER 4096
+
+#define MAX_ITERATION_COUNTER 0x10000
+
+/* maximum length of the iteration_counter (as a string). Assume it is 32bits */
+#define ITERATION_COUNTER_BUF_LEN 20
+
+#define BASE64_LEN(size) (((size) / 3 * 4) + (((size) % 3) ? 4 : 0))
+
+#define MAX_CLIENTIN_LEN 2048
+#define MAX_SERVERIN_LEN 2048
+
+#define STRINGIZE(x) #x
+#define MAX_CLIENTIN_LEN_STR STRINGIZE((MAX_CLIENTIN_LEN))
+#define MAX_SERVERIN_LEN_STR STRINGIZE((MAX_SERVERIN_LEN))
+
+#define CLIENT_KEY_CONSTANT "Client Key"
+#define SERVER_KEY_CONSTANT "Server Key"
+#define CLIENT_KEY_CONSTANT_LEN sizeof(CLIENT_KEY_CONSTANT)-1
+#define SERVER_KEY_CONSTANT_LEN sizeof(SERVER_KEY_CONSTANT)-1
+
+#define SCRAM_CB_FLAG_MASK 0x0F
+#define SCRAM_CB_FLAG_N 0x00
+#define SCRAM_CB_FLAG_P 0x01
+#define SCRAM_CB_FLAG_Y 0x02
+
+#ifdef SCRAM_DEBUG
+#define PRINT_HASH(func,hash,size) print_hash(func,hash,size)
+#else
+#define PRINT_HASH(func,hash,size)
+#endif
+
+/* NB: A temporary mapping for "internal errors". It would be better to add
+ a new SASL error code for that */
+#define SASL_SCRAM_INTERNAL SASL_NOMEM
+
+
+/* Holds the core salt to avoid regenerating salt each auth. */
+static unsigned char g_salt_key[SALT_SIZE];
+
+/* Note that currently only SHA-* variants are supported! */
+static const char *
+scram_sasl_mech_name(size_t hash_size)
+{
+ switch (hash_size) {
+ case 64:
+ return "SCRAM-SHA-512";
+
+ case 48:
+ return "SCRAM-SHA-384";
+
+ case 32:
+ return "SCRAM-SHA-256";
+
+ case 28:
+ return "SCRAM-SHA-224";
+
+ case 20:
+ return "SCRAM-SHA-1";
+ }
+
+ return NULL;
+}
+
+/* Convert saslname = 1*(value-safe-char / "=2C" / "=3D") in place.
+ Returns SASL_FAIL if the encoding is invalid, otherwise SASL_OK */
+static int
+decode_saslname (char *buf)
+{
+ char * inp;
+ char * outp;
+
+ inp = outp = buf;
+
+ while (*inp) {
+ if (*inp == '=') {
+ inp++;
+ if (*inp == '\0') {
+ return SASL_FAIL;
+ }
+ if (inp[0] == '2' && inp[1] == 'C') {
+ *outp = ',';
+ inp += 2;
+ } else if (inp[0] == '3' && inp[1] == 'D') {
+ *outp = '=';
+ inp += 2;
+ } else {
+ return SASL_FAIL;
+ }
+ } else {
+ *outp = *inp;
+ inp++;
+ }
+ outp++;
+ }
+
+ *outp = '\0';
+
+ return SASL_OK;
+}
+
+/* Convert a username to saslname = 1*(value-safe-char / "=2C" / "=3D")
+ and return an allocated copy.
+ "freeme" contains pointer to the allocated output, or NULL,
+ if encoded_saslname just points to saslname.
+ Returns SASL_NOMEM if can't allocate memory for the output, otherwise SASL_OK */
+static int
+encode_saslname (const char *saslname,
+ const char **encoded_saslname,
+ char **freeme)
+{
+ const char * inp;
+ char * outp;
+ int special_chars = 0;
+
+ /* Found out if anything needs encoding */
+ for (inp = saslname; *inp; inp++) {
+ if (*inp == ',' || *inp == '=') {
+ special_chars++;
+ }
+ }
+
+ if (special_chars == 0) {
+ *encoded_saslname = saslname;
+ *freeme = NULL;
+ return SASL_OK;
+ }
+
+ outp = malloc(strlen(saslname) + special_chars * 2 + 1);
+ *encoded_saslname = outp;
+ *freeme = outp;
+ if (outp == NULL) {
+ return SASL_NOMEM;
+ }
+
+ for (inp = saslname; *inp; inp++) {
+ switch (*inp) {
+ case ',':
+ *outp++ = '=';
+ *outp++ = '2';
+ *outp++ = 'C';
+ break;
+
+ case '=':
+ *outp++ = '=';
+ *outp++ = '3';
+ *outp++ = 'D';
+ break;
+
+ default:
+ *outp++ = *inp;
+ }
+ }
+
+ *outp = '\0';
+
+ return SASL_OK;
+}
+
+static char *
+create_nonce(const sasl_utils_t * utils,
+ char *buffer,
+ size_t buflen) /* Including the terminating NUL */
+{
+ char *intbuf;
+ unsigned int estimated;
+
+ if ((buflen - 1) % 4 != 0) {
+ /* NB: the algorithm below doesn't work for such length.
+ It needs to be adjusted to allocate + 4 bytes,
+ encode the last 4 bytes to a separate buffer and
+ then copy the necessary number of bytes to the end of the output */
+ return NULL;
+ }
+
+ estimated = (unsigned int)((buflen - 1) / 4 * 3);
+ intbuf = (char *) utils->malloc(estimated + 1);
+ if (intbuf == NULL) {
+ return NULL;
+ }
+
+ utils->rand(utils->rpool, intbuf, estimated);
+
+ /* base 64 encode it so it has valid chars */
+ if (utils->encode64(intbuf,
+ estimated,
+ buffer,
+ (unsigned int)buflen,
+ NULL) != SASL_OK) {
+ utils->free(intbuf);
+ return NULL;
+ }
+
+ utils->free(intbuf);
+
+ buffer[buflen-1] = '\0';
+
+ return buffer;
+}
+
+#ifdef SCRAM_DEBUG
+/* Useful for debugging interop issues */
+static void
+print_hash (const char * func, const char * hash, size_t hash_size)
+{
+ int i;
+
+ printf (" HASH in %s:", func);
+ for (i = 0; i < hash_size; i++) {
+ printf (" %.2X", (unsigned char)hash[i]);
+ }
+ printf ("\n");
+}
+#endif
+
+
+/* The result variable need to point to a buffer big enough for the [SHA-*] hash */
+static void
+Hi (const sasl_utils_t * utils,
+ const EVP_MD *md,
+ const char * str,
+ size_t str_len,
+ const char * salt,
+ size_t salt_len,
+ unsigned int iteration_count,
+ char * result)
+{
+ char * initial_key = NULL;
+ unsigned int i;
+ char * temp_result;
+ unsigned int hash_len = 0;
+ size_t k, hash_size = EVP_MD_size(md);
+
+ initial_key = utils->malloc(salt_len + 4);
+ memcpy (initial_key, salt, salt_len);
+ initial_key[salt_len] = 0;
+ initial_key[salt_len+1] = 0;
+ initial_key[salt_len+2] = 0;
+ initial_key[salt_len+3] = 1;
+
+ temp_result = utils->malloc(hash_size);
+
+ /* U1 := HMAC(str, salt || INT(1)) */
+
+ if (HMAC(md,
+ (const unsigned char *) str,
+ (int)str_len,
+ (const unsigned char *) initial_key,
+ (int)salt_len + 4,
+ (unsigned char *)result,
+ &hash_len) == NULL) {
+ }
+
+ memcpy(temp_result, result, hash_size);
+
+ PRINT_HASH ("first HMAC in Hi()", temp_result, hash_size);
+
+ /* On each loop iteration j "temp_result" contains Uj,
+ while "result" contains "U1 XOR ... XOR Uj" */
+ for (i = 2; i <= iteration_count; i++) {
+ if (HMAC(md,
+ (const unsigned char *) str,
+ (int)str_len,
+ (const unsigned char *) temp_result,
+ hash_size,
+ (unsigned char *)temp_result,
+ &hash_len) == NULL) {
+ }
+
+ PRINT_HASH ("Hi() HMAC inside loop", temp_result, hash_size);
+
+ for (k = 0; k < hash_size; k++) {
+ result[k] ^= temp_result[k];
+ }
+
+ PRINT_HASH ("Hi() - accumulated result inside loop", result, hash_size);
+ }
+
+ utils->free(initial_key);
+ utils->free(temp_result);
+}
+
+/**
+ * User salt is Hi(username,salt_key);
+ * This is fixed per reboot, to allow caching of SCRAM
+ * SaltedPassword.
+ */
+static unsigned char *
+scram_server_user_salt(const sasl_utils_t * utils,
+ const EVP_MD *md,
+ const char * username,
+ size_t * p_salt_len)
+{
+ size_t hash_size = EVP_MD_size(md);
+ char * result = utils->malloc(hash_size);
+ Hi(utils, md, username, strlen(username), (const char *) g_salt_key, SALT_SIZE,
+ 20 /* iterations */, result);
+ *p_salt_len = hash_size;
+ return (unsigned char *) result;
+}
+
+static int
+GenerateScramSecrets (const sasl_utils_t * utils,
+ const EVP_MD *md,
+ const char * password,
+ size_t password_len,
+ char * salt,
+ size_t salt_len,
+ unsigned int iteration_count,
+ char * StoredKey,
+ char * ServerKey,
+ char ** error_text)
+{
+ char SaltedPassword[EVP_MAX_MD_SIZE];
+ char ClientKey[EVP_MAX_MD_SIZE];
+ sasl_secret_t *sec = NULL;
+ unsigned int hash_len = 0;
+ int result;
+ size_t hash_size = EVP_MD_size(md);
+
+ *error_text = NULL;
+
+ if (password_len == 0) {
+ *error_text = "empty secret";
+ result = SASL_FAIL;
+ goto cleanup;
+ }
+
+ sec = utils->malloc(sizeof(sasl_secret_t) + password_len);
+ if (sec == NULL) {
+ result = SASL_NOMEM;
+ goto cleanup;
+ }
+
+ sec->len = (unsigned) password_len;
+ strncpy((char *)sec->data, password, password_len + 1);
+
+ /* SaltedPassword := Hi(password, salt) */
+ Hi (utils,
+ md,
+ (const char *) sec->data,
+ sec->len,
+ salt,
+ salt_len,
+ iteration_count,
+ SaltedPassword);
+
+ /* ClientKey := HMAC(SaltedPassword, "Client Key") */
+ if (HMAC(md,
+ (const unsigned char *) SaltedPassword,
+ hash_size,
+ (const unsigned char *) CLIENT_KEY_CONSTANT,
+ CLIENT_KEY_CONSTANT_LEN,
+ (unsigned char *)ClientKey,
+ &hash_len) == NULL) {
+ *error_text = "HMAC call failed";
+ result = SASL_SCRAM_INTERNAL;
+ goto cleanup;
+ }
+
+ /* StoredKey := H(ClientKey) */
+ if (EVP_Digest((const unsigned char *) ClientKey, hash_size,
+ (unsigned char *) StoredKey, NULL, md, NULL) == 0) {
+ *error_text = "Digest call failed";
+ result = SASL_SCRAM_INTERNAL;
+ goto cleanup;
+
+ }
+
+ /* ServerKey := HMAC(SaltedPassword, "Server Key") */
+ if (HMAC(md,
+ (const unsigned char *) SaltedPassword,
+ hash_size,
+ (const unsigned char *) SERVER_KEY_CONSTANT,
+ SERVER_KEY_CONSTANT_LEN,
+ (unsigned char *)ServerKey,
+ &hash_len) == NULL) {
+ *error_text = "HMAC call failed";
+ result = SASL_SCRAM_INTERNAL;
+ goto cleanup;
+ }
+
+ result = SASL_OK;
+
+cleanup:
+ if (sec) {
+ _plug_free_secret(utils, &sec);
+ }
+ return result;
+}
+
+/***************************** Server Section *****************************/
+
+typedef struct server_context {
+ int state;
+
+ const EVP_MD *md; /* underlying MDA */
+
+ char * authentication_id;
+ char * authorization_id;
+
+ char * out_buf;
+ unsigned out_buf_len;
+ char * auth_message;
+ size_t auth_message_len;
+ char * nonce;
+ /* in binary form */
+ char * salt;
+ size_t salt_len;
+ unsigned int iteration_count;
+ char StoredKey[EVP_MAX_MD_SIZE + 1];
+ char ServerKey[EVP_MAX_MD_SIZE + 1];
+
+ int cb_flags;
+ char *cbindingname;
+ char *gs2_header;
+ size_t gs2_header_length;
+} server_context_t;
+
+static int
+scram_server_mech_new(void *glob_context,
+ sasl_server_params_t *sparams,
+ const char *challenge __attribute__((unused)),
+ unsigned challen __attribute__((unused)),
+ void **conn_context)
+{
+ server_context_t *text;
+
+ /* holds state are in */
+ text = sparams->utils->malloc(sizeof(server_context_t));
+ if (text == NULL) {
+ MEMERROR( sparams->utils );
+ return SASL_NOMEM;
+ }
+
+ memset(text, 0, sizeof(server_context_t));
+ /* text->state = 0; */
+
+ text->md = EVP_get_digestbyname((const char *) glob_context);
+
+ *conn_context = text;
+
+ return SASL_OK;
+}
+
+static int
+scram_server_mech_step1(server_context_t *text,
+ sasl_server_params_t *sparams,
+ const char *clientin,
+ unsigned clientinlen,
+ const char **serverout,
+ unsigned *serveroutlen,
+ sasl_out_params_t *oparams __attribute__((unused)))
+{
+ char * authorization_id;
+ char * authentication_id;
+ char * p;
+ char * nonce;
+ size_t client_nonce_len;
+ char * base64_salt = NULL;
+ size_t base64len;
+ size_t estimated_challenge_len;
+ size_t pure_scram_length;
+ char * inbuf = NULL;
+ const char *password_request[] = { SASL_AUX_PASSWORD,
+ "*authPassword",
+ NULL };
+ int canon_flags;
+ struct propval auxprop_values[3];
+ int result;
+ size_t hash_size = EVP_MD_size(text->md);
+ const char *scram_sasl_mech = scram_sasl_mech_name(hash_size);
+
+ if (clientinlen == 0) {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "%s input expected", scram_sasl_mech);
+ return SASL_BADPROT;
+ }
+
+ /* Expecting: 'gs2-cbind-flag "," [ authzid ] "," [reserved-mext ","]
+ username "," nonce ["," extensions]' */
+
+ if (clientinlen < 10) {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "Invalid %s input", scram_sasl_mech);
+ return SASL_BADPROT;
+ }
+
+ inbuf = sparams->utils->malloc (clientinlen + 1);
+
+ if (inbuf == NULL) {
+ MEMERROR( sparams->utils );
+ return SASL_NOMEM;
+ }
+
+ memcpy(inbuf, clientin, clientinlen);
+ inbuf[clientinlen] = 0;
+
+ if (strlen(inbuf) != clientinlen) {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "NULs found in %s input", scram_sasl_mech);
+ result = SASL_BADPROT;
+ goto cleanup;
+ }
+
+ p = inbuf;
+
+ /* gs2-cbind-flag = "p=" cb-name / "n" / "y"
+ ;; "n" -> client doesn't support channel binding
+ ;; "y" -> client does support channel binding
+ ;; but thinks the server does not.
+ ;; "p" -> client requires channel binding.
+ ;; The selected channel binding follows "p=". */
+ switch (p[0]) {
+ case 'p':
+ if (p[1] != '=') {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "The initial 'p' needs to be followed by '=' in %s input",
+ scram_sasl_mech);
+ result = SASL_BADPROT;
+ goto cleanup;
+ }
+ p++;
+
+ text->cbindingname = p + 1;
+ p = strchr (p, ',');
+ if (p == NULL) {
+ text->cbindingname = NULL;
+
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "Channel binding name must be terminated by a comma in %s input",
+ scram_sasl_mech);
+ result = SASL_BADPROT;
+ goto cleanup;
+ }
+
+ *p = '\0';
+ _plug_strdup(sparams->utils, text->cbindingname, &text->cbindingname, NULL);
+ *p = ',';
+
+ text->cb_flags = SCRAM_CB_FLAG_P;
+ break;
+
+ case 'n':
+ text->cb_flags = SCRAM_CB_FLAG_N;
+ /* We always have at least 10 bytes, so this is safe */
+ p++;
+ break;
+
+ case 'y':
+ text->cb_flags = SCRAM_CB_FLAG_Y;
+ /* We always have at least 10 bytes, so this is safe */
+ p++;
+ break;
+
+ default:
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "The initial %s client response needs to start with 'y', 'n' or 'p'",
+ scram_sasl_mech);
+ result = SASL_BADPROT;
+ goto cleanup;
+ }
+
+ if (p[0] != ',') {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "',' expected in %s input", scram_sasl_mech);
+ result = SASL_BADPROT;
+ goto cleanup;
+ }
+ p++;
+
+ if (p[0] == 'a' && p[1] == '=') {
+ authorization_id = p + 2;
+
+ p = strchr (authorization_id, ',');
+ if (p == NULL) {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "At least nonce is expected in %s input",
+ scram_sasl_mech);
+ result = SASL_BADPROT;
+ goto cleanup;
+ }
+
+ /* End of the GS2 header */
+ p[0] = '\0';
+ /* The GS2 header length DOES include the terminating comma */
+ text->gs2_header_length = p - inbuf + 1;
+
+ p++;
+
+ /* Make a read-write copy we can modify */
+ _plug_strdup(sparams->utils, authorization_id, &text->authorization_id, NULL);
+
+ if (decode_saslname(text->authorization_id) != SASL_OK) {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "Invalid authorization identity encoding in %s input",
+ scram_sasl_mech);
+ result = SASL_BADPROT;
+ goto cleanup;
+ }
+ } else if (p[0] != ',') {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "',' expected in %s input", scram_sasl_mech);
+ result = SASL_BADPROT;
+ goto cleanup;
+ } else {
+ /* End of the GS2 header */
+ p[0] = '\0';
+ /* The GS2 header length DOES include the terminating comma */
+ text->gs2_header_length = p - inbuf + 1;
+
+ p++;
+ }
+
+ text->gs2_header = sparams->utils->malloc (text->gs2_header_length + 1);
+ if (text->gs2_header == NULL) {
+ MEMERROR( sparams->utils );
+ result = SASL_NOMEM;
+ goto cleanup;
+ }
+
+ memcpy(text->gs2_header, inbuf, text->gs2_header_length - 1);
+ /* Remember the comma */
+ text->gs2_header[text->gs2_header_length - 1] = ',';
+ text->gs2_header[text->gs2_header_length] = 0;
+
+
+
+ if (p[1] != '=') {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "Invalid %s input", scram_sasl_mech);
+ result = SASL_BADPROT;
+ goto cleanup;
+ }
+
+ if (p[0] == 'm') {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "Unsupported mandatory extension to %s",
+ scram_sasl_mech);
+ result = SASL_BADPROT;
+ goto cleanup;
+ }
+
+ if (p[0] != 'n') {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "Username (n=) expected in %s input",
+ scram_sasl_mech);
+ result = SASL_BADPROT;
+ goto cleanup;
+ }
+
+ authentication_id = p + 2;
+ p = strchr (authentication_id, ',');
+
+ /* MUST be followed by a nonce */
+ if (p == NULL) {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "Nonce expected after the username in %s input",
+ scram_sasl_mech);
+ result = SASL_BADPROT;
+ goto cleanup;
+ }
+
+ *p = '\0';
+ p++;
+
+ if (decode_saslname(authentication_id) != SASL_OK) {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "Invalid username encoding in %s input",
+ scram_sasl_mech);
+ result = SASL_BADPROT;
+ goto cleanup;
+ }
+
+ _plug_strdup(sparams->utils, authentication_id, &text->authentication_id, NULL);
+
+ if (strncmp(p, "r=", 2) != 0) {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "Nonce expected after the username in %s input",
+ scram_sasl_mech);
+ result = SASL_BADPROT;
+ goto cleanup;
+ }
+
+ p += 2;
+ nonce = p;
+ p = strchr (nonce, ',');
+
+ if (p == NULL) {
+ p = nonce + strlen(nonce);
+ } else {
+ *p = '\0';
+ }
+
+ /* Generate server nonce, by appending some random stuff to the client nonce */
+ client_nonce_len = strlen(nonce);
+ text->nonce = sparams->utils->malloc (client_nonce_len + NONCE_SIZE + 1);
+
+ if (text->nonce == NULL) {
+ MEMERROR( sparams->utils );
+ result = SASL_NOMEM;
+ goto cleanup;
+ }
+
+ strcpy (text->nonce, nonce);
+
+ if (create_nonce(sparams->utils,
+ text->nonce + client_nonce_len,
+ NONCE_SIZE + 1) == NULL) {
+ MEMERROR( sparams->utils );
+ result = SASL_NOMEM;
+ goto cleanup;
+ }
+
+
+
+ /* Now we fetch user's password and calculate our secret */
+ result = sparams->utils->prop_request(sparams->propctx, password_request);
+ if (result != SASL_OK) {
+ goto cleanup;
+ }
+
+ /* this will trigger the getting of the aux properties */
+ canon_flags = SASL_CU_AUTHID;
+ if (text->authorization_id == NULL || *text->authorization_id == '\0') {
+ canon_flags |= SASL_CU_AUTHZID;
+ }
+
+ result = sparams->canon_user(sparams->utils->conn,
+ text->authentication_id,
+ 0,
+ canon_flags,
+ oparams);
+ if (result != SASL_OK) {
+ SETERROR(sparams->utils, "unable to canonify user and get auxprops");
+ goto cleanup;
+ }
+
+ if (text->authorization_id != NULL && *text->authorization_id != '\0') {
+ result = sparams->canon_user(sparams->utils->conn,
+ text->authorization_id,
+ 0,
+ SASL_CU_AUTHZID,
+ oparams);
+ }
+ if (result != SASL_OK) {
+ SETERROR(sparams->utils, "unable to canonify authorization ID");
+ goto cleanup;
+ }
+
+ result = sparams->utils->prop_getnames(sparams->propctx,
+ password_request,
+ auxprop_values);
+ if (result < 0 ||
+ ((!auxprop_values[0].name || !auxprop_values[0].values) &&
+ (!auxprop_values[1].name || !auxprop_values[1].values))) {
+ /* We didn't find this username */
+ sparams->utils->seterror(sparams->utils->conn,0,
+ "no secret in database");
+ result = sparams->transition ? SASL_TRANS : SASL_NOUSER;
+ goto cleanup;
+ }
+
+ if (auxprop_values[0].name && auxprop_values[0].values) {
+ char * error_text = NULL;
+ char * s_iteration_count;
+ char * end;
+
+ text->salt = (char *) scram_server_user_salt(sparams->utils, text->md, text->authentication_id, &text->salt_len);
+
+ sparams->utils->getopt(sparams->utils->getopt_context,
+ /* Different SCRAM hashes can have different strengh */
+ scram_sasl_mech,
+ "scram_iteration_counter",
+ (const char **) &s_iteration_count,
+ NULL);
+
+ if (s_iteration_count != NULL) {
+ errno = 0;
+ text->iteration_count = strtoul(s_iteration_count, &end, 10);
+ if (s_iteration_count == end || *end != '\0' || errno != 0) {
+ sparams->utils->log(NULL,
+ SASL_LOG_DEBUG,
+ "Invalid iteration-count in scram_iteration_count SASL option: not a number. Using the default instead.");
+ s_iteration_count = NULL;
+ }
+ }
+
+ if (s_iteration_count == NULL) {
+ text->iteration_count = DEFAULT_ITERATION_COUNTER;
+ }
+
+ result = GenerateScramSecrets (sparams->utils,
+ text->md,
+ auxprop_values[0].values[0],
+ strlen(auxprop_values[0].values[0]),
+ text->salt,
+ text->salt_len,
+ text->iteration_count,
+ text->StoredKey,
+ text->ServerKey,
+ &error_text);
+ if (result != SASL_OK) {
+ if (error_text != NULL) {
+ sparams->utils->seterror(sparams->utils->conn, 0, "%s",
+ error_text);
+ }
+ goto cleanup;
+ }
+
+ } else if (auxprop_values[1].name && auxprop_values[1].values) {
+ char s_iteration_count[ITERATION_COUNTER_BUF_LEN+1];
+ size_t base64_salt_len;
+ unsigned int exact_key_len;
+ const char * scram_hash;
+ const char * p_field;
+ char * end;
+ int i;
+ size_t scram_sasl_mech_len = strlen(scram_sasl_mech);
+
+ result = SASL_SCRAM_INTERNAL;
+
+ for (i = 0; auxprop_values[1].values[i] != NULL; i++) {
+ scram_hash = auxprop_values[1].values[i];
+
+ /* Skip the leading spaces */
+ while (*scram_hash == ' ') {
+ scram_hash++;
+ }
+
+ if (strncmp(scram_hash, scram_sasl_mech, scram_sasl_mech_len) != 0) {
+ continue;
+ }
+ scram_hash += scram_sasl_mech_len;
+
+ /* Skip spaces */
+ while (*scram_hash == ' ') {
+ scram_hash++;
+ }
+
+ if (*scram_hash != '$') {
+ /* syntax error, ignore the value */
+ continue;
+ }
+ scram_hash++;
+
+ /* Skip spaces */
+ while (*scram_hash == ' ') {
+ scram_hash++;
+ }
+
+ p_field = strchr(scram_hash, ':');
+ if (p_field == NULL || p_field == scram_hash) {
+ /* syntax error, ignore the value */
+ continue;
+ }
+
+ if ((p_field - scram_hash) > ITERATION_COUNTER_BUF_LEN) {
+ /* The iteration counter is too big for us */
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "Invalid iteration-count in %s input: the value is too big",
+ scram_sasl_mech);
+ continue;
+ }
+
+ memcpy(s_iteration_count, scram_hash, p_field - scram_hash);
+ s_iteration_count[p_field - scram_hash] = '\0';
+
+ errno = 0;
+ text->iteration_count = strtoul(s_iteration_count, &end, 10);
+ if (s_iteration_count == end || *end != '\0' || errno != 0) {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "Invalid iteration-count in %s input: not a number",
+ scram_sasl_mech);
+ continue;
+ }
+
+ scram_hash = p_field + 1;
+
+ p_field = scram_hash + strcspn(scram_hash, "$ ");
+ if (p_field == scram_hash || *p_field == '\0') {
+ /* syntax error, ignore the value */
+ continue;
+ }
+
+ base64_salt_len = p_field - scram_hash;
+ text->salt = (char *) sparams->utils->malloc(base64_salt_len);
+ if (sparams->utils->decode64(scram_hash,
+ (unsigned int)base64_salt_len,
+ text->salt,
+ (unsigned int)base64_salt_len,
+ (unsigned int *) &text->salt_len) != SASL_OK) {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "Invalid base64 encoding of the salt in %s stored value",
+ scram_sasl_mech);
+ continue;
+ }
+
+ scram_hash = p_field;
+
+ /* Skip spaces */
+ while (*scram_hash == ' ') {
+ scram_hash++;
+ }
+
+ if (*scram_hash != '$') {
+ /* syntax error, ignore the value */
+ sparams->utils->free(text->salt);
+ text->salt = NULL;
+ continue;
+ }
+ scram_hash++;
+
+ /* Skip spaces */
+ while (*scram_hash == ' ') {
+ scram_hash++;
+ }
+
+ p_field = strchr(scram_hash, ':');
+ if (p_field == NULL || p_field == scram_hash) {
+ /* syntax error, ignore the value */
+ sparams->utils->free(text->salt);
+ text->salt = NULL;
+ continue;
+ }
+
+ if (sparams->utils->decode64(scram_hash,
+ (unsigned int)(p_field - scram_hash),
+ text->StoredKey,
+ hash_size + 1,
+ &exact_key_len) != SASL_OK) {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "Invalid base64 encoding of StoredKey in %s per-user storage",
+ scram_sasl_mech);
+ sparams->utils->free(text->salt);
+ text->salt = NULL;
+ continue;
+ }
+
+ if (exact_key_len != hash_size) {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "Invalid StoredKey in %s per-user storage",
+ scram_sasl_mech);
+ sparams->utils->free(text->salt);
+ text->salt = NULL;
+ continue;
+ }
+
+ scram_hash = p_field + 1;
+
+ p_field = strchr(scram_hash, ' ');
+ if (p_field == NULL) {
+ p_field = scram_hash + strlen(scram_hash);
+ }
+
+
+ if (sparams->utils->decode64(scram_hash,
+ (unsigned int)(p_field - scram_hash),
+ text->ServerKey,
+ hash_size + 1,
+ &exact_key_len) != SASL_OK) {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "Invalid base64 encoding of ServerKey in %s per-user storage",
+ scram_sasl_mech);
+ sparams->utils->free(text->salt);
+ text->salt = NULL;
+ continue;
+ }
+
+ if (exact_key_len != hash_size) {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "Invalid ServerKey in %s per-user storage", scram_sasl_mech);
+ sparams->utils->free(text->salt);
+ text->salt = NULL;
+ continue;
+ }
+
+ result = SASL_OK;
+ break;
+ }
+
+ if (result != SASL_OK) {
+ sparams->utils->seterror(sparams->utils->conn,
+ 0, "No valid %s secret found",
+ scram_sasl_mech);
+ goto cleanup;
+ }
+
+ } else {
+ sparams->utils->seterror(sparams->utils->conn,
+ 0,
+ "Have neither type of secret");
+ return SASL_FAIL;
+ }
+
+ /* erase the plaintext password */
+ sparams->utils->prop_erase(sparams->propctx, password_request[0]);
+
+
+
+ /* base 64 encode it so it has valid chars */
+ base64len = (text->salt_len / 3 * 4) + ((text->salt_len % 3) ? 4 : 0);
+
+ base64_salt = (char *) sparams->utils->malloc(base64len + 1);
+ if (base64_salt == NULL) {
+ MEMERROR( sparams->utils );
+ result = SASL_NOMEM;
+ goto cleanup;
+ }
+
+ /*
+ * Returns SASL_OK on success, SASL_BUFOVER if result won't fit
+ */
+ if (sparams->utils->encode64(text->salt,
+ (unsigned int)text->salt_len,
+ base64_salt,
+ (unsigned int)base64len + 1,
+ NULL) != SASL_OK) {
+ MEMERROR( sparams->utils );
+ result = SASL_NOMEM;
+ goto cleanup;
+ }
+
+ base64_salt[base64len] = '\0';
+
+ /* Now we generate server challenge */
+ estimated_challenge_len = client_nonce_len + NONCE_SIZE +
+ base64len +
+ ITERATION_COUNTER_BUF_LEN +
+ strlen("r=,s=,i=");
+ result = _plug_buf_alloc(sparams->utils,
+ &(text->out_buf),
+ &(text->out_buf_len),
+ (unsigned) estimated_challenge_len + 1);
+ if (result != SASL_OK) {
+ MEMERROR( sparams->utils );
+ result = SASL_NOMEM;
+ goto cleanup;
+ }
+
+ sprintf(text->out_buf,
+ "r=%s,s=%s,i=%u",
+ text->nonce,
+ base64_salt,
+ text->iteration_count);
+
+
+ /* Save the (client response, ",", server challenge, ",").
+ Note, we skip the GS2 prefix here */
+ pure_scram_length = clientinlen - text->gs2_header_length;
+ text->auth_message_len = pure_scram_length + 1 + estimated_challenge_len + 1;
+ text->auth_message = sparams->utils->malloc (text->auth_message_len + 1);
+ if (text->auth_message == NULL) {
+ MEMERROR( sparams->utils );
+ result = SASL_NOMEM;
+ goto cleanup;
+ }
+
+ memcpy(text->auth_message, clientin + text->gs2_header_length, pure_scram_length);
+ text->auth_message[pure_scram_length] = ',';
+ strcpy (text->auth_message + pure_scram_length + 1, text->out_buf);
+ strcat (text->auth_message + pure_scram_length + 1, ",");
+
+ /* Now remember the exact length, not the estimated one */
+ text->auth_message_len = strlen(text->auth_message);
+
+ *serverout = text->out_buf;
+ *serveroutlen = (unsigned) strlen(text->out_buf);
+
+ result = SASL_CONTINUE;
+ text->state = 2;
+
+cleanup:
+ if (inbuf != NULL) {
+ sparams->utils->free(inbuf);
+ }
+ if (base64_salt != NULL) {
+ sparams->utils->free(base64_salt);
+ }
+ return result;
+}
+
+static int
+scram_server_mech_step2(server_context_t *text,
+ sasl_server_params_t *sparams,
+ const char *clientin,
+ unsigned clientinlen,
+ const char **serverout,
+ unsigned *serveroutlen,
+ sasl_out_params_t *oparams)
+{
+ char *channel_binding = NULL;
+ size_t channel_binding_len = 0;
+ char *binary_channel_binding = NULL;
+ unsigned binary_channel_binding_len = 0;
+ char *client_proof = NULL;
+ char *inbuf = NULL;
+ char *p;
+ int result = SASL_FAIL;
+ size_t proof_offset;
+ char * full_auth_message;
+ char ReceivedClientKey[EVP_MAX_MD_SIZE];
+ char DecodedClientProof[EVP_MAX_MD_SIZE + 1];
+ char CalculatedStoredKey[EVP_MAX_MD_SIZE];
+ char ClientSignature[EVP_MAX_MD_SIZE];
+ char ServerSignature[EVP_MAX_MD_SIZE];
+ char * nonce;
+ size_t client_proof_len;
+ size_t server_proof_len;
+ unsigned exact_client_proof_len;
+ unsigned int hash_len = 0;
+ size_t k, hash_size = EVP_MD_size(text->md);
+ const char *scram_sasl_mech = scram_sasl_mech_name(hash_size);
+
+ if (clientinlen == 0) {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "%s input expected", scram_sasl_mech);
+ return SASL_BADPROT;
+ }
+
+ if (clientinlen < 3 || clientin[1] != '=') {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "Invalid %s input", scram_sasl_mech);
+ return SASL_BADPROT;
+ }
+
+ inbuf = sparams->utils->malloc (clientinlen + 1);
+
+ if (inbuf == NULL) {
+ MEMERROR( sparams->utils );
+ return SASL_NOMEM;
+ }
+
+ memcpy(inbuf, clientin, clientinlen);
+ inbuf[clientinlen] = 0;
+
+ if (strlen(inbuf) != clientinlen) {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "NULs found in %s input", scram_sasl_mech);
+ result = SASL_BADPROT;
+ goto cleanup;
+ }
+
+ /* Expecting: channel-binding "," nonce ["," extensions] "," proof */
+
+ p = inbuf;
+
+ if (strncmp(p, "c=", 2) != 0) {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "Channel binding expected in %s input",
+ scram_sasl_mech);
+ result = SASL_BADPROT;
+ goto cleanup;
+ }
+
+ channel_binding = p + 2;
+
+ p = strchr (channel_binding, ',');
+ if (p == NULL) {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "At least nonce is expected in %s input",
+ scram_sasl_mech);
+ result = SASL_BADPROT;
+ goto cleanup;
+ }
+ *p = '\0';
+ p++;
+
+ channel_binding_len = strlen(channel_binding);
+
+ /* We can calculate the exact length, but the decoded (binary) data
+ is always shorter than its base64 version. */
+ binary_channel_binding = (char *) sparams->utils->malloc(channel_binding_len + 1);
+
+ if (sparams->utils->decode64(channel_binding,
+ (unsigned int)channel_binding_len,
+ binary_channel_binding,
+ (unsigned int)channel_binding_len,
+ &binary_channel_binding_len) != SASL_OK) {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "Invalid base64 encoding of the channel bindings in %s",
+ scram_sasl_mech);
+ result = SASL_BADPROT;
+ goto cleanup;
+ }
+
+ if (binary_channel_binding_len < text->gs2_header_length ||
+ strncmp(binary_channel_binding, text->gs2_header, text->gs2_header_length) != 0) {
+ sparams->utils->seterror (sparams->utils->conn,
+ 0,
+ "Channel bindings prefix doesn't match the one received in the GS2 header of %s. Expected \"%s\"",
+ scram_sasl_mech, text->gs2_header);
+ result = SASL_BADPROT;
+ goto cleanup;
+ }
+
+ switch (text->cb_flags & SCRAM_CB_FLAG_MASK) {
+ case SCRAM_CB_FLAG_P:
+ binary_channel_binding_len -= (unsigned)text->gs2_header_length;
+ if (binary_channel_binding_len == 0) {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "Channel bindings data expected in %s",
+ scram_sasl_mech);
+ result = SASL_BADPROT;
+ goto cleanup;
+ }
+
+ if (sparams->cbinding == NULL) {
+ sparams->utils->seterror (sparams->utils->conn,
+ 0,
+ "Server does not support channel binding type received in %s. Received: %s",
+ scram_sasl_mech,
+ text->cbindingname);
+ result = SASL_BADPROT;
+ goto cleanup;
+ }
+
+ if (strcmp(sparams->cbinding->name, text->cbindingname) != 0) {
+ sparams->utils->seterror (sparams->utils->conn,
+ 0,
+ "Unsupported channel bindings type received in %s. Expected: %s, received: %s",
+ scram_sasl_mech,
+ sparams->cbinding->name,
+ text->cbindingname);
+ result = SASL_BADPROT;
+ goto cleanup;
+ }
+
+ if (binary_channel_binding_len != sparams->cbinding->len) {
+ sparams->utils->seterror (sparams->utils->conn,
+ 0,
+ "Unsupported channel bindings length received in %s. Expected length: %lu, received: %d",
+ scram_sasl_mech,
+ sparams->cbinding->len,
+ binary_channel_binding_len);
+ result = SASL_BADPROT;
+ goto cleanup;
+ }
+
+ if (memcmp(binary_channel_binding + text->gs2_header_length,
+ sparams->cbinding->data,
+ binary_channel_binding_len) != 0) {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "Channel bindings mismatch in %s",
+ scram_sasl_mech);
+ result = SASL_BADPROT;
+ goto cleanup;
+ }
+ break;
+ }
+
+ if (strncmp(p, "r=", 2) != 0) {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "Nonce expected in %s input",
+ scram_sasl_mech);
+ result = SASL_BADPROT;
+ goto cleanup;
+ }
+
+ nonce = p + 2;
+
+ p = strchr (nonce, ',');
+ if (p == NULL) {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "At least proof is expected in %s input",
+ scram_sasl_mech);
+ result = SASL_BADPROT;
+ goto cleanup;
+ }
+ *p = '\0';
+ p++;
+
+ if (strcmp(nonce, text->nonce) != 0) {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "Nonce mismatch %s input",
+ scram_sasl_mech);
+ result = SASL_BADPROT;
+ goto cleanup;
+ }
+
+ while (p[0] != '\0') {
+ if (strncmp(p, "p=", 2) == 0) {
+ client_proof = p + 2;
+ proof_offset = p - inbuf - 1;
+ break;
+ }
+
+ p = strchr (p, ',');
+ if (p == NULL) {
+ break;
+ }
+ p++;
+ }
+
+ if (client_proof == NULL) {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "Client proof is expected in %s input",
+ scram_sasl_mech);
+ result = SASL_BADPROT;
+ goto cleanup;
+ }
+
+ /* Check that no extension data exists after the proof */
+ p = strchr (client_proof, ',');
+ if (p != NULL) {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "No extension data is allowed after the client proof in %s input",
+ scram_sasl_mech);
+ result = SASL_BADPROT;
+ goto cleanup;
+ }
+
+ if (strlen(client_proof) != (hash_size / 3 * 4 + (hash_size % 3 ? 4 : 0))) {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "Invalid client proof length in %s input",
+ scram_sasl_mech);
+ result = SASL_BADPROT;
+ goto cleanup;
+ }
+
+ /* Construct the full AuthMessage */
+ full_auth_message = sparams->utils->realloc(text->auth_message,
+ text->auth_message_len + proof_offset + 1);
+ if (full_auth_message == NULL) {
+ MEMERROR( sparams->utils );
+ result = SASL_NOMEM;
+ goto cleanup;
+ }
+ text->auth_message = full_auth_message;
+
+ memcpy(text->auth_message + text->auth_message_len, clientin, proof_offset);
+
+ text->auth_message_len += proof_offset;
+ text->auth_message[text->auth_message_len] = '\0';
+
+
+ /* ClientSignature := HMAC(StoredKey, AuthMessage) */
+ if (HMAC(text->md,
+ (const unsigned char *) text->StoredKey,
+ hash_size,
+ (const unsigned char *)text->auth_message,
+ (int)text->auth_message_len,
+ (unsigned char *)ClientSignature,
+ &hash_len) == NULL) {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "HMAC-%s call failed", scram_sasl_mech+6);
+ result = SASL_SCRAM_INTERNAL;
+ goto cleanup;
+ }
+
+ client_proof_len = strlen(client_proof);
+ if (sparams->utils->decode64(client_proof,
+ (unsigned int)client_proof_len,
+ DecodedClientProof,
+ hash_size + 1,
+ &exact_client_proof_len) != SASL_OK) {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "Invalid base64 encoding of the client proof in %s input",
+ scram_sasl_mech);
+ result = SASL_BADPROT;
+ goto cleanup;
+ }
+
+ if (exact_client_proof_len != hash_size) {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "Invalid client proof (truncated) in %s input",
+ scram_sasl_mech);
+ result = SASL_BADPROT;
+ goto cleanup;
+ }
+
+ for (k = 0; k < hash_size; k++) {
+ ReceivedClientKey[k] = DecodedClientProof[k] ^ ClientSignature[k];
+ }
+
+ /* StoredKey := H(ClientKey) */
+ if (EVP_Digest((const unsigned char *) ReceivedClientKey, hash_size,
+ (unsigned char *) CalculatedStoredKey, NULL, text->md, NULL) == 0) {
+ sparams->utils->seterror(sparams->utils->conn,0,
+ "%s call failed", scram_sasl_mech+6);
+ result = SASL_SCRAM_INTERNAL;
+ goto cleanup;
+ }
+
+ for (k = 0; k < hash_size; k++) {
+ if (CalculatedStoredKey[k] != text->StoredKey[k]) {
+ SETERROR(sparams->utils, "StoredKey mismatch");
+ result = SASL_BADAUTH;
+ goto cleanup;
+ }
+ }
+
+ /* ServerSignature := HMAC(ServerKey, AuthMessage) */
+ if (HMAC(text->md,
+ (const unsigned char *) text->ServerKey,
+ hash_size,
+ (unsigned char *) text->auth_message,
+ (int)text->auth_message_len,
+ (unsigned char *)ServerSignature,
+ &hash_len) == NULL) {
+ sparams->utils->seterror(sparams->utils->conn,0,
+ "HMAC-%s call failed", scram_sasl_mech+6);
+ result = SASL_SCRAM_INTERNAL;
+ goto cleanup;
+ }
+
+ server_proof_len = (hash_size / 3 * 4 + (hash_size % 3 ? 4 : 0));
+ result = _plug_buf_alloc(sparams->utils,
+ &(text->out_buf),
+ &(text->out_buf_len),
+ (unsigned) server_proof_len + strlen("v=") + 1);
+ if (result != SASL_OK) {
+ MEMERROR( sparams->utils );
+ result = SASL_NOMEM;
+ goto cleanup;
+ }
+
+ text->out_buf[0] = 'v';
+ text->out_buf[1] = '=';
+
+
+ if (sparams->utils->encode64(ServerSignature,
+ hash_size,
+ text->out_buf+2,
+ (unsigned int)server_proof_len + 1,
+ NULL) != SASL_OK) {
+ SETERROR(sparams->utils, "Internal error");
+ /* This is not quite right, but better than alternatives */
+ result = SASL_NOMEM;
+ goto cleanup;
+ }
+
+ text->out_buf[server_proof_len + 2] = '\0';
+
+ *serverout = text->out_buf;
+ *serveroutlen = (unsigned) strlen(text->out_buf);
+
+
+ /* set oparams */
+
+ switch (text->cb_flags & SCRAM_CB_FLAG_MASK) {
+ case SCRAM_CB_FLAG_N:
+ oparams->cbindingdisp = SASL_CB_DISP_NONE;
+ break;
+ case SCRAM_CB_FLAG_P:
+ oparams->cbindingdisp = SASL_CB_DISP_USED;
+ oparams->cbindingname = text->cbindingname;
+ break;
+ case SCRAM_CB_FLAG_Y:
+ oparams->cbindingdisp = SASL_CB_DISP_WANT;
+ break;
+ }
+
+ oparams->doneflag = 1;
+ oparams->mech_ssf = 0;
+ oparams->maxoutbuf = 0;
+ oparams->encode_context = NULL;
+ oparams->encode = NULL;
+ oparams->decode_context = NULL;
+ oparams->decode = NULL;
+ oparams->param_version = 0;
+
+ result = SASL_OK;
+
+cleanup:
+ if (inbuf != NULL) {
+ sparams->utils->free(inbuf);
+ }
+ if (binary_channel_binding != NULL) {
+ sparams->utils->free(binary_channel_binding);
+ }
+
+ return result;
+}
+
+static int scram_server_mech_step(void *conn_context,
+ sasl_server_params_t *sparams,
+ const char *clientin,
+ unsigned clientinlen,
+ const char **serverout,
+ unsigned *serveroutlen,
+ sasl_out_params_t *oparams)
+{
+ server_context_t *text = (server_context_t *) conn_context;
+ const char *scram_sasl_mech = NULL;
+
+ *serverout = NULL;
+ *serveroutlen = 0;
+
+ if (text == NULL) {
+ return SASL_BADPROT;
+ }
+
+ scram_sasl_mech = scram_sasl_mech_name(EVP_MD_size(text->md));
+
+ /* this should be well more than is ever needed */
+ if (clientinlen > MAX_CLIENTIN_LEN) {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "%s input longer than "
+ STRINGIZE((MAX_CLIENTIN_LEN)) " bytes",
+ scram_sasl_mech);
+ return SASL_BADPROT;
+ }
+
+ switch (text->state) {
+ case 0:
+ text->state++;
+ /* Assume the protocol doesn't support initial client response */
+ if (clientinlen == 0) {
+ return SASL_CONTINUE;
+ }
+ /* fall through */
+
+ case 1:
+ return scram_server_mech_step1(text,
+ sparams,
+ clientin,
+ clientinlen,
+ serverout,
+ serveroutlen,
+ oparams);
+
+ case 2:
+ text->state++;
+ return scram_server_mech_step2(text,
+ sparams,
+ clientin,
+ clientinlen,
+ serverout,
+ serveroutlen,
+ oparams);
+
+ default: /* should never get here */
+ sparams->utils->log(NULL, SASL_LOG_ERR,
+ "Invalid %s server step %d\n",
+ scram_sasl_mech, text->state);
+ return SASL_FAIL;
+ }
+
+ return SASL_FAIL; /* should never get here */
+}
+
+static int scram_setpass(void *glob_context,
+ sasl_server_params_t *sparams,
+ const char *userstr,
+ const char *pass,
+ unsigned passlen,
+ const char *oldpass __attribute__((unused)),
+ unsigned oldpasslen __attribute__((unused)),
+ unsigned flags)
+{
+ int r;
+ char *user = NULL;
+ char *user_only = NULL;
+ char *realm = NULL;
+ sasl_secret_t *sec = NULL;
+ struct propctx *propctx = NULL;
+ const char *store_request[] = { "authPassword",
+ NULL };
+ const char *generate_scram_secret;
+ const EVP_MD *md = EVP_get_digestbyname((const char *) glob_context);
+ size_t hash_size = EVP_MD_size(md);
+ const char *scram_sasl_mech = scram_sasl_mech_name(hash_size);
+
+ /* Do we have a backend that can store properties? */
+ if (!sparams->utils->auxprop_store ||
+ sparams->utils->auxprop_store(NULL, NULL, NULL) != SASL_OK) {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "%s: auxprop backend can't store properties",
+ scram_sasl_mech);
+ return SASL_NOMECH;
+ }
+
+ sparams->utils->getopt(sparams->utils->getopt_context,
+ /* This affects all SCRAM plugins, not just SCRAM-SHA-1 */
+ "SCRAM",
+ "scram_secret_generate",
+ &generate_scram_secret,
+ NULL);
+
+ /* NOTE: The default (when this option is not set) is NOT to generate authPassword secret */
+ if (!(generate_scram_secret &&
+ (generate_scram_secret[0] == '1' || generate_scram_secret[0] == 'y' ||
+ (generate_scram_secret[0] == 'o' && generate_scram_secret[1] == 'n') ||
+ generate_scram_secret[0] == 't'))) {
+ /* Pretend that everything is Ok, no need to generate noise in the logs */
+ return SASL_OK;
+ }
+
+ r = _plug_parseuser(sparams->utils,
+ &user_only,
+ &realm,
+ sparams->user_realm,
+ sparams->serverFQDN,
+ userstr);
+ if (r) {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "%s: Error parsing user", scram_sasl_mech);
+ return r;
+ }
+
+ r = _plug_make_fulluser(sparams->utils, &user, user_only, realm);
+ if (r) {
+ goto cleanup;
+ }
+
+ if ((flags & SASL_SET_DISABLE) || pass == NULL) {
+ sec = NULL;
+ } else {
+ char * error_text = NULL;
+ char salt[SALT_SIZE + 1];
+ char base64_salt[BASE64_LEN(SALT_SIZE) + 1];
+ /* size_t salt_len = SALT_SIZE; */
+ char StoredKey[EVP_MAX_MD_SIZE + 1];
+ char ServerKey[EVP_MAX_MD_SIZE + 1];
+ char base64_StoredKey[BASE64_LEN(EVP_MAX_MD_SIZE) + 1];
+ char base64_ServerKey[BASE64_LEN(EVP_MAX_MD_SIZE) + 1];
+ size_t secret_len;
+ unsigned int iteration_count = DEFAULT_ITERATION_COUNTER;
+ char * s_iteration_count;
+ char * end;
+
+ sparams->utils->getopt(sparams->utils->getopt_context,
+ /* Different SCRAM hashes can have different strengh */
+ scram_sasl_mech,
+ "scram_iteration_counter",
+ (const char **) &s_iteration_count,
+ NULL);
+
+ if (s_iteration_count != NULL) {
+ errno = 0;
+ iteration_count = strtoul(s_iteration_count, &end, 10);
+ if (s_iteration_count == end || *end != '\0' || errno != 0) {
+ sparams->utils->log(NULL,
+ SASL_LOG_DEBUG,
+ "Invalid iteration-count in scram_iteration_count SASL option: not a number. Using the default instead.");
+ s_iteration_count = NULL;
+ }
+ }
+
+ if (s_iteration_count == NULL) {
+ iteration_count = DEFAULT_ITERATION_COUNTER;
+ }
+
+ sparams->utils->rand(sparams->utils->rpool, salt, SALT_SIZE);
+
+ r = GenerateScramSecrets (sparams->utils,
+ md,
+ pass,
+ passlen,
+ salt,
+ SALT_SIZE,
+ iteration_count,
+ StoredKey,
+ ServerKey,
+ &error_text);
+ if (r != SASL_OK) {
+ if (error_text != NULL) {
+ sparams->utils->seterror(sparams->utils->conn, 0, "%s",
+ error_text);
+ }
+ goto cleanup;
+ }
+
+ /* Returns SASL_OK on success, SASL_BUFOVER if result won't fit */
+ if (sparams->utils->encode64(salt,
+ SALT_SIZE,
+ base64_salt,
+ BASE64_LEN(SALT_SIZE) + 1,
+ NULL) != SASL_OK) {
+ MEMERROR( sparams->utils );
+ r = SASL_NOMEM;
+ goto cleanup;
+ }
+
+ base64_salt[BASE64_LEN(SALT_SIZE)] = '\0';
+
+
+ /* Returns SASL_OK on success, SASL_BUFOVER if result won't fit */
+ if (sparams->utils->encode64(StoredKey,
+ hash_size,
+ base64_StoredKey,
+ BASE64_LEN(hash_size) + 1,
+ NULL) != SASL_OK) {
+ MEMERROR( sparams->utils );
+ r = SASL_NOMEM;
+ goto cleanup;
+ }
+
+ base64_StoredKey[BASE64_LEN(hash_size)] = '\0';
+
+
+
+ /* Returns SASL_OK on success, SASL_BUFOVER if result won't fit */
+ if (sparams->utils->encode64(ServerKey,
+ hash_size,
+ base64_ServerKey,
+ BASE64_LEN(hash_size) + 1,
+ NULL) != SASL_OK) {
+ MEMERROR( sparams->utils );
+ r = SASL_NOMEM;
+ goto cleanup;
+ }
+
+ base64_ServerKey[BASE64_LEN(hash_size)] = '\0';
+
+ secret_len = strlen(scram_sasl_mech) + strlen("$:$:") +
+ ITERATION_COUNTER_BUF_LEN +
+ sizeof(base64_salt) +
+ sizeof(base64_StoredKey) +
+ sizeof(base64_ServerKey);
+
+ sec = sparams->utils->malloc(sizeof(sasl_secret_t) + secret_len);
+ if (sec == NULL) {
+ MEMERROR( sparams->utils );
+ r = SASL_NOMEM;
+ goto cleanup;
+ }
+
+ sprintf((char *) sec->data,
+ "%s$%u:%s$%s:%s",
+ scram_sasl_mech,
+ iteration_count,
+ base64_salt,
+ base64_StoredKey,
+ base64_ServerKey);
+ sec->len = (unsigned int) strlen((const char *) sec->data);
+ }
+
+ /* do the store */
+ propctx = sparams->utils->prop_new(0);
+ if (!propctx) {
+ r = SASL_FAIL;
+ }
+ if (!r) {
+ r = sparams->utils->prop_request(propctx, store_request);
+ }
+ if (!r) {
+ r = sparams->utils->prop_set(propctx,
+ "authPassword",
+ (const char *) (sec ? sec->data : NULL),
+ (sec ? sec->len : 0));
+ }
+ if (!r) {
+ r = sparams->utils->auxprop_store(sparams->utils->conn, propctx, user);
+ }
+ if (propctx) {
+ sparams->utils->prop_dispose(&propctx);
+ }
+
+ if (r) {
+ sparams->utils->seterror(sparams->utils->conn, 0,
+ "Error putting %s secret",
+ scram_sasl_mech);
+ goto cleanup;
+ }
+
+ sparams->utils->log(NULL, SASL_LOG_DEBUG, "Setpass for %s successful\n",
+ scram_sasl_mech);
+
+ cleanup:
+ if (user) _plug_free_string(sparams->utils, &user);
+ if (user_only) _plug_free_string(sparams->utils, &user_only);
+ if (realm) _plug_free_string(sparams->utils, &realm);
+ if (sec) _plug_free_secret(sparams->utils, &sec);
+
+ return r;
+}
+
+static void scram_server_mech_dispose(void *conn_context,
+ const sasl_utils_t *utils)
+{
+ server_context_t *text = (server_context_t *) conn_context;
+
+ if (!text) return;
+
+ if (text->authentication_id) _plug_free_string(utils,&(text->authentication_id));
+ if (text->authorization_id) _plug_free_string(utils,&(text->authorization_id));
+ if (text->out_buf) _plug_free_string(utils,&(text->out_buf));
+ if (text->auth_message) _plug_free_string(utils,&(text->auth_message));
+ if (text->nonce) _plug_free_string(utils,&(text->nonce));
+ if (text->salt) utils->free(text->salt);
+ if (text->cbindingname != NULL) {
+ utils->free(text->cbindingname);
+ text->cbindingname = NULL;
+ }
+ if (text->gs2_header != NULL) {
+ utils->free(text->gs2_header);
+ text->gs2_header = NULL;
+ }
+
+ utils->free(text);
+}
+
+static sasl_server_plug_t scram_server_plugins[] =
+{
+#ifdef HAVE_SHA512
+ {
+ "SCRAM-SHA-512", /* mech_name */
+ 0, /* max_ssf */
+ SASL_SET_HASH_STRENGTH_BITS(512) |
+ SASL_SEC_NOPLAINTEXT
+ | SASL_SEC_NOACTIVE
+ | SASL_SEC_NOANONYMOUS
+ | SASL_SEC_MUTUAL_AUTH, /* security_flags */
+ SASL_FEAT_ALLOWS_PROXY
+ | SASL_FEAT_SUPPORTS_HTTP
+ | SASL_FEAT_CHANNEL_BINDING, /* features */
+ "SHA512", /* glob_context */
+ &scram_server_mech_new, /* mech_new */
+ &scram_server_mech_step, /* mech_step */
+ &scram_server_mech_dispose, /* mech_dispose */
+ NULL, /* mech_free */
+ &scram_setpass, /* setpass */
+ NULL, /* user_query */
+ NULL, /* idle */
+ NULL, /* mech avail */
+ NULL /* spare */
+ },
+ {
+ "SCRAM-SHA-384", /* mech_name */
+ 0, /* max_ssf */
+ SASL_SET_HASH_STRENGTH_BITS(384) |
+ SASL_SEC_NOPLAINTEXT
+ | SASL_SEC_NOACTIVE
+ | SASL_SEC_NOANONYMOUS
+ | SASL_SEC_MUTUAL_AUTH, /* security_flags */
+ SASL_FEAT_ALLOWS_PROXY
+ | SASL_FEAT_SUPPORTS_HTTP
+ | SASL_FEAT_CHANNEL_BINDING, /* features */
+ "SHA384", /* glob_context */
+ &scram_server_mech_new, /* mech_new */
+ &scram_server_mech_step, /* mech_step */
+ &scram_server_mech_dispose, /* mech_dispose */
+ NULL, /* mech_free */
+ &scram_setpass, /* setpass */
+ NULL, /* user_query */
+ NULL, /* idle */
+ NULL, /* mech avail */
+ NULL /* spare */
+ },
+ {
+ "SCRAM-SHA-256", /* mech_name */
+ 0, /* max_ssf */
+ SASL_SET_HASH_STRENGTH_BITS(256) |
+ SASL_SEC_NOPLAINTEXT
+ | SASL_SEC_NOACTIVE
+ | SASL_SEC_NOANONYMOUS
+ | SASL_SEC_MUTUAL_AUTH, /* security_flags */
+ SASL_FEAT_ALLOWS_PROXY
+ | SASL_FEAT_SUPPORTS_HTTP
+ | SASL_FEAT_CHANNEL_BINDING, /* features */
+ "SHA256", /* glob_context */
+ &scram_server_mech_new, /* mech_new */
+ &scram_server_mech_step, /* mech_step */
+ &scram_server_mech_dispose, /* mech_dispose */
+ NULL, /* mech_free */
+ &scram_setpass, /* setpass */
+ NULL, /* user_query */
+ NULL, /* idle */
+ NULL, /* mech avail */
+ NULL /* spare */
+ },
+ {
+ "SCRAM-SHA-224", /* mech_name */
+ 0, /* max_ssf */
+ SASL_SET_HASH_STRENGTH_BITS(224) |
+ SASL_SEC_NOPLAINTEXT
+ | SASL_SEC_NOACTIVE
+ | SASL_SEC_NOANONYMOUS
+ | SASL_SEC_MUTUAL_AUTH, /* security_flags */
+ SASL_FEAT_ALLOWS_PROXY
+ | SASL_FEAT_SUPPORTS_HTTP
+ | SASL_FEAT_CHANNEL_BINDING, /* features */
+ "SHA224", /* glob_context */
+ &scram_server_mech_new, /* mech_new */
+ &scram_server_mech_step, /* mech_step */
+ &scram_server_mech_dispose, /* mech_dispose */
+ NULL, /* mech_free */
+ &scram_setpass, /* setpass */
+ NULL, /* user_query */
+ NULL, /* idle */
+ NULL, /* mech avail */
+ NULL /* spare */
+ },
+#endif
+ {
+ "SCRAM-SHA-1", /* mech_name */
+ 0, /* max_ssf */
+ SASL_SET_HASH_STRENGTH_BITS(160) |
+ SASL_SEC_NOPLAINTEXT
+ | SASL_SEC_NOACTIVE
+ | SASL_SEC_NOANONYMOUS
+ | SASL_SEC_MUTUAL_AUTH, /* security_flags */
+ SASL_FEAT_ALLOWS_PROXY
+ | SASL_FEAT_SUPPORTS_HTTP
+ | SASL_FEAT_CHANNEL_BINDING, /* features */
+ "SHA1", /* glob_context */
+ &scram_server_mech_new, /* mech_new */
+ &scram_server_mech_step, /* mech_step */
+ &scram_server_mech_dispose, /* mech_dispose */
+ NULL, /* mech_free */
+ &scram_setpass, /* setpass */
+ NULL, /* user_query */
+ NULL, /* idle */
+ NULL, /* mech avail */
+ NULL /* spare */
+ }
+};
+
+int scram_server_plug_init(const sasl_utils_t *utils,
+ int maxversion,
+ int *out_version,
+ sasl_server_plug_t **pluglist,
+ int *plugcount)
+{
+ if (maxversion < SASL_SERVER_PLUG_VERSION) {
+ SETERROR( utils, "SCRAM-SHA-* version mismatch");
+ return SASL_BADVERS;
+ }
+
+ *out_version = SASL_SERVER_PLUG_VERSION;
+ *pluglist = scram_server_plugins;
+#ifdef HAVE_SHA512
+ *plugcount = 5;
+#else
+ *plugcount = 1;
+#endif
+ utils->rand(utils->rpool, (char *)g_salt_key, SALT_SIZE);
+
+ return SASL_OK;
+}
+
+/***************************** Client Section *****************************/
+
+typedef struct client_context {
+ int state;
+
+ const EVP_MD *md; /* underlying MDA */
+
+ sasl_secret_t *password; /* user password */
+ unsigned int free_password; /* set if we need to free the password */
+
+ char * gs2_header;
+ size_t gs2_header_length;
+ char * out_buf;
+ unsigned out_buf_len;
+ char * auth_message;
+ size_t auth_message_len;
+ char * nonce;
+ /* in binary form */
+ char * salt;
+ size_t salt_len;
+ unsigned int iteration_count;
+ char SaltedPassword[EVP_MAX_MD_SIZE];
+
+ int cb_flags;
+} client_context_t;
+
+static int scram_client_mech_new(void *glob_context,
+ sasl_client_params_t *params,
+ void **conn_context)
+{
+ client_context_t *text;
+
+ /* holds state are in */
+ text = params->utils->malloc(sizeof(client_context_t));
+ if (text == NULL) {
+ MEMERROR(params->utils);
+ return SASL_NOMEM;
+ }
+
+ memset(text, 0, sizeof(client_context_t));
+
+ text->md = EVP_get_digestbyname((const char *) glob_context);
+
+ *conn_context = text;
+
+ return SASL_OK;
+}
+
+static int
+scram_client_mech_step1(client_context_t *text,
+ sasl_client_params_t *params,
+ const char *serverin __attribute__((unused)),
+ unsigned serverinlen __attribute__((unused)),
+ sasl_interact_t **prompt_need,
+ const char **clientout,
+ unsigned *clientoutlen,
+ sasl_out_params_t *oparams)
+{
+ const char *authid = NULL;
+ const char *userid = NULL;
+ int user_result = SASL_OK;
+ int auth_result = SASL_OK;
+ int pass_result = SASL_OK;
+ int result;
+ size_t maxsize;
+ char * encoded_authcid;
+ char * freeme = NULL;
+ char * freeme2 = NULL;
+ char channel_binding_state = 'n';
+ const char * channel_binding_name = NULL;
+ char * encoded_authorization_id = NULL;
+ const char *scram_sasl_mech = scram_sasl_mech_name(EVP_MD_size(text->md));
+
+ /* check if sec layer strong enough */
+ if (params->props.min_ssf > params->external_ssf) {
+ params->utils->seterror(params->utils->conn, 0,
+ "SSF requested of %s plugin",
+ scram_sasl_mech);
+ return SASL_TOOWEAK;
+ }
+
+ /* try to get the userid */
+ if (oparams->authid == NULL) {
+ auth_result=_plug_get_authid(params->utils, &authid, prompt_need);
+
+ if ((auth_result != SASL_OK) && (auth_result != SASL_INTERACT))
+ return auth_result;
+ }
+
+ /* try to get the userid */
+ if (oparams->user == NULL) {
+ user_result = _plug_get_userid(params->utils, &userid, prompt_need);
+
+ if ((user_result != SASL_OK) && (user_result != SASL_INTERACT)) {
+ return user_result;
+ }
+ }
+
+ /* try to get the password */
+ if (text->password == NULL) {
+ pass_result = _plug_get_password(params->utils,
+ &text->password,
+ &text->free_password,
+ prompt_need);
+ if ((pass_result != SASL_OK) && (pass_result != SASL_INTERACT)) {
+ return pass_result;
+ }
+ }
+
+ /* free prompts we got */
+ if (prompt_need && *prompt_need) {
+ params->utils->free(*prompt_need);
+ *prompt_need = NULL;
+ }
+
+ /* if there are prompts not filled in */
+ if ((auth_result == SASL_INTERACT) ||
+ (user_result == SASL_INTERACT) ||
+ (pass_result == SASL_INTERACT)) {
+ /* make the prompt list */
+ result =
+ _plug_make_prompts(params->utils,
+ prompt_need,
+ user_result == SASL_INTERACT ?
+ "Please enter your authorization name" : NULL,
+ NULL,
+ auth_result == SASL_INTERACT ?
+ "Please enter your authentication name" : NULL,
+ NULL,
+ pass_result == SASL_INTERACT ?
+ "Please enter your password" : NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+
+ if (result != SASL_OK) {
+ goto cleanup;
+ }
+
+ return SASL_INTERACT;
+ }
+
+ if (!text->password) {
+ PARAMERROR(params->utils);
+ return SASL_BADPARAM;
+ }
+
+ if (oparams->authid == NULL) {
+ if (!userid || !*userid) {
+ result = params->canon_user(params->utils->conn,
+ authid,
+ 0,
+ SASL_CU_AUTHID | SASL_CU_AUTHZID,
+ oparams);
+ }
+ else {
+ result = params->canon_user(params->utils->conn,
+ authid,
+ 0,
+ SASL_CU_AUTHID,
+ oparams);
+ if (result != SASL_OK) {
+ goto cleanup;
+ }
+
+ result = params->canon_user(params->utils->conn,
+ userid,
+ 0,
+ SASL_CU_AUTHZID,
+ oparams);
+ }
+ if (result != SASL_OK) {
+ goto cleanup;
+ }
+ }
+
+ switch (params->cbindingdisp) {
+ case SASL_CB_DISP_NONE:
+ text->cb_flags = SCRAM_CB_FLAG_N;
+ channel_binding_state = 'n';
+ break;
+ case SASL_CB_DISP_USED:
+ if (!SASL_CB_PRESENT(params)) {
+ result = SASL_BADPARAM;
+ goto cleanup;
+ }
+ channel_binding_name = params->cbinding->name;
+ text->cb_flags = SCRAM_CB_FLAG_P;
+ channel_binding_state = 'p';
+ break;
+ case SASL_CB_DISP_WANT:
+ text->cb_flags = SCRAM_CB_FLAG_Y;
+ channel_binding_state = 'y';
+ break;
+ }
+
+ text->nonce = params->utils->malloc (NONCE_SIZE + 1);
+
+ if (text->nonce == NULL) {
+ MEMERROR( params->utils );
+ result = SASL_NOMEM;
+ goto cleanup;
+ }
+
+ if (create_nonce(params->utils,
+ text->nonce,
+ NONCE_SIZE + 1) == NULL) {
+ MEMERROR( params->utils );
+ result = SASL_NOMEM;
+ goto cleanup;
+ }
+
+ if (userid != NULL && *userid != '\0') {
+ result = encode_saslname (oparams->user,
+ (const char **) &encoded_authorization_id,
+ &freeme2);
+
+ if (result != SASL_OK) {
+ MEMERROR( params->utils );
+ result = SASL_NOMEM;
+ goto cleanup;
+ }
+ }
+
+ result = encode_saslname (oparams->authid,
+ (const char **) &encoded_authcid,
+ &freeme);
+ if (result != SASL_OK) {
+ MEMERROR( params->utils );
+ result = SASL_NOMEM;
+ goto cleanup;
+ }
+
+ maxsize = strlen("p=,a=,n=,r=") +
+ ((channel_binding_name != NULL) ? strlen(channel_binding_name) : 0) +
+ ((encoded_authorization_id != NULL) ? strlen(encoded_authorization_id) : 0) +
+ strlen(encoded_authcid) +
+ strlen(text->nonce);
+ result = _plug_buf_alloc(params->utils,
+ &(text->out_buf),
+ &(text->out_buf_len),
+ (unsigned) maxsize + 1);
+ if (result != SASL_OK) {
+ MEMERROR( params->utils );
+ result = SASL_NOMEM;
+ goto cleanup;
+ }
+
+ snprintf(text->out_buf,
+ maxsize + 1,
+ "%c%s%s,%s%s,",
+ channel_binding_state,
+ (channel_binding_name != NULL) ? "=" : "",
+ (channel_binding_name != NULL) ? channel_binding_name : "",
+ (encoded_authorization_id != NULL) ? "a=" : "",
+ (encoded_authorization_id != NULL) ? encoded_authorization_id : "");
+
+ text->gs2_header_length = strlen(text->out_buf);
+ _plug_strdup(params->utils, text->out_buf, &text->gs2_header, NULL);
+
+ sprintf(text->out_buf + text->gs2_header_length,
+ "n=%s,r=%s",
+ encoded_authcid,
+ text->nonce);
+
+ /* Save the copy of the client-first-message */
+
+ /* Need to skip the GS2 prefix here */
+ _plug_strdup(params->utils,
+ text->out_buf + text->gs2_header_length,
+ &text->auth_message,
+ NULL);
+ if (text->auth_message == NULL) {
+ MEMERROR( params->utils );
+ result = SASL_NOMEM;
+ goto cleanup;
+ }
+
+ text->auth_message_len = strlen(text->auth_message);
+
+ *clientout = text->out_buf;
+ *clientoutlen = (unsigned) strlen(*clientout);
+
+ result = SASL_CONTINUE;
+
+cleanup:
+ if (freeme != NULL) _plug_free_string(params->utils, &freeme);
+ if (freeme2 != NULL) _plug_free_string(params->utils, &freeme2);
+
+ return result;
+}
+
+static int
+scram_client_mech_step2(client_context_t *text,
+ sasl_client_params_t *params,
+ const char *serverin,
+ unsigned serverinlen,
+ sasl_interact_t **prompt_need __attribute__((unused)),
+ const char **clientout,
+ unsigned *clientoutlen,
+ sasl_out_params_t *oparams __attribute__((unused)))
+{
+ char * p;
+ char * nonce;
+ size_t server_nonce_len;
+ char * base64_salt = NULL;
+ size_t base64_salt_len;
+ unsigned exact_salt_len;
+ char * counter;
+ char * end;
+ char * inbuf = NULL;
+ size_t estimated_response_len;
+ size_t length_no_proof;
+ char * full_auth_message;
+ size_t cb_bin_length;
+ size_t channel_binding_data_len = 0;
+ size_t cb_encoded_length;
+ const char * channel_binding_data = NULL;
+ char * cb_encoded = NULL;
+ char * cb_bin = NULL;
+ int result;
+ char ClientKey[EVP_MAX_MD_SIZE];
+ char StoredKey[EVP_MAX_MD_SIZE];
+ char ClientSignature[EVP_MAX_MD_SIZE];
+ char ClientProof[EVP_MAX_MD_SIZE];
+ char * client_proof = NULL;
+ size_t client_proof_len;
+ unsigned int hash_len = 0;
+ size_t k, hash_size = EVP_MD_size(text->md);
+ const char *scram_sasl_mech = scram_sasl_mech_name(hash_size);
+
+ if (serverinlen == 0) {
+ params->utils->seterror(params->utils->conn, 0,
+ "%s input expected", scram_sasl_mech);
+ return SASL_BADPROT;
+ }
+
+ /* [reserved-mext ","] nonce "," salt "," iteration-count ["," extensions] */
+
+ if (serverinlen < 3 || serverin[1] != '=') {
+ params->utils->seterror(params->utils->conn, 0,
+ "Invalid %s input", scram_sasl_mech);
+ return SASL_BADPROT;
+ }
+
+ if (serverin[0] == 'm') {
+ params->utils->seterror(params->utils->conn, 0,
+ "Unsupported mandatory extension to %s",
+ scram_sasl_mech);
+ return SASL_BADPROT;
+ }
+
+ if (serverin[0] != 'r') {
+ params->utils->seterror(params->utils->conn, 0,
+ "Nonce (r=) expected in %s input",
+ scram_sasl_mech);
+ return SASL_BADPROT;
+ }
+
+ inbuf = params->utils->malloc (serverinlen + 1);
+ if (inbuf == NULL) {
+ MEMERROR( params->utils );
+ return SASL_NOMEM;
+ }
+
+ memcpy(inbuf, serverin, serverinlen);
+ inbuf[serverinlen] = 0;
+
+ if (strlen(inbuf) != serverinlen) {
+ params->utils->seterror(params->utils->conn, 0,
+ "NULs found in %s input", scram_sasl_mech);
+ result = SASL_BADPROT;
+ goto cleanup;
+ }
+
+ nonce = inbuf + 2;
+ p = strchr (nonce, ',');
+
+ /* MUST be followed by a salt */
+ if (p == NULL) {
+ params->utils->seterror(params->utils->conn, 0,
+ "Salt expected after the nonce in %s input",
+ scram_sasl_mech);
+ result = SASL_BADPROT;
+ goto cleanup;
+ }
+
+ *p = '\0';
+ p++;
+
+ if (strncmp(p, "s=", 2) != 0) {
+ params->utils->seterror(params->utils->conn, 0,
+ "Salt expected after the nonce in %s input",
+ scram_sasl_mech);
+ result = SASL_BADPROT;
+ goto cleanup;
+ }
+
+ p += 2;
+ base64_salt = p;
+
+ p = strchr (base64_salt, ',');
+
+ /* MUST be followed by an iteration-count */
+ if (p == NULL) {
+ params->utils->seterror(params->utils->conn, 0,
+ "iteration-count expected after the salt in %s input",
+ scram_sasl_mech);
+ result = SASL_BADPROT;
+ goto cleanup;
+ }
+
+ *p = '\0';
+ p++;
+
+ if (strncmp(p, "i=", 2) != 0) {
+ params->utils->seterror(params->utils->conn, 0,
+ "iteration-count expected after the salt in %s input",
+ scram_sasl_mech);
+ result = SASL_BADPROT;
+ goto cleanup;
+ }
+
+ p += 2;
+ counter = p;
+ p = strchr (counter, ',');
+
+ if (p == NULL) {
+ p = counter + strlen(counter);
+ } else {
+ *p = '\0';
+ }
+
+ errno = 0;
+ text->iteration_count = strtoul(counter, &end, 10);
+ if (counter == end || *end != '\0' || errno != 0) {
+ params->utils->seterror(params->utils->conn, 0,
+ "Invalid iteration-count in %s input",
+ scram_sasl_mech);
+ result = SASL_BADPROT;
+ goto cleanup;
+ }
+
+ if (text->iteration_count < MIN_ITERATION_COUNTER) {
+ }
+
+ if (text->iteration_count > MAX_ITERATION_COUNTER) {
+ SETERROR(params->utils, "iteration-count is too big, refusing to compute");
+ result = SASL_BADPROT;
+ goto cleanup;
+ }
+
+ /* The client MUST verify that the initial part of the nonce
+ used in subsequent messages is the same as the nonce it
+ initially specified. */
+ server_nonce_len = strlen(nonce);
+
+ if (server_nonce_len <= NONCE_SIZE ||
+ strncmp(nonce, text->nonce, NONCE_SIZE) != 0) {
+ SETERROR(params->utils, "The nonce received from the server doesn't start from the nonce sent by the client");
+ result = SASL_BADPROT;
+ goto cleanup;
+ }
+
+ /* Now we can forget about our nonce */
+ params->utils->free(text->nonce);
+
+ _plug_strdup(params->utils, nonce, &text->nonce, NULL);
+
+ if (text->nonce == NULL) {
+ MEMERROR( params->utils );
+ result = SASL_NOMEM;
+ goto cleanup;
+ }
+
+ /* base64 decode salt */
+ base64_salt_len = strlen(base64_salt);
+
+ if (base64_salt_len == 0) {
+ SETERROR(params->utils, "The salt can't be empty");
+ result = SASL_BADPROT;
+ goto cleanup;
+ }
+
+ if (base64_salt_len % 4 != 0) {
+ SETERROR(params->utils, "Invalid base64 encoding of the salt");
+ result = SASL_BADPROT;
+ goto cleanup;
+ }
+
+ text->salt_len = base64_salt_len / 4 * 3;
+
+ text->salt = (char *) params->utils->malloc(text->salt_len + 1);
+ if (text->salt == NULL) {
+ MEMERROR( params->utils );
+ result = SASL_NOMEM;
+ goto cleanup;
+ }
+
+ if (params->utils->decode64(base64_salt,
+ (unsigned int)base64_salt_len,
+ text->salt,
+ (unsigned int)text->salt_len + 1,
+ &exact_salt_len) != SASL_OK) {
+ params->utils->seterror(params->utils->conn, 0,
+ "Invalid base64 encoding of the salt in %s input",
+ scram_sasl_mech);
+ result = SASL_BADPROT;
+ goto cleanup;
+ }
+
+ text->salt_len = exact_salt_len;
+
+ /* Now we generate client response */
+
+ if (text->gs2_header[0] == 'p') {
+
+ if (params->cbinding == NULL) {
+ result = SASL_FAIL;
+ goto cleanup;
+ }
+
+ channel_binding_data = (const char *) params->cbinding->data;
+ channel_binding_data_len = params->cbinding->len;
+ }
+
+ cb_bin_length = text->gs2_header_length +
+ ((channel_binding_data != NULL) ? channel_binding_data_len : 0);
+ cb_encoded_length = (cb_bin_length / 3 * 4) + ((cb_bin_length % 3) ? 4 : 0);
+
+ if (channel_binding_data != NULL) {
+ cb_bin = (char *) params->utils->malloc(cb_bin_length + 1);
+ if (cb_bin == NULL) {
+ MEMERROR( params->utils );
+ result = SASL_NOMEM;
+ goto cleanup;
+ }
+
+ memcpy(cb_bin, text->gs2_header, text->gs2_header_length);
+ memcpy(cb_bin + text->gs2_header_length, channel_binding_data, channel_binding_data_len);
+ }
+
+ cb_encoded = (char *) params->utils->malloc(cb_encoded_length + 1);
+ if (cb_encoded == NULL) {
+ MEMERROR( params->utils );
+ result = SASL_NOMEM;
+ goto cleanup;
+ }
+
+ /*
+ * Returns SASL_OK on success, SASL_BUFOVER if result won't fit
+ */
+ if (params->utils->encode64((cb_bin != NULL) ? cb_bin : text->gs2_header,
+ (unsigned int)cb_bin_length,
+ cb_encoded,
+ (unsigned int)cb_encoded_length + 1,
+ NULL) != SASL_OK) {
+ MEMERROR( params->utils );
+ result = SASL_NOMEM;
+ goto cleanup;
+ }
+
+ cb_encoded[cb_encoded_length] = '\0';
+
+ client_proof_len = hash_size / 3 * 4 + ((hash_size % 3) ? 4 : 0);
+ estimated_response_len = strlen(cb_encoded)+
+ strlen(text->nonce)+
+ client_proof_len +
+ strlen("c=,r=,p=");
+ result = _plug_buf_alloc(params->utils,
+ &(text->out_buf),
+ &(text->out_buf_len),
+ (unsigned) estimated_response_len + 1);
+ if (result != SASL_OK) {
+ MEMERROR( params->utils );
+ result = SASL_NOMEM;
+ goto cleanup;
+ }
+
+ /* channel-binding "," nonce ["," extensions] */
+ sprintf(text->out_buf,
+ "c=%s,r=%s",
+ cb_encoded,
+ text->nonce);
+
+ length_no_proof = strlen(text->out_buf);
+
+ /* Build AuthMessage */
+ full_auth_message = params->utils->realloc(text->auth_message,
+ text->auth_message_len + 1 +
+ serverinlen + 1 +
+ length_no_proof + 1);
+ if (full_auth_message == NULL) {
+ MEMERROR( params->utils );
+ result = SASL_NOMEM;
+ goto cleanup;
+ }
+
+ text->auth_message = full_auth_message;
+
+ text->auth_message[text->auth_message_len] = ',';
+ memcpy(text->auth_message + text->auth_message_len + 1, serverin, serverinlen);
+ text->auth_message[text->auth_message_len + 1 + serverinlen] = ',';
+ memcpy(text->auth_message + text->auth_message_len + 1 + serverinlen + 1,
+ text->out_buf,
+ length_no_proof);
+ text->auth_message_len += serverinlen + 2 + length_no_proof;
+ text->auth_message[text->auth_message_len] = '\0';
+
+ /* Calculate ClientProof */
+
+ /* SaltedPassword := Hi(password, salt) */
+ Hi (params->utils,
+ text->md,
+ (const char *) text->password->data,
+ text->password->len,
+ text->salt,
+ text->salt_len,
+ text->iteration_count,
+ text->SaltedPassword);
+
+ PRINT_HASH ("SaltedPassword", text->SaltedPassword, hash_size);
+
+ /* ClientKey := HMAC(SaltedPassword, "Client Key") */
+ if (HMAC(text->md,
+ (const unsigned char *) text->SaltedPassword,
+ hash_size,
+ (const unsigned char *) CLIENT_KEY_CONSTANT,
+ CLIENT_KEY_CONSTANT_LEN,
+ (unsigned char *)ClientKey,
+ &hash_len) == NULL) {
+ params->utils->seterror(params->utils->conn,0,
+ "HMAC-%s call failed", scram_sasl_mech+6);
+ result = SASL_SCRAM_INTERNAL;
+ goto cleanup;
+ }
+
+ PRINT_HASH ("ClientKey", ClientKey, hash_size);
+
+ /* StoredKey := H(ClientKey) */
+ if (EVP_Digest((const unsigned char *) ClientKey, hash_size,
+ (unsigned char *) StoredKey, NULL, text->md, NULL) == 0) {
+ params->utils->seterror(params->utils->conn,0,
+ "%s call failed", scram_sasl_mech+6);
+ result = SASL_SCRAM_INTERNAL;
+ goto cleanup;
+ }
+
+ PRINT_HASH ("StoredKey", StoredKey, hash_size);
+
+ /* ClientSignature := HMAC(StoredKey, AuthMessage) */
+ if (HMAC(text->md,
+ (const unsigned char *)StoredKey,
+ hash_size,
+ (const unsigned char *) text->auth_message,
+ (int)text->auth_message_len,
+ (unsigned char *)ClientSignature,
+ &hash_len) == NULL) {
+ params->utils->seterror(params->utils->conn,0,
+ "HMAC-%s call failed", scram_sasl_mech+6);
+ result = SASL_SCRAM_INTERNAL;
+ goto cleanup;
+ }
+
+ PRINT_HASH ("ClientSignature", ClientSignature, hash_size);
+
+ /* ClientProof := ClientKey XOR ClientSignature */
+ for (k = 0; k < hash_size; k++) {
+ ClientProof[k] = ClientKey[k] ^ ClientSignature[k];
+ }
+
+ PRINT_HASH ("ClientProof", ClientProof, hash_size);
+
+ /* base64-encode ClientProof */
+ client_proof = (char *) params->utils->malloc(client_proof_len + 1);
+ if (client_proof == NULL) {
+ MEMERROR( params->utils );
+ result = SASL_NOMEM;
+ goto cleanup;
+ }
+
+ result = params->utils->encode64(ClientProof,
+ hash_size,
+ client_proof,
+ (unsigned int)client_proof_len + 1,
+ NULL);
+
+ if (result != SASL_OK) {
+ goto cleanup;
+ }
+
+ client_proof[client_proof_len] = '\0';
+
+ sprintf(text->out_buf + length_no_proof,
+ ",p=%s",
+ client_proof);
+
+ *clientout = text->out_buf;
+ *clientoutlen = (unsigned) strlen(text->out_buf);
+
+ result = SASL_CONTINUE;
+
+cleanup:
+ if (inbuf != NULL) {
+ params->utils->free(inbuf);
+ }
+
+ if (client_proof != NULL) {
+ params->utils->free(client_proof);
+ }
+
+ if (cb_encoded != NULL) {
+ params->utils->free(cb_encoded);
+ }
+
+ if (cb_bin != NULL) {
+ params->utils->free(cb_bin);
+ }
+
+ return result;
+}
+
+
+static int
+scram_client_mech_step3(client_context_t *text,
+ sasl_client_params_t *params,
+ const char *serverin,
+ unsigned serverinlen,
+ sasl_interact_t **prompt_need __attribute__((unused)),
+ const char **clientout __attribute__((unused)),
+ unsigned *clientoutlen __attribute__((unused)),
+ sasl_out_params_t *oparams)
+{
+ char * p;
+ int result;
+ size_t server_proof_len;
+ unsigned exact_server_proof_len;
+ char DecodedServerProof[EVP_MAX_MD_SIZE + 1];
+ char ServerKey[EVP_MAX_MD_SIZE];
+ char ServerSignature[EVP_MAX_MD_SIZE];
+ unsigned int hash_len = 0;
+ size_t k, hash_size = EVP_MD_size(text->md);
+ const char *scram_sasl_mech = scram_sasl_mech_name(hash_size);
+
+ if (serverinlen < 3) {
+ params->utils->seterror(params->utils->conn, 0,
+ "Invalid %s input expected",
+ scram_sasl_mech);
+ return SASL_BADPROT;
+ }
+
+ /* Expecting: 'verifier ["," extensions]' */
+
+ if (strncmp(serverin, "v=", 2) != 0) {
+ params->utils->seterror(params->utils->conn, 0,
+ "ServerSignature expected in %s input",
+ scram_sasl_mech);
+ return SASL_BADPROT;
+ }
+
+ /* Use memchr instead of the original strchr as there is no guarantee that
+ the input data is NUL terminated */
+ p = memchr (serverin + 2, ',', serverinlen - 2);
+ if (p != NULL) {
+ server_proof_len = p - (serverin + 2) - 1;
+ } else {
+ server_proof_len = serverinlen - 2;
+ }
+
+ if (params->utils->decode64(serverin + 2, /* ServerProof */
+ (unsigned int)server_proof_len,
+ DecodedServerProof,
+ hash_size + 1,
+ &exact_server_proof_len) != SASL_OK) {
+ params->utils->seterror(params->utils->conn, 0,
+ "Invalid base64 encoding of the server proof in %s input",
+ scram_sasl_mech);
+ result = SASL_BADPROT;
+ goto cleanup;
+ }
+
+ if (exact_server_proof_len != hash_size) {
+ params->utils->seterror(params->utils->conn, 0,
+ "Invalid server proof (truncated) in %s input",
+ scram_sasl_mech);
+ result = SASL_BADPROT;
+ goto cleanup;
+ }
+
+ /* ServerKey := HMAC(SaltedPassword, "Server Key") */
+ if (HMAC(text->md,
+ (const unsigned char *)text->SaltedPassword,
+ hash_size,
+ (const unsigned char *) SERVER_KEY_CONSTANT,
+ SERVER_KEY_CONSTANT_LEN,
+ (unsigned char *)ServerKey,
+ &hash_len) == NULL) {
+ params->utils->seterror(params->utils->conn,0,
+ "HMAC-%s call failed", scram_sasl_mech+6);
+ result = SASL_SCRAM_INTERNAL;
+ goto cleanup;
+ }
+
+ /* ServerSignature := HMAC(ServerKey, AuthMessage) */
+ if (HMAC(text->md,
+ (const unsigned char *)ServerKey,
+ hash_size,
+ (const unsigned char *) text->auth_message,
+ (int)text->auth_message_len,
+ (unsigned char *)ServerSignature,
+ &hash_len) == NULL) {
+ params->utils->seterror(params->utils->conn,0,
+ "HMAC-%s call failed", scram_sasl_mech+6);
+ result = SASL_SCRAM_INTERNAL;
+ goto cleanup;
+ }
+
+ for (k = 0; k < hash_size; k++) {
+ if (DecodedServerProof[k] != ServerSignature[k]) {
+ SETERROR(params->utils, "ServerSignature mismatch");
+ result = SASL_BADAUTH;
+ goto cleanup;
+ }
+ }
+
+ /* set oparams */
+ oparams->doneflag = 1;
+ oparams->mech_ssf = 0;
+ oparams->maxoutbuf = 0;
+ oparams->encode_context = NULL;
+ oparams->encode = NULL;
+ oparams->decode_context = NULL;
+ oparams->decode = NULL;
+ oparams->param_version = 0;
+
+ result = SASL_OK;
+
+cleanup:
+ return result;
+}
+
+static int scram_client_mech_step(void *conn_context,
+ sasl_client_params_t *params,
+ const char *serverin,
+ unsigned serverinlen,
+ sasl_interact_t **prompt_need,
+ const char **clientout,
+ unsigned *clientoutlen,
+ sasl_out_params_t *oparams)
+{
+ int result = SASL_FAIL;
+ client_context_t *text = (client_context_t *) conn_context;
+ const char *scram_sasl_mech = scram_sasl_mech_name(EVP_MD_size(text->md));
+
+ *clientout = NULL;
+ *clientoutlen = 0;
+
+ /* this should be well more than is ever needed */
+ if (serverinlen > MAX_SERVERIN_LEN) {
+ params->utils->seterror(params->utils->conn, 0,
+ "%s input longer than " STRINGIZE((MAX_SERVERIN_LEN)) " bytes",
+ scram_sasl_mech);
+ return SASL_BADPROT;
+ }
+
+ switch (text->state) {
+ case 0:
+ result = scram_client_mech_step1(text,
+ params,
+ serverin,
+ serverinlen,
+ prompt_need,
+ clientout,
+ clientoutlen,
+ oparams);
+ break;
+
+ case 1:
+ result = scram_client_mech_step2(text,
+ params,
+ serverin,
+ serverinlen,
+ prompt_need,
+ clientout,
+ clientoutlen,
+ oparams);
+ break;
+
+ case 2:
+ result = scram_client_mech_step3(text,
+ params,
+ serverin,
+ serverinlen,
+ prompt_need,
+ clientout,
+ clientoutlen,
+ oparams);
+ break;
+
+ default: /* should never get here */
+ params->utils->log(NULL, SASL_LOG_ERR,
+ "Invalid %s client step %d\n",
+ scram_sasl_mech, text->state);
+ return SASL_FAIL;
+ }
+
+ if (result != SASL_INTERACT) {
+ text->state++;
+ }
+ return result;
+}
+
+static void scram_client_mech_dispose(void *conn_context,
+ const sasl_utils_t *utils)
+{
+ client_context_t *text = (client_context_t *) conn_context;
+
+ if (!text) return;
+
+ /* get rid of all sensitive info */
+ if (text->free_password) {
+ _plug_free_secret(utils, &text->password);
+ text->free_password = 0;
+ }
+
+ if (text->gs2_header) {
+ utils->free(text->gs2_header);
+ text->gs2_header = NULL;
+ }
+
+ if (text->out_buf) {
+ utils->free(text->out_buf);
+ text->out_buf = NULL;
+ }
+
+ if (text->auth_message) _plug_free_string(utils,&(text->auth_message));
+ if (text->nonce) _plug_free_string(utils,&(text->nonce));
+ if (text->salt) utils->free(text->salt);
+
+ utils->free(text);
+}
+
+static sasl_client_plug_t scram_client_plugins[] =
+{
+#ifdef HAVE_SHA512
+ {
+ "SCRAM-SHA-512", /* mech_name */
+ 0, /* max_ssf */
+ SASL_SET_HASH_STRENGTH_BITS(512) |
+ SASL_SEC_NOPLAINTEXT
+ | SASL_SEC_NOANONYMOUS
+ | SASL_SEC_NOACTIVE
+ | SASL_SEC_MUTUAL_AUTH, /* security_flags */
+ SASL_FEAT_ALLOWS_PROXY
+ | SASL_FEAT_SUPPORTS_HTTP
+ | SASL_FEAT_CHANNEL_BINDING, /* features */
+ NULL, /* required_prompts */
+ "SHA512", /* glob_context */
+ &scram_client_mech_new, /* mech_new */
+ &scram_client_mech_step, /* mech_step */
+ &scram_client_mech_dispose, /* mech_dispose */
+ NULL, /* mech_free */
+ NULL, /* idle */
+ NULL, /* spare */
+ NULL /* spare */
+ },
+ {
+ "SCRAM-SHA-384", /* mech_name */
+ 0, /* max_ssf */
+ SASL_SET_HASH_STRENGTH_BITS(384) |
+ SASL_SEC_NOPLAINTEXT
+ | SASL_SEC_NOANONYMOUS
+ | SASL_SEC_NOACTIVE
+ | SASL_SEC_MUTUAL_AUTH, /* security_flags */
+ SASL_FEAT_ALLOWS_PROXY
+ | SASL_FEAT_SUPPORTS_HTTP
+ | SASL_FEAT_CHANNEL_BINDING, /* features */
+ NULL, /* required_prompts */
+ "SHA384", /* glob_context */
+ &scram_client_mech_new, /* mech_new */
+ &scram_client_mech_step, /* mech_step */
+ &scram_client_mech_dispose, /* mech_dispose */
+ NULL, /* mech_free */
+ NULL, /* idle */
+ NULL, /* spare */
+ NULL /* spare */
+ },
+ {
+ "SCRAM-SHA-256", /* mech_name */
+ 0, /* max_ssf */
+ SASL_SET_HASH_STRENGTH_BITS(256) |
+ SASL_SEC_NOPLAINTEXT
+ | SASL_SEC_NOANONYMOUS
+ | SASL_SEC_NOACTIVE
+ | SASL_SEC_MUTUAL_AUTH, /* security_flags */
+ SASL_FEAT_ALLOWS_PROXY
+ | SASL_FEAT_SUPPORTS_HTTP
+ | SASL_FEAT_CHANNEL_BINDING, /* features */
+ NULL, /* required_prompts */
+ "SHA256", /* glob_context */
+ &scram_client_mech_new, /* mech_new */
+ &scram_client_mech_step, /* mech_step */
+ &scram_client_mech_dispose, /* mech_dispose */
+ NULL, /* mech_free */
+ NULL, /* idle */
+ NULL, /* spare */
+ NULL /* spare */
+ },
+ {
+ "SCRAM-SHA-224", /* mech_name */
+ 0, /* max_ssf */
+ SASL_SET_HASH_STRENGTH_BITS(224) |
+ SASL_SEC_NOPLAINTEXT
+ | SASL_SEC_NOANONYMOUS
+ | SASL_SEC_NOACTIVE
+ | SASL_SEC_MUTUAL_AUTH, /* security_flags */
+ SASL_FEAT_ALLOWS_PROXY
+ | SASL_FEAT_SUPPORTS_HTTP
+ | SASL_FEAT_CHANNEL_BINDING, /* features */
+ NULL, /* required_prompts */
+ "SHA224", /* glob_context */
+ &scram_client_mech_new, /* mech_new */
+ &scram_client_mech_step, /* mech_step */
+ &scram_client_mech_dispose, /* mech_dispose */
+ NULL, /* mech_free */
+ NULL, /* idle */
+ NULL, /* spare */
+ NULL /* spare */
+ },
+#endif
+ {
+ "SCRAM-SHA-1", /* mech_name */
+ 0, /* max_ssf */
+ SASL_SET_HASH_STRENGTH_BITS(160) |
+ SASL_SEC_NOPLAINTEXT
+ | SASL_SEC_NOANONYMOUS
+ | SASL_SEC_NOACTIVE
+ | SASL_SEC_MUTUAL_AUTH, /* security_flags */
+ SASL_FEAT_ALLOWS_PROXY
+ | SASL_FEAT_SUPPORTS_HTTP
+ | SASL_FEAT_CHANNEL_BINDING, /* features */
+ NULL, /* required_prompts */
+ "SHA1", /* glob_context */
+ &scram_client_mech_new, /* mech_new */
+ &scram_client_mech_step, /* mech_step */
+ &scram_client_mech_dispose, /* mech_dispose */
+ NULL, /* mech_free */
+ NULL, /* idle */
+ NULL, /* spare */
+ NULL /* spare */
+ }
+};
+
+int scram_client_plug_init(const sasl_utils_t *utils,
+ int maxversion,
+ int *out_version,
+ sasl_client_plug_t **pluglist,
+ int *plugcount)
+{
+ if (maxversion < SASL_CLIENT_PLUG_VERSION) {
+ SETERROR( utils, "SCRAM-SHA-* version mismatch");
+ return SASL_BADVERS;
+ }
+
+ *out_version = SASL_CLIENT_PLUG_VERSION;
+ *pluglist = scram_client_plugins;
+#ifdef HAVE_SHA512
+ *plugcount = 5;
+#else
+ *plugcount = 1;
+#endif
+
+ return SASL_OK;
+}
diff --git a/contrib/libs/sasl/sasldb/db_none.c b/contrib/libs/sasl/sasldb/db_none.c
new file mode 100644
index 0000000000..12eaedb2bf
--- /dev/null
+++ b/contrib/libs/sasl/sasldb/db_none.c
@@ -0,0 +1,103 @@
+/* db_none.c--provides linkage for systems which lack a backend db lib
+ * Rob Siemborski
+ * Rob Earhart
+ */
+/*
+ * Copyright (c) 1998-2016 Carnegie Mellon University. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For permission or any other legal
+ * details, please contact
+ * Carnegie Mellon University
+ * Center for Technology Transfer and Enterprise Creation
+ * 4615 Forbes Avenue
+ * Suite 302
+ * Pittsburgh, PA 15213
+ * (412) 268-7393, fax: (412) 268-7395
+ * innovation@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Computing Services
+ * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+#include "sasldb.h"
+
+/* This just exists to provide these symbols on systems where configure
+ * couldn't find a database library (or the user says we do not want one). */
+int _sasldb_getdata(const sasl_utils_t *utils,
+ sasl_conn_t *conn,
+ const char *authid __attribute__((unused)),
+ const char *realm __attribute__((unused)),
+ const char *propName __attribute__((unused)),
+ char *out __attribute__((unused)),
+ const size_t max_out __attribute__((unused)),
+ size_t *out_len __attribute__((unused)))
+{
+ if(conn) utils->seterror(conn, 0, "No Database Driver");
+ return SASL_FAIL;
+}
+
+int _sasldb_putdata(const sasl_utils_t *utils,
+ sasl_conn_t *conn,
+ const char *authid __attribute__((unused)),
+ const char *realm __attribute__((unused)),
+ const char *propName __attribute__((unused)),
+ const char *data __attribute__((unused)),
+ size_t data_len __attribute__((unused)))
+{
+ if(conn) utils->seterror(conn, 0, "No Database Driver");
+ return SASL_FAIL;
+}
+
+int _sasl_check_db(const sasl_utils_t *utils,
+ sasl_conn_t *conn)
+{
+ if(conn) utils->seterror(conn, 0, "No Database Driver");
+ return SASL_FAIL;
+}
+
+sasldb_handle _sasldb_getkeyhandle(const sasl_utils_t *utils,
+ sasl_conn_t *conn)
+{
+ if(conn) utils->seterror(conn, 0, "No Database Driver");
+ return NULL;
+}
+
+int _sasldb_getnextkey(const sasl_utils_t *utils __attribute__((unused)),
+ sasldb_handle handle __attribute__((unused)),
+ char *out __attribute__((unused)),
+ const size_t max_out __attribute__((unused)),
+ size_t *out_len __attribute__((unused)))
+{
+ return SASL_FAIL;
+}
+
+int _sasldb_releasekeyhandle(const sasl_utils_t *utils __attribute__((unused)),
+ sasldb_handle handle __attribute__((unused)))
+{
+ return SASL_FAIL;
+}
diff --git a/contrib/libs/sasl/sasldb/sasldb.h b/contrib/libs/sasl/sasldb/sasldb.h
new file mode 100644
index 0000000000..8068a8b019
--- /dev/null
+++ b/contrib/libs/sasl/sasldb/sasldb.h
@@ -0,0 +1,134 @@
+/* sasldb.h - SASLdb library header
+ * Rob Siemborski
+ * Tim Martin
+ */
+/*
+ * Copyright (c) 1998-2016 Carnegie Mellon University. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The name "Carnegie Mellon University" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For permission or any other legal
+ * details, please contact
+ * Carnegie Mellon University
+ * Center for Technology Transfer and Enterprise Creation
+ * 4615 Forbes Avenue
+ * Suite 302
+ * Pittsburgh, PA 15213
+ * (412) 268-7393, fax: (412) 268-7395
+ * innovation@andrew.cmu.edu
+ *
+ * 4. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by Computing Services
+ * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
+ *
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef SASLDB_H
+#define SASLDB_H
+
+#include "sasl.h"
+#include "saslplug.h"
+
+/*
+ * Note that some of these require a sasl_conn_t in order for
+ * the getcallback stuff to work correctly. This is great for
+ * when they are called from a plugin or the library but makes
+ * for much wierdness when an otherwise non-sasl application needs
+ * to make use of this functionality.
+ */
+
+int _sasldb_getdata(const sasl_utils_t *utils,
+ sasl_conn_t *conn,
+ const char *authid,
+ const char *realm,
+ const char *propName,
+ char *out, const size_t max_out, size_t *out_len);
+
+/* pass NULL for data to delete it */
+int _sasldb_putdata(const sasl_utils_t *utils,
+ sasl_conn_t *conn,
+ const char *authid,
+ const char *realm,
+ const char *propName,
+ const char *data, size_t data_len);
+
+/* Should be run before any db access is attempted */
+LIBSASL_API int _sasl_check_db(const sasl_utils_t *utils,
+ sasl_conn_t *conn);
+
+/* These allow iterating through the keys of the database */
+typedef void* sasldb_handle;
+
+typedef int (* sasldb_list_callback_t) (const char *authid,
+ const char *realm,
+ const char *property,
+ void *rock);
+
+LIBSASL_API sasldb_handle _sasldb_getkeyhandle(const sasl_utils_t *utils,
+ sasl_conn_t *conn);
+LIBSASL_API int _sasldb_getnextkey(const sasl_utils_t *utils,
+ sasldb_handle handle, char *out,
+ const size_t max_out, size_t *out_len);
+LIBSASL_API int _sasldb_releasekeyhandle(const sasl_utils_t *utils,
+ sasldb_handle handle);
+
+LIBSASL_API int _sasldb_listusers(const sasl_utils_t *utils,
+ sasl_conn_t *context,
+ sasldb_list_callback_t callback,
+ void *callback_rock);
+
+#if defined(KEEP_DB_OPEN)
+void sasldb_auxprop_free (void *glob_context, const sasl_utils_t *utils);
+#else
+#define sasldb_auxprop_free NULL
+#endif
+
+/* The rest are implemented in allockey.c and individual drivers need not
+ * do so */
+/* These two are aliases for getdata/putdata */
+int _sasldb_getsecret(const sasl_utils_t *utils,
+ sasl_conn_t *context,
+ const char *auth_identity,
+ const char *realm,
+ sasl_secret_t ** secret);
+
+int _sasldb_putsecret(const sasl_utils_t *utils,
+ sasl_conn_t *context,
+ const char *auth_identity,
+ const char *realm,
+ const sasl_secret_t * secret);
+
+LIBSASL_API int _sasldb_parse_key(const char *key, const size_t key_len,
+ char *authid, const size_t max_authid,
+ char *realm, const size_t max_realm,
+ char *propName, const size_t max_propname);
+
+/* This function is internal, but might be useful to have around */
+int _sasldb_alloc_key(const sasl_utils_t *utils,
+ const char *auth_identity,
+ const char *realm,
+ const char *propName,
+ char **key,
+ size_t *key_len);
+
+#endif /* SASLDB_H */
diff --git a/contrib/libs/sasl/ya.make b/contrib/libs/sasl/ya.make
new file mode 100644
index 0000000000..bc4592640e
--- /dev/null
+++ b/contrib/libs/sasl/ya.make
@@ -0,0 +1,68 @@
+# Generated by devtools/yamaker from nixpkgs 22.11.
+
+LIBRARY()
+
+LICENSE(
+ BSD-4-Clause-UC AND
+ Cmu-Computing-Services AND
+ IBM-pibs AND
+ LicenseRef-scancode-paul-mackerras-binary AND
+ RSA-MD
+)
+
+LICENSE_TEXTS(.yandex_meta/licenses.list.txt)
+
+VERSION(2.1.28)
+
+ORIGINAL_SOURCE(https://github.com/cyrusimap/cyrus-sasl/archive/cyrus-sasl-2.1.28.tar.gz)
+
+PEERDIR(
+ contrib/libs/openssl
+)
+
+ADDINCL(
+ contrib/libs/sasl
+ contrib/libs/sasl/common
+ contrib/libs/sasl/include
+ contrib/libs/sasl/lib
+ contrib/libs/sasl/plugins
+ contrib/libs/sasl/sasldb
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_RUNTIME()
+
+CFLAGS(
+ -DCONFIGDIR=\"/tmp/yamaker/sasl/out/lib/sasl2:/var/empty/cyrus-sasl-2.1.28/etc/sasl2\"
+ -DHAVE_CONFIG_H
+ -DOBSOLETE_CRAM_ATTR=1
+ -DOBSOLETE_DIGEST_ATTR=1
+ -DPLUGINDIR=\"/tmp/yamaker/sasl/out/lib/sasl2\"
+)
+
+SRCS(
+ common/plugin_common.c
+ lib/auxprop.c
+ lib/canonusr.c
+ lib/checkpw.c
+ lib/client.c
+ lib/common.c
+ lib/config.c
+ lib/dlopen.c
+ lib/external.c
+ lib/md5.c
+ lib/saslutil.c
+ lib/server.c
+ lib/seterror.c
+ plugins/anonymous.c
+ plugins/cram.c
+ plugins/digestmd5.c
+ plugins/otp.c
+ plugins/plain.c
+ plugins/sasldb.c
+ plugins/scram.c
+ sasldb/db_none.c
+)
+
+END()