From: Timo Sirainen Date: Fri, 14 Feb 2025 08:41:01 +0000 (+0200) Subject: auth: lua - Passdb/userdb lookups can no longer return a single string on success X-Git-Tag: 2.4.1~182 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=104d14cfa5c4e6e9f87e52656046bf5d1da8a8fc;p=thirdparty%2Fdovecot%2Fcore.git auth: lua - Passdb/userdb lookups can no longer return a single string on success The second return value must be either a table or nil. Returning a single string was a bit unsafe since its values could accidentally become expanded to spaces, causing unsafe behavior. If the first return value indicates an error, the second can still be a string. --- diff --git a/src/auth/db-lua.c b/src/auth/db-lua.c index 057661bd15..591d76c5da 100644 --- a/src/auth/db-lua.c +++ b/src/auth/db-lua.c @@ -371,10 +371,10 @@ static void auth_lua_dovecot_auth_register(lua_State *L) lua_pop(L, 1); } -static int auth_lua_call_lookup(lua_State *L, const char *fn, +static int auth_lua_call_lookup(lua_State *L, const char *fn, int ret_success, struct auth_request *req, const char **error_r) { - int err = 0; + int ret, err = 0; e_debug(authdb_event(req), "Calling %s", fn); @@ -388,11 +388,22 @@ static int auth_lua_call_lookup(lua_State *L, const char *fn, "(expected number got %s)", fn, luaL_typename(L, -2)); err = -1; - } else if (!lua_isstring(L, -1) && !lua_istable(L, -1) && !lua_isnil(L, -1)) { - *error_r = t_strdup_printf("db-lua: %s(req) invalid return value " - "(expected nil, string or table, got %s)", - fn, luaL_typename(L, -1)); - err = -1; + } else if ((ret = lua_tointeger(L, -2)) != ret_success) { + if (!lua_isstring(L, -1) && !lua_isnil(L, -1)) { + *error_r = t_strdup_printf( + "db-lua: %s(req) invalid error return value " + "(expected nil or string, got %s)", + fn, luaL_typename(L, -1)); + err = -1; + } + } else { + if (!lua_istable(L, -1) && !lua_isnil(L, -1)) { + *error_r = t_strdup_printf( + "db-lua: %s(req) invalid return value " + "(expected nil or table, got %s)", + fn, luaL_typename(L, -1)); + err = -1; + } } if (err != 0) { @@ -483,38 +494,17 @@ auth_lua_script_get_default_cache_key(const struct auth_lua_script_parameters *p return 0; } -static void -auth_lua_export_fields(struct auth_request *req, - const char *str, - const char **scheme_r, const char **password_r) -{ - const char *const *fields = t_strsplit_spaces(str, " "); - while(*fields != NULL) { - const char *value = strchr(*fields, '='); - const char *key; - - if (value == NULL) { - key = *fields; - value = ""; - } else { - key = t_strdup_until(*fields, value++); - } - - if (password_r != NULL && strcmp(key, "password") == 0) { - *scheme_r = password_get_scheme(&value); - *password_r = value; - } else if (req->userdb_lookup) { - auth_request_set_userdb_field(req, key, value); - } else { - auth_request_set_field(req, key, value, STATIC_PASS_SCHEME); - } - fields++; - } -} - static void auth_lua_export_table(lua_State *L, struct auth_request *req, const char **scheme_r, const char **password_r) { + if (lua_isnil(L, -1)) { + lua_pop(L, 2); + lua_gc(L, LUA_GCCOLLECT, 0); + i_assert(lua_gettop(L) == 0); + return; + } + i_assert(lua_istable(L, -1)); + lua_pushvalue(L, -1); lua_pushnil(L); while (lua_next(L, -2) != 0) { @@ -584,9 +574,12 @@ auth_lua_export_userdb_table(lua_State *L, struct auth_request *req, enum userdb_result ret = lua_tointeger(L, -2); if (ret != USERDB_RESULT_OK) { + if (lua_isnil(L, -1)) + *error_r = "userdb failed"; + else + *error_r = t_strdup(lua_tostring(L, -1)); lua_pop(L, 2); lua_gc(L, LUA_GCCOLLECT, 0); - *error_r = "userdb failed"; return ret; } @@ -602,9 +595,12 @@ auth_lua_export_passdb_table(lua_State *L, struct auth_request *req, enum passdb_result ret = lua_tointeger(L, -2); if (ret != PASSDB_RESULT_OK) { + if (lua_isnil(L, -1)) + *error_r = "passdb failed"; + else + *error_r = t_strdup(lua_tostring(L, -1)); lua_pop(L, 2); lua_gc(L, LUA_GCCOLLECT, 0); - *error_r = "passb failed"; return ret; } @@ -612,40 +608,12 @@ auth_lua_export_passdb_table(lua_State *L, struct auth_request *req, return PASSDB_RESULT_OK; } -static enum passdb_result -auth_lua_call_lookup_finish(lua_State *L, struct auth_request *req, - const char **scheme_r, const char **password_r, - const char **error_r) -{ - if (lua_istable(L, -1)) { - return auth_lua_export_passdb_table(L, req, scheme_r, - password_r, error_r); - } - - enum passdb_result ret = lua_tointeger(L, -2); - const char *str = t_strdup(lua_tostring(L, -1)); - lua_pop(L, 2); - lua_gc(L, LUA_GCCOLLECT, 0); - /* stack should be empty now */ - i_assert(lua_gettop(L) == 0); - - if (ret != PASSDB_RESULT_OK && ret != PASSDB_RESULT_NEXT) { - *error_r = str; - } else if (str != NULL) { - auth_lua_export_fields(req, str, scheme_r, password_r); - } - - if (scheme_r != NULL && *scheme_r == NULL) - *scheme_r = "PLAIN"; - - return ret; -} - enum passdb_result auth_lua_call_password_verify(struct dlua_script *script, struct auth_request *req, const char *password, const char **error_r) { lua_State *L = script->L; + enum passdb_result ret; int err = 0; e_debug(authdb_event(req), "Calling %s", AUTH_LUA_PASSWORD_VERIFY); @@ -663,12 +631,22 @@ auth_lua_call_password_verify(struct dlua_script *script, AUTH_LUA_PASSWORD_VERIFY, luaL_typename(L, -2)); err = -1; - } else if (!lua_isstring(L, -1) && !lua_istable(L, -1) && !lua_isnil(L, -1)) { - *error_r = t_strdup_printf("db-lua: %s invalid return value " - "(expected nil, string or table, got %s)", - AUTH_LUA_PASSWORD_VERIFY, - luaL_typename(L, -1)); - err = -1; + } else if ((ret = lua_tointeger(L, -2)) != PASSDB_RESULT_OK) { + if (!lua_isstring(L, -1) && !lua_isnil(L, -1)) { + *error_r = t_strdup_printf( + "db-lua: %s invalid error return value " + "(expected nil or string, got %s)", + AUTH_LUA_PASSWORD_VERIFY, luaL_typename(L, -1)); + err = -1; + } + } else { + if (!lua_istable(L, -1) && !lua_isnil(L, -1)) { + *error_r = t_strdup_printf( + "db-lua: %s invalid return value " + "(expected nil or table, got %s)", + AUTH_LUA_PASSWORD_VERIFY, luaL_typename(L, -1)); + err = -1; + } } if (err != 0) { @@ -678,8 +656,7 @@ auth_lua_call_password_verify(struct dlua_script *script, return PASSDB_RESULT_INTERNAL_FAILURE; } - - return auth_lua_call_lookup_finish(L, req, NULL, NULL, error_r); + return auth_lua_export_passdb_table(L, req, NULL, NULL, error_r); } @@ -691,13 +668,15 @@ auth_lua_call_passdb_lookup(struct dlua_script *script, lua_State *L = script->L; *scheme_r = *password_r = NULL; - if (auth_lua_call_lookup(L, AUTH_LUA_PASSDB_LOOKUP, req, error_r) < 0) { + if (auth_lua_call_lookup(L, AUTH_LUA_PASSDB_LOOKUP, PASSDB_RESULT_OK, + req, error_r) < 0) { lua_gc(L, LUA_GCCOLLECT, 0); i_assert(lua_gettop(L) == 0); return PASSDB_RESULT_INTERNAL_FAILURE; } - return auth_lua_call_lookup_finish(L, req, scheme_r, password_r, error_r); + return auth_lua_export_passdb_table(L, req, scheme_r, password_r, + error_r); } @@ -707,29 +686,14 @@ auth_lua_call_userdb_lookup(struct dlua_script *script, { lua_State *L = script->L; - if (auth_lua_call_lookup(L, AUTH_LUA_USERDB_LOOKUP, req, error_r) < 0) { + if (auth_lua_call_lookup(L, AUTH_LUA_USERDB_LOOKUP, USERDB_RESULT_OK, + req, error_r) < 0) { lua_gc(L, LUA_GCCOLLECT, 0); i_assert(lua_gettop(L) == 0); return USERDB_RESULT_INTERNAL_FAILURE; } - if (lua_istable(L, -1)) - return auth_lua_export_userdb_table(L, req, error_r); - - enum userdb_result ret = lua_tointeger(L, -2); - const char *str = t_strdup(lua_tostring(L, -1)); - lua_pop(L, 2); - lua_gc(L, LUA_GCCOLLECT, 0); - i_assert(lua_gettop(L) == 0); - - if (ret != USERDB_RESULT_OK) { - *error_r = str; - return ret; - } - if (str != NULL) - auth_lua_export_fields(req, str, NULL, NULL); - - return USERDB_RESULT_OK; + return auth_lua_export_userdb_table(L, req, error_r); } struct userdb_iterate_context *