diff options
Diffstat (limited to 'src/auth/passdb-lua.c')
-rw-r--r-- | src/auth/passdb-lua.c | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/src/auth/passdb-lua.c b/src/auth/passdb-lua.c new file mode 100644 index 0000000..13665c4 --- /dev/null +++ b/src/auth/passdb-lua.c @@ -0,0 +1,193 @@ +/* Copyright (c) 2017-2018 Dovecot authors, see the included COPYING file */ + +#include "auth-common.h" +#include "passdb.h" +#include "auth-cache.h" + +#if defined(BUILTIN_LUA) || defined(PLUGIN_BUILD) + +#include "db-lua.h" + +struct dlua_passdb_module { + struct passdb_module module; + struct dlua_script *script; + const char *file; + bool has_password_verify; +}; + +static enum passdb_result +passdb_lua_verify_password(struct dlua_passdb_module *module, + struct auth_request *request, const char *password) +{ + const char *error = NULL; + enum passdb_result result = + auth_lua_call_password_verify(module->script, request, + password, &error); + if (result == PASSDB_RESULT_PASSWORD_MISMATCH) { + auth_request_log_password_mismatch(request, AUTH_SUBSYS_DB); + } else if (result == PASSDB_RESULT_INTERNAL_FAILURE && error != NULL) { + e_error(authdb_event(request), "passdb-lua: %s", + error); + } + return result; +} + +static enum passdb_result +passdb_lua_lookup(struct auth_request *request, + const char **scheme_r, const char **password_r) +{ + const char *error = NULL; + enum passdb_result result; + struct dlua_passdb_module *module = + (struct dlua_passdb_module *)request->passdb->passdb; + + *scheme_r = *password_r = NULL; + + result = auth_lua_call_passdb_lookup(module->script, request, scheme_r, + password_r, &error); + + if (result == PASSDB_RESULT_INTERNAL_FAILURE && error != NULL) { + e_error(authdb_event(request), "db-lua: %s", error); + } else if (result != PASSDB_RESULT_OK) { + /* skip next bit */ + } else if (!auth_fields_exists(request->fields.extra_fields, "nopassword")) { + if (*password_r == NULL || **password_r == '\0') { + result = auth_request_password_missing(request); + } else { + if (*scheme_r == NULL) + *scheme_r = request->passdb->passdb->default_pass_scheme; + auth_request_set_field(request, "password", + *password_r, *scheme_r); + } + } else if (*password_r != NULL && **password_r != '\0') { + e_info(authdb_event(request), + "nopassword given and password is not empty"); + result = PASSDB_RESULT_PASSWORD_MISMATCH; + } + return result; +} + +static void +passdb_lua_lookup_credentials(struct auth_request *request, + lookup_credentials_callback_t *callback) +{ + const char *lua_password, *lua_scheme; + enum passdb_result result = + passdb_lua_lookup(request, &lua_scheme, &lua_password); + + passdb_handle_credentials(result, lua_password, lua_scheme, callback, request); +} + +static void +passdb_lua_verify_plain(struct auth_request *request, const char *password, + verify_plain_callback_t *callback) +{ + struct dlua_passdb_module *module = + (struct dlua_passdb_module *)request->passdb->passdb; + const char *lua_password, *lua_scheme; + enum passdb_result result; + + if (module->has_password_verify) { + result = passdb_lua_verify_password(module, request, password); + } else { + result = passdb_lua_lookup(request, &lua_scheme, &lua_password); + if (result == PASSDB_RESULT_OK) { + if (lua_scheme == NULL) + lua_scheme = "PLAIN"; + result = auth_request_password_verify(request, password, + lua_password, + lua_scheme, + AUTH_SUBSYS_DB); + } + } + callback(result, request); +} + +static struct passdb_module * +passdb_lua_preinit(pool_t pool, const char *args) +{ + const char *cache_key = "%u"; + const char *scheme = "PLAIN"; + struct dlua_passdb_module *module; + bool blocking = TRUE; + + module = p_new(pool, struct dlua_passdb_module, 1); + const char *const *fields = t_strsplit_spaces(args, " "); + while(*fields != NULL) { + if (str_begins(*fields, "file=")) { + module->file = p_strdup(pool, (*fields)+5); + } else if (str_begins(*fields, "blocking=")) { + const char *value = (*fields)+9; + if (strcmp(value, "yes") == 0) { + blocking = TRUE; + } else if (strcmp(value, "no") == 0) { + blocking = FALSE; + } else { + i_fatal("Invalid value %s. " + "Field blocking must be yes or no", + value); + } + } else if (str_begins(*fields, "cache_key=")) { + if (*((*fields)+10) != '\0') + cache_key = (*fields)+10; + else /* explicitly disable auth caching for lua */ + cache_key = NULL; + } else if (str_begins(*fields, "scheme=")) { + scheme = p_strdup(pool, (*fields)+7); + } else { + i_fatal("Unsupported parameter %s", *fields); + } + fields++; + } + + if (module->file == NULL) + i_fatal("passdb-lua: Missing mandatory file= parameter"); + + module->module.blocking = blocking; + module->module.default_cache_key = + auth_cache_parse_key(pool, cache_key); + module->module.default_pass_scheme = scheme; + return &module->module; +} + +static void passdb_lua_init(struct passdb_module *_module) +{ + struct dlua_passdb_module *module = + (struct dlua_passdb_module *)_module; + const char *error; + + if (dlua_script_create_file(module->file, &module->script, auth_event, &error) < 0 || + auth_lua_script_init(module->script, &error) < 0) + i_fatal("passdb-lua: initialization failed: %s", error); + module->has_password_verify = + dlua_script_has_function(module->script, AUTH_LUA_PASSWORD_VERIFY); +} + +static void passdb_lua_deinit(struct passdb_module *_module) +{ + struct dlua_passdb_module *module = + (struct dlua_passdb_module *)_module; + dlua_script_unref(&module->script); +} + +#ifndef PLUGIN_BUILD +struct passdb_module_interface passdb_lua = +#else +struct passdb_module_interface passdb_lua_plugin = +#endif +{ + "lua", + + passdb_lua_preinit, + passdb_lua_init, + passdb_lua_deinit, + + passdb_lua_verify_plain, + passdb_lua_lookup_credentials, + NULL +}; +#else +struct passdb_module_interface passdb_lua = { + .name = "lua" +}; +#endif |