Initially supports PLAIN and LOGIN mechanisms.
LIBDOVECOT_COMPRESS='$(top_builddir)/src/lib-compression/libcompression.la'
LIBDOVECOT_LDA='$(top_builddir)/src/lib-lda/libdovecot-lda.la'
else
- LIBDOVECOT_DEPS='$(top_builddir)/src/lib-master/libmaster.la $(top_builddir)/src/lib-settings/libsettings.la $(top_builddir)/src/lib-http/libhttp.la $(top_builddir)/src/lib-dict/libdict.la $(top_builddir)/src/lib-dns/libdns.la $(top_builddir)/src/lib-fs/libfs.la $(top_builddir)/src/lib-imap/libimap.la $(top_builddir)/src/lib-mail/libmail.la $(top_builddir)/src/lib-auth/libauth.la $(top_builddir)/src/lib-charset/libcharset.la $(top_builddir)/src/lib-ssl-iostream/libssl_iostream.la $(top_builddir)/src/lib-test/libtest.la $(top_builddir)/src/lib/liblib.la'
+ LIBDOVECOT_DEPS='$(top_builddir)/src/lib-master/libmaster.la $(top_builddir)/src/lib-settings/libsettings.la $(top_builddir)/src/lib-http/libhttp.la $(top_builddir)/src/lib-dict/libdict.la $(top_builddir)/src/lib-dns/libdns.la $(top_builddir)/src/lib-fs/libfs.la $(top_builddir)/src/lib-imap/libimap.la $(top_builddir)/src/lib-mail/libmail.la $(top_builddir)/src/lib-sasl/libsasl.la $(top_builddir)/src/lib-auth/libauth.la $(top_builddir)/src/lib-charset/libcharset.la $(top_builddir)/src/lib-ssl-iostream/libssl_iostream.la $(top_builddir)/src/lib-test/libtest.la $(top_builddir)/src/lib/liblib.la'
LIBDOVECOT="$LIBDOVECOT_DEPS \$(LIBICONV) \$(MODULE_LIBS)"
LIBDOVECOT_STORAGE_LAST='$(top_builddir)/src/lib-storage/list/libstorage_list.la $(top_builddir)/src/lib-storage/index/libstorage_index.la $(top_builddir)/src/lib-storage/libstorage.la $(top_builddir)/src/lib-index/libindex.la $(top_builddir)/src/lib-imap-storage/libimap-storage.la'
LIBDOVECOT_STORAGE_FIRST='$(top_builddir)/src/lib-storage/libstorage_service.la $(top_builddir)/src/lib-storage/register/libstorage_register.la'
src/lib-ntlm/Makefile
src/lib-otp/Makefile
src/lib-dovecot/Makefile
+src/lib-sasl/Makefile
src/lib-settings/Makefile
src/lib-ssl-iostream/Makefile
src/lib-test/Makefile
lib-charset \
lib-dns \
lib-dict \
+ lib-sasl \
lib-ssl-iostream \
lib-http \
lib-fs \
../lib-dict/libdict.la \
../lib-imap/libimap.la \
../lib-mail/libmail.la \
+ ../lib-sasl/libsasl.la \
../lib-auth/libauth.la \
../lib-dns/libdns.la \
../lib-charset/libcharset.la \
--- /dev/null
+noinst_LTLIBRARIES = libsasl.la
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/lib
+
+libsasl_la_SOURCES = \
+ mech-login.c \
+ mech-plain.c \
+ sasl-client.c
+
+headers = \
+ sasl-client.h \
+ sasl-client-private.h
+
+pkginc_libdir=$(pkgincludedir)
+pkginc_lib_HEADERS = $(headers)
--- /dev/null
+/* Copyright (c) 2013 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "str.h"
+#include "sasl-client-private.h"
+
+enum login_state {
+ STATE_INIT = 0,
+ STATE_USER,
+ STATE_PASS
+};
+
+struct login_sasl_client {
+ struct sasl_client client;
+ enum login_state state;
+};
+
+static int
+mech_login_input(struct sasl_client *_client,
+ const unsigned char *input ATTR_UNUSED,
+ unsigned int input_len ATTR_UNUSED,
+ const char **error_r)
+{
+ struct login_sasl_client *client = (struct login_sasl_client *)_client;
+
+ if (client->state == STATE_PASS) {
+ *error_r = "Server didn't finish authentication";
+ return -1;
+ }
+ client->state++;
+ return 0;
+}
+
+static int
+mech_login_output(struct sasl_client *_client,
+ const unsigned char **output_r, unsigned int *output_len_r,
+ const char **error_r)
+{
+ struct login_sasl_client *client = (struct login_sasl_client *)_client;
+
+ if (_client->set.authid == NULL) {
+ *error_r = "authid not set";
+ return -1;
+ }
+ if (_client->password == NULL) {
+ *error_r = "password not set";
+ return -1;
+ }
+
+ switch (client->state) {
+ case STATE_INIT:
+ *output_r = &uchar_nul;
+ *output_len_r = 0;
+ return 0;
+ case STATE_USER:
+ *output_r = (const unsigned char *)_client->set.authid;
+ *output_len_r = strlen(_client->set.authid);
+ return 0;
+ case STATE_PASS:
+ *output_r = (const unsigned char *)_client->set.password;
+ *output_len_r = strlen(_client->set.password);
+ return 0;
+ }
+ i_unreached();
+}
+
+const struct sasl_client_mech sasl_client_mech_login = {
+ .name = "LOGIN",
+ .struct_size = sizeof(struct login_sasl_client),
+
+ .input = mech_login_input,
+ .output = mech_login_output
+};
--- /dev/null
+/* Copyright (c) 2013 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "str.h"
+#include "sasl-client-private.h"
+
+struct plain_sasl_client {
+ struct sasl_client client;
+ bool output_sent;
+};
+
+static int
+mech_plain_input(struct sasl_client *_client,
+ const unsigned char *input ATTR_UNUSED, unsigned int input_len,
+ const char **error_r)
+{
+ struct plain_sasl_client *client = (struct plain_sasl_client *)_client;
+
+ if (!client->output_sent) {
+ if (input_len > 0) {
+ *error_r = "Server sent non-empty initial response";
+ return -1;
+ }
+ } else {
+ *error_r = "Server didn't finish authentication";
+ return -1;
+ }
+ return 0;
+}
+
+static int
+mech_plain_output(struct sasl_client *_client,
+ const unsigned char **output_r, unsigned int *output_len_r,
+ const char **error_r)
+{
+ struct plain_sasl_client *client = (struct plain_sasl_client *)_client;
+ string_t *str;
+
+ if (_client->set.authid == NULL) {
+ *error_r = "authid not set";
+ return -1;
+ }
+ if (_client->password == NULL) {
+ *error_r = "password not set";
+ return -1;
+ }
+
+ str = str_new(_client->pool, 64);
+ if (_client->set.authzid != NULL)
+ str_append(str, _client->set.authzid);
+ str_append_c(str, '\0');
+ str_append(str, _client->set.authid);
+ str_append_c(str, '\0');
+ str_append(str, _client->password);
+
+ *output_r = str_data(str);
+ *output_len_r = str_len(str);
+ client->output_sent = TRUE;
+ return 0;
+}
+
+const struct sasl_client_mech sasl_client_mech_plain = {
+ .name = "PLAIN",
+ .struct_size = sizeof(struct plain_sasl_client),
+
+ .input = mech_plain_input,
+ .output = mech_plain_output
+};
--- /dev/null
+#ifndef SASL_CLIENT_PRIVATE_H
+#define SASL_CLIENT_PRIVATE_H
+
+#include "sasl-client.h"
+
+struct sasl_client {
+ pool_t pool;
+ struct sasl_client_settings set;
+ char *password;
+ const struct sasl_client_mech *mech;
+};
+
+struct sasl_client_mech {
+ const char *name;
+ size_t struct_size;
+
+ int (*input)(struct sasl_client *client,
+ const unsigned char *input,
+ unsigned int input_len,
+ const char **error_r);
+ int (*output)(struct sasl_client *client,
+ const unsigned char **output_r,
+ unsigned int *output_len_r,
+ const char **error_r);
+ void (*free)(struct sasl_client *client);
+};
+
+extern const struct sasl_client_mech sasl_client_mech_login;
+
+void sasl_client_mech_register(const struct sasl_client_mech *mech);
+void sasl_client_mech_unregister(const struct sasl_client_mech *mech);
+
+#endif
--- /dev/null
+/* Copyright (c) 2013 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "array.h"
+#include "safe-memset.h"
+#include "sasl-client-private.h"
+
+static ARRAY(const struct sasl_client_mech *) sasl_mechanisms = ARRAY_INIT;
+
+static const struct sasl_client_mech *
+sasl_client_mech_find_idx(const char *name, unsigned int *idx_r)
+{
+ const struct sasl_client_mech *const *mechp;
+
+ array_foreach(&sasl_mechanisms, mechp) {
+ if (strcasecmp((*mechp)->name, name) == 0) {
+ *idx_r = array_foreach_idx(&sasl_mechanisms, mechp);
+ return *mechp;
+ }
+ }
+ return NULL;
+}
+
+const struct sasl_client_mech *sasl_client_mech_find(const char *name)
+{
+ unsigned int idx;
+
+ return sasl_client_mech_find_idx(name, &idx);
+}
+
+const char *sasl_client_mech_get_name(const struct sasl_client_mech *mech)
+{
+ return mech->name;
+}
+
+void sasl_client_mech_register(const struct sasl_client_mech *mech)
+{
+ array_append(&sasl_mechanisms, &mech, 1);
+}
+
+void sasl_client_mech_unregister(const struct sasl_client_mech *mech)
+{
+ unsigned int idx;
+
+ if (sasl_client_mech_find_idx(mech->name, &idx) == NULL)
+ i_panic("SASL mechanism not registered: %s", mech->name);
+ array_delete(&sasl_mechanisms, idx, 1);
+}
+
+struct sasl_client *sasl_client_new(const struct sasl_client_mech *mech,
+ const struct sasl_client_settings *set)
+{
+ struct sasl_client *client;
+ pool_t pool = pool_alloconly_create("sasl client", 512);
+
+ client = p_malloc(pool, mech->struct_size);
+ client->pool = pool;
+ client->mech = mech;
+ client->set.authid = p_strdup(pool, set->authid);
+ client->set.authzid = p_strdup(pool, set->authzid);
+ client->password = p_strdup(pool, set->password);
+ client->set.password = client->password;
+ return client;
+}
+
+void sasl_client_free(struct sasl_client **_client)
+{
+ struct sasl_client *client = *_client;
+
+ *_client = NULL;
+
+ if (client->mech->free != NULL)
+ client->mech->free(client);
+ safe_memset(client->password, 0, strlen(client->password));
+ pool_unref(&client->pool);
+}
+
+int sasl_client_input(struct sasl_client *client,
+ const unsigned char *input,
+ unsigned int input_len,
+ const char **error_r)
+{
+ return client->mech->input(client, input, input_len, error_r);
+}
+
+int sasl_client_output(struct sasl_client *client,
+ const unsigned char **output_r,
+ unsigned int *output_len_r,
+ const char **error_r)
+{
+ return client->mech->output(client, output_r, output_len_r, error_r);
+}
+
+void sasl_clients_init(void)
+{
+ i_array_init(&sasl_mechanisms, 8);
+ sasl_client_mech_register(&sasl_client_mech_plain);
+ sasl_client_mech_register(&sasl_client_mech_login);
+}
+
+void sasl_clients_deinit(void)
+{
+ array_free(&sasl_mechanisms);
+}
--- /dev/null
+#ifndef SASL_CLIENT_H
+#define SASL_CLIENT_H
+
+struct sasl_client_settings {
+ /* authentication ID - must be set with most mechanisms */
+ const char *authid;
+ /* authorization ID ("master user") */
+ const char *authzid;
+ /* password - must be set with most mechanisms */
+ const char *password;
+};
+
+/* PLAIN mechanism always exists and can be accessed directly via this. */
+extern const struct sasl_client_mech sasl_client_mech_plain;
+
+const struct sasl_client_mech *sasl_client_mech_find(const char *name);
+const char *sasl_client_mech_get_name(const struct sasl_client_mech *mech);
+
+struct sasl_client *sasl_client_new(const struct sasl_client_mech *mech,
+ const struct sasl_client_settings *set);
+void sasl_client_free(struct sasl_client **client);
+
+/* Call for server input. */
+int sasl_client_input(struct sasl_client *client,
+ const unsigned char *input,
+ unsigned int input_len,
+ const char **error_r);
+/* Call for getting server output. Also used to get the initial SASL response
+ if supported by the protocol. */
+int sasl_client_output(struct sasl_client *client,
+ const unsigned char **output_r,
+ unsigned int *output_len_r,
+ const char **error_r);
+
+void sasl_clients_init(void);
+void sasl_clients_deinit(void);
+
+#endif