passdb-lua.c revision 9698cd24356147d8a5471260062ea7e10e692fdf
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny/* Copyright (c) 2017 Dovecot authors, see the included COPYING file */
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny#include "auth-common.h"
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny#include "passdb.h"
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny#if defined(BUILTIN_LUA) || defined(PLUGIN_BUILD)
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny#include "db-lua.h"
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zelenystruct dlua_passdb_module {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny struct passdb_module module;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny struct dlua_script *script;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny const char *file;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny bool has_password_verify;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny};
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zelenystatic enum passdb_result
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zelenypassdb_lua_verify_password(struct dlua_passdb_module *module,
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny struct auth_request *request, const char *password)
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny{
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny const char *error = NULL;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny enum passdb_result result =
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny auth_lua_call_password_verify(module->script, request,
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny password, &error);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny if (result == PASSDB_RESULT_PASSWORD_MISMATCH) {
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce auth_request_log_password_mismatch(request, AUTH_SUBSYS_DB);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny } else if (result == PASSDB_RESULT_INTERNAL_FAILURE && error != NULL) {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny auth_request_log_error(request, AUTH_SUBSYS_DB, "passdb-lua: %s",
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny error);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny }
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny return result;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny}
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zelenystatic enum passdb_result
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zelenypassdb_lua_lookup(struct auth_request *request,
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose const char **scheme_r, const char **password_r)
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny{
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce const char *error = NULL;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny enum passdb_result result;
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose struct dlua_passdb_module *module =
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose (struct dlua_passdb_module *)request->passdb->passdb;
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose *scheme_r = *password_r = NULL;
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny result = auth_lua_call_passdb_lookup(module->script, request, scheme_r,
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny password_r, &error);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny if (result == PASSDB_RESULT_INTERNAL_FAILURE && error != NULL) {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny auth_request_log_error(request, AUTH_SUBSYS_DB, "db-lua: %s", error);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny } else if (result != PASSDB_RESULT_OK) {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny /* skip next bit */
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce } else if (!auth_fields_exists(request->extra_fields, "nopassword")) {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny if (*password_r == NULL || **password_r == '\0') {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny auth_request_log_info(request, AUTH_SUBSYS_DB,
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny "No password returned (and no nopassword)");
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny result = PASSDB_RESULT_PASSWORD_MISMATCH;
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce }
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny } else if (*password_r == NULL || **password_r != '\0') {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny auth_request_log_info(request, AUTH_SUBSYS_DB,
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny "nopassword given and password is not empty");
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny result = PASSDB_RESULT_PASSWORD_MISMATCH;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny }
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny return result;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny}
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorcestatic void
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorcepassdb_lua_lookup_credentials(struct auth_request *request,
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce lookup_credentials_callback_t *callback)
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce{
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce const char *lua_password, *lua_scheme;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce enum passdb_result result =
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce passdb_lua_lookup(request, &lua_scheme, &lua_password);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny passdb_handle_credentials(result, lua_password, lua_scheme, callback, request);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny}
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorcestatic void
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorcepassdb_lua_verify_plain(struct auth_request *request, const char *password,
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce verify_plain_callback_t *callback)
7fe69bb6ec70bce439c6b975a9a0044c98ff502bSimo Sorce{
7fe69bb6ec70bce439c6b975a9a0044c98ff502bSimo Sorce struct dlua_passdb_module *module =
7fe69bb6ec70bce439c6b975a9a0044c98ff502bSimo Sorce (struct dlua_passdb_module *)request->passdb->passdb;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny const char *lua_password, *lua_scheme;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny enum passdb_result result;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny if (module->has_password_verify) {
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce result = passdb_lua_verify_password(module, request, password);
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce } else {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny result = passdb_lua_lookup(request, &lua_scheme, &lua_password);
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce if (result == PASSDB_RESULT_OK) {
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce if ((auth_request_password_verify(request, password, lua_password,
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce lua_scheme, AUTH_SUBSYS_DB)) <=0) {
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce result = PASSDB_RESULT_PASSWORD_MISMATCH;
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce }
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny }
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose }
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose callback(result, request);
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose}
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorcestatic struct passdb_module *
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorcepassdb_lua_preinit(pool_t pool, const char *args)
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce{
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce struct dlua_passdb_module *module;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce bool blocking = TRUE;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce module = p_new(pool, struct dlua_passdb_module, 1);
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce const char *const *fields = t_strsplit_spaces(args, " ");
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce while(*fields != NULL) {
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce if (strncmp(*fields, "file=", 5) == 0) {
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce module->file = p_strdup(pool, (*fields)+5);
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce } else if (strncmp(*fields, "blocking=", 9) == 0) {
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce const char *value = (*fields)+9;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce if (strcmp(value, "yes") == 0) {
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce blocking = TRUE;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce } else if (strcmp(value, "no") == 0) {
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce blocking = FALSE;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce } else {
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce i_fatal("Invalid value %s. "
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce "Field blocking must be yes or no",
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce value);
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce }
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce } else {
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce i_fatal("Unsupported parameter %s", *fields);
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce }
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce fields++;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce }
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce if (module->file == NULL)
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce i_fatal("passdb-lua: Missing mandatory file= parameter");
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce module->module.blocking = blocking;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce return &module->module;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce}
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorcestatic void passdb_lua_init(struct passdb_module *_module)
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce{
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose struct dlua_passdb_module *module =
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose (struct dlua_passdb_module *)_module;
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose const char *error;
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose if (dlua_script_create_file(module->file, &module->script, &error) < 0 ||
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose auth_lua_script_init(module->script, &error) < 0)
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose i_fatal("passdb-lua: initialization failed: %s", error);
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose module->has_password_verify =
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose dlua_script_has_function(module->script, AUTH_LUA_PASSWORD_VERIFY);
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce}
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorcestatic void passdb_lua_deinit(struct passdb_module *_module)
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce{
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce struct dlua_passdb_module *module =
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose (struct dlua_passdb_module *)_module;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce dlua_script_unref(&module->script);
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce}
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce#ifndef PLUGIN_BUILD
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorcestruct passdb_module_interface passdb_lua =
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny#else
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zelenystruct passdb_module_interface passdb_lua_plugin =
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny#endif
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny{
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny "lua",
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny passdb_lua_preinit,
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny passdb_lua_init,
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny passdb_lua_deinit,
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce passdb_lua_verify_plain,
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny passdb_lua_lookup_credentials,
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny NULL
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny};
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny#else
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zelenystruct passdb_module_interface passdb_lua = {
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny .name = "lua"
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny};
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce#endif
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny