diff options
Diffstat (limited to 'src/auth/mech.c')
-rw-r--r-- | src/auth/mech.c | 245 |
1 files changed, 245 insertions, 0 deletions
diff --git a/src/auth/mech.c b/src/auth/mech.c new file mode 100644 index 0000000..477f27b --- /dev/null +++ b/src/auth/mech.c @@ -0,0 +1,245 @@ +/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */ + +#include "auth-common.h" +#include "ioloop.h" +#include "mech.h" +#include "str.h" +#include "strfuncs.h" +#include "passdb.h" + +#include <ctype.h> + +static struct mech_module_list *mech_modules; + +void mech_register_module(const struct mech_module *module) +{ + struct mech_module_list *list; + i_assert(strcmp(module->mech_name, t_str_ucase(module->mech_name)) == 0); + + list = i_new(struct mech_module_list, 1); + list->module = *module; + + list->next = mech_modules; + mech_modules = list; +} + +void mech_unregister_module(const struct mech_module *module) +{ + struct mech_module_list **pos, *list; + + for (pos = &mech_modules; *pos != NULL; pos = &(*pos)->next) { + if (strcmp((*pos)->module.mech_name, module->mech_name) == 0) { + list = *pos; + *pos = (*pos)->next; + i_free(list); + break; + } + } +} + +const struct mech_module *mech_module_find(const char *name) +{ + struct mech_module_list *list; + name = t_str_ucase(name); + + for (list = mech_modules; list != NULL; list = list->next) { + if (strcmp(list->module.mech_name, name) == 0) + return &list->module; + } + return NULL; +} + +void mech_generic_auth_initial(struct auth_request *request, + const unsigned char *data, size_t data_size) +{ + if (data == NULL) { + auth_request_handler_reply_continue(request, uchar_empty_ptr, 0); + } else { + /* initial reply given, even if it was 0 bytes */ + request->mech->auth_continue(request, data, data_size); + } +} + +void mech_generic_auth_free(struct auth_request *request) +{ + pool_unref(&request->pool); +} + +extern const struct mech_module mech_plain; +extern const struct mech_module mech_login; +extern const struct mech_module mech_apop; +extern const struct mech_module mech_cram_md5; +extern const struct mech_module mech_digest_md5; +extern const struct mech_module mech_external; +extern const struct mech_module mech_otp; +extern const struct mech_module mech_scram_sha1; +extern const struct mech_module mech_scram_sha256; +extern const struct mech_module mech_anonymous; +#ifdef HAVE_GSSAPI +extern const struct mech_module mech_gssapi; +#endif +#ifdef HAVE_GSSAPI_SPNEGO +extern const struct mech_module mech_gssapi_spnego; +#endif +extern const struct mech_module mech_winbind_ntlm; +extern const struct mech_module mech_winbind_spnego; +extern const struct mech_module mech_oauthbearer; +extern const struct mech_module mech_xoauth2; + +static void mech_register_add(struct mechanisms_register *reg, + const struct mech_module *mech) +{ + struct mech_module_list *list; + + list = p_new(reg->pool, struct mech_module_list, 1); + list->module = *mech; + + str_printfa(reg->handshake, "MECH\t%s", mech->mech_name); + if ((mech->flags & MECH_SEC_PRIVATE) != 0) + str_append(reg->handshake, "\tprivate"); + if ((mech->flags & MECH_SEC_ANONYMOUS) != 0) + str_append(reg->handshake, "\tanonymous"); + if ((mech->flags & MECH_SEC_PLAINTEXT) != 0) + str_append(reg->handshake, "\tplaintext"); + if ((mech->flags & MECH_SEC_DICTIONARY) != 0) + str_append(reg->handshake, "\tdictionary"); + if ((mech->flags & MECH_SEC_ACTIVE) != 0) + str_append(reg->handshake, "\tactive"); + if ((mech->flags & MECH_SEC_FORWARD_SECRECY) != 0) + str_append(reg->handshake, "\tforward-secrecy"); + if ((mech->flags & MECH_SEC_MUTUAL_AUTH) != 0) + str_append(reg->handshake, "\tmutual-auth"); + str_append_c(reg->handshake, '\n'); + + list->next = reg->modules; + reg->modules = list; +} + +static const char *mech_get_plugin_name(const char *name) +{ + string_t *str = t_str_new(32); + + str_append(str, "mech_"); + for (; *name != '\0'; name++) { + if (*name == '-') + str_append_c(str, '_'); + else + str_append_c(str, i_tolower(*name)); + } + return str_c(str); +} + +struct mechanisms_register * +mech_register_init(const struct auth_settings *set) +{ + struct mechanisms_register *reg; + const struct mech_module *mech; + const char *const *mechanisms; + pool_t pool; + + pool = pool_alloconly_create("mechanisms register", 1024); + reg = p_new(pool, struct mechanisms_register, 1); + reg->pool = pool; + reg->set = set; + reg->handshake = str_new(pool, 512); + + mechanisms = t_strsplit_spaces(set->mechanisms, " "); + for (; *mechanisms != NULL; mechanisms++) { + const char *name = t_str_ucase(*mechanisms); + + if (strcmp(name, "ANONYMOUS") == 0) { + if (*set->anonymous_username == '\0') { + i_fatal("ANONYMOUS listed in mechanisms, " + "but anonymous_username not set"); + } + } + mech = mech_module_find(name); + if (mech == NULL) { + /* maybe it's a plugin. try to load it. */ + auth_module_load(mech_get_plugin_name(name)); + mech = mech_module_find(name); + } + if (mech == NULL) + i_fatal("Unknown authentication mechanism '%s'", name); + mech_register_add(reg, mech); + } + + if (reg->modules == NULL) + i_fatal("No authentication mechanisms configured"); + return reg; +} + +void mech_register_deinit(struct mechanisms_register **_reg) +{ + struct mechanisms_register *reg = *_reg; + + *_reg = NULL; + pool_unref(®->pool); +} + +const struct mech_module * +mech_register_find(const struct mechanisms_register *reg, const char *name) +{ + const struct mech_module_list *list; + name = t_str_ucase(name); + + for (list = reg->modules; list != NULL; list = list->next) { + if (strcmp(list->module.mech_name, name) == 0) + return &list->module; + } + return NULL; +} + +void mech_init(const struct auth_settings *set) +{ + mech_register_module(&mech_plain); + mech_register_module(&mech_login); + mech_register_module(&mech_apop); + mech_register_module(&mech_cram_md5); + mech_register_module(&mech_digest_md5); + mech_register_module(&mech_external); + if (set->use_winbind) { + mech_register_module(&mech_winbind_ntlm); + mech_register_module(&mech_winbind_spnego); + } else { +#if defined(HAVE_GSSAPI_SPNEGO) && defined(BUILTIN_GSSAPI) + mech_register_module(&mech_gssapi_spnego); +#endif + } + mech_register_module(&mech_otp); + mech_register_module(&mech_scram_sha1); + mech_register_module(&mech_scram_sha256); + mech_register_module(&mech_anonymous); +#ifdef BUILTIN_GSSAPI + mech_register_module(&mech_gssapi); +#endif + mech_register_module(&mech_oauthbearer); + mech_register_module(&mech_xoauth2); +} + +void mech_deinit(const struct auth_settings *set) +{ + mech_unregister_module(&mech_plain); + mech_unregister_module(&mech_login); + mech_unregister_module(&mech_apop); + mech_unregister_module(&mech_cram_md5); + mech_unregister_module(&mech_digest_md5); + mech_unregister_module(&mech_external); + if (set->use_winbind) { + mech_unregister_module(&mech_winbind_ntlm); + mech_unregister_module(&mech_winbind_spnego); + } else { +#if defined(HAVE_GSSAPI_SPNEGO) && defined(BUILTIN_GSSAPI) + mech_unregister_module(&mech_gssapi_spnego); +#endif + } + mech_unregister_module(&mech_otp); + mech_unregister_module(&mech_scram_sha1); + mech_unregister_module(&mech_scram_sha256); + mech_unregister_module(&mech_anonymous); +#ifdef BUILTIN_GSSAPI + mech_unregister_module(&mech_gssapi); +#endif + mech_unregister_module(&mech_oauthbearer); + mech_unregister_module(&mech_xoauth2); +} |