Mercurial > dovecot > core-2.2
changeset 16486:1cbff0a8a849
Added initial libsasl for implementing client side SASL library.
Initially supports PLAIN and LOGIN mechanisms.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Sun, 09 Jun 2013 06:02:14 +0300 |
parents | 7e54af474ea4 |
children | 266101990d63 |
files | configure.ac src/Makefile.am src/lib-dovecot/Makefile.am src/lib-sasl/Makefile.am src/lib-sasl/mech-login.c src/lib-sasl/mech-plain.c src/lib-sasl/sasl-client-private.h src/lib-sasl/sasl-client.c src/lib-sasl/sasl-client.h |
diffstat | 9 files changed, 336 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- a/configure.ac Sun Jun 09 03:10:43 2013 +0300 +++ b/configure.ac Sun Jun 09 06:02:14 2013 +0300 @@ -2559,7 +2559,7 @@ 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' @@ -2822,6 +2822,7 @@ 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
--- a/src/Makefile.am Sun Jun 09 03:10:43 2013 +0300 +++ b/src/Makefile.am Sun Jun 09 06:02:14 2013 +0300 @@ -7,6 +7,7 @@ lib-charset \ lib-dns \ lib-dict \ + lib-sasl \ lib-ssl-iostream \ lib-http \ lib-fs \
--- a/src/lib-dovecot/Makefile.am Sun Jun 09 03:10:43 2013 +0300 +++ b/src/lib-dovecot/Makefile.am Sun Jun 09 06:02:14 2013 +0300 @@ -7,6 +7,7 @@ ../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 Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-sasl/Makefile.am Sun Jun 09 06:02:14 2013 +0300 @@ -0,0 +1,16 @@ +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 Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-sasl/mech-login.c Sun Jun 09 06:02:14 2013 +0300 @@ -0,0 +1,73 @@ +/* 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 Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-sasl/mech-plain.c Sun Jun 09 06:02:14 2013 +0300 @@ -0,0 +1,68 @@ +/* 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 Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-sasl/sasl-client-private.h Sun Jun 09 06:02:14 2013 +0300 @@ -0,0 +1,33 @@ +#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 Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-sasl/sasl-client.c Sun Jun 09 06:02:14 2013 +0300 @@ -0,0 +1,104 @@ +/* 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 Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-sasl/sasl-client.h Sun Jun 09 06:02:14 2013 +0300 @@ -0,0 +1,38 @@ +#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