passdb-cache.c revision a64adf62fa33f2463a86f990217b0c9078531a40
45312f52ff3a3d4c137447be4c7556500c2f8bf2Timo Sirainen/* Copyright (c) 2004-2009 Dovecot authors, see the included COPYING file */
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen#include "common.h"
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen#include "password-scheme.h"
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen#include "passdb.h"
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen#include "passdb-cache.h"
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen#include <stdlib.h>
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainenstruct auth_cache *passdb_cache = NULL;
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen
7ace5117d5f2395bd66f20b09e77dac05492f7ceTimo Sirainenstatic void
7ace5117d5f2395bd66f20b09e77dac05492f7ceTimo Sirainenpassdb_cache_log_hit(struct auth_request *request, const char *value)
7ace5117d5f2395bd66f20b09e77dac05492f7ceTimo Sirainen{
7ace5117d5f2395bd66f20b09e77dac05492f7ceTimo Sirainen const char *p;
7ace5117d5f2395bd66f20b09e77dac05492f7ceTimo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (!request->auth->set->debug_passwords &&
7ace5117d5f2395bd66f20b09e77dac05492f7ceTimo Sirainen *value != '\0' && *value != '\t') {
7ace5117d5f2395bd66f20b09e77dac05492f7ceTimo Sirainen /* hide the password */
7ace5117d5f2395bd66f20b09e77dac05492f7ceTimo Sirainen p = strchr(value, '\t');
7ace5117d5f2395bd66f20b09e77dac05492f7ceTimo Sirainen value = t_strconcat("<hidden>", p, NULL);
7ace5117d5f2395bd66f20b09e77dac05492f7ceTimo Sirainen }
7ace5117d5f2395bd66f20b09e77dac05492f7ceTimo Sirainen auth_request_log_debug(request, "cache", "hit: %s", value);
7ace5117d5f2395bd66f20b09e77dac05492f7ceTimo Sirainen}
7ace5117d5f2395bd66f20b09e77dac05492f7ceTimo Sirainen
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenbool passdb_cache_verify_plain(struct auth_request *request, const char *key,
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen const char *password,
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen enum passdb_result *result_r, int use_expired)
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen{
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen const char *value, *cached_pw, *scheme, *const *list;
8759adc67109b5a12a7af3ed717c7040622a0a04Timo Sirainen struct auth_cache_node *node;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen int ret;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen bool expired;
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen
0549732db3a80a0821f42648be2666e74f6b35c5Timo Sirainen if (passdb_cache == NULL || key == NULL)
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen return FALSE;
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen /* value = password \t ... */
8759adc67109b5a12a7af3ed717c7040622a0a04Timo Sirainen value = auth_cache_lookup(passdb_cache, request, key, &node, &expired);
00bde9ae9eab9e720462bf6ec9a4dd85e88c3bbfTimo Sirainen if (value == NULL || (expired && !use_expired)) {
00bde9ae9eab9e720462bf6ec9a4dd85e88c3bbfTimo Sirainen auth_request_log_debug(request, "cache",
00bde9ae9eab9e720462bf6ec9a4dd85e88c3bbfTimo Sirainen value == NULL ? "miss" : "expired");
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen return FALSE;
00bde9ae9eab9e720462bf6ec9a4dd85e88c3bbfTimo Sirainen }
7ace5117d5f2395bd66f20b09e77dac05492f7ceTimo Sirainen passdb_cache_log_hit(request, value);
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen if (*value == '\0') {
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen /* negative cache entry */
bcf5f1acb2e3891f951fd0848c23b86c35efe7e1Timo Sirainen auth_request_log_info(request, "cache", "User unknown");
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen *result_r = PASSDB_RESULT_USER_UNKNOWN;
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen return TRUE;
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen }
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen list = t_strsplit(value, "\t");
3ab7783791bd46cdd46e9b9de3e98e8efcb6c6bfTimo Sirainen
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen cached_pw = list[0];
3ab7783791bd46cdd46e9b9de3e98e8efcb6c6bfTimo Sirainen if (*cached_pw == '\0') {
3ab7783791bd46cdd46e9b9de3e98e8efcb6c6bfTimo Sirainen /* NULL password */
bcf5f1acb2e3891f951fd0848c23b86c35efe7e1Timo Sirainen auth_request_log_info(request, "cache", "NULL password access");
24d7c5fc9fa1cb1f49402ec796654113199ba4e6Timo Sirainen ret = 1;
24d7c5fc9fa1cb1f49402ec796654113199ba4e6Timo Sirainen } else {
24d7c5fc9fa1cb1f49402ec796654113199ba4e6Timo Sirainen scheme = password_get_scheme(&cached_pw);
24d7c5fc9fa1cb1f49402ec796654113199ba4e6Timo Sirainen i_assert(scheme != NULL);
24d7c5fc9fa1cb1f49402ec796654113199ba4e6Timo Sirainen
24d7c5fc9fa1cb1f49402ec796654113199ba4e6Timo Sirainen ret = auth_request_password_verify(request, password, cached_pw,
24d7c5fc9fa1cb1f49402ec796654113199ba4e6Timo Sirainen scheme, "cache");
24d7c5fc9fa1cb1f49402ec796654113199ba4e6Timo Sirainen
24d7c5fc9fa1cb1f49402ec796654113199ba4e6Timo Sirainen if (ret == 0 && node->last_success) {
24d7c5fc9fa1cb1f49402ec796654113199ba4e6Timo Sirainen /* the last authentication was successful. assume that
24d7c5fc9fa1cb1f49402ec796654113199ba4e6Timo Sirainen the password was changed and cache is expired. */
24d7c5fc9fa1cb1f49402ec796654113199ba4e6Timo Sirainen node->last_success = FALSE;
24d7c5fc9fa1cb1f49402ec796654113199ba4e6Timo Sirainen return FALSE;
24d7c5fc9fa1cb1f49402ec796654113199ba4e6Timo Sirainen }
8759adc67109b5a12a7af3ed717c7040622a0a04Timo Sirainen }
8759adc67109b5a12a7af3ed717c7040622a0a04Timo Sirainen node->last_success = ret > 0;
8759adc67109b5a12a7af3ed717c7040622a0a04Timo Sirainen
24d7c5fc9fa1cb1f49402ec796654113199ba4e6Timo Sirainen /* save the extra_fields only after we know we're using the
24d7c5fc9fa1cb1f49402ec796654113199ba4e6Timo Sirainen cached data */
553308791c097219e8eb31cbd03a29e9e1333848Timo Sirainen auth_request_set_fields(request, list + 1, NULL);
24d7c5fc9fa1cb1f49402ec796654113199ba4e6Timo Sirainen
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen *result_r = ret > 0 ? PASSDB_RESULT_OK :
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen PASSDB_RESULT_PASSWORD_MISMATCH;
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen return TRUE;
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen}
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenbool passdb_cache_lookup_credentials(struct auth_request *request,
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen const char *key, const char **password_r,
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen const char **scheme_r,
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen enum passdb_result *result_r,
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen bool use_expired)
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen{
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen const char *value, *const *list;
8759adc67109b5a12a7af3ed717c7040622a0a04Timo Sirainen struct auth_cache_node *node;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen bool expired;
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen if (passdb_cache == NULL)
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen return FALSE;
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen
8759adc67109b5a12a7af3ed717c7040622a0a04Timo Sirainen value = auth_cache_lookup(passdb_cache, request, key, &node, &expired);
00bde9ae9eab9e720462bf6ec9a4dd85e88c3bbfTimo Sirainen if (value == NULL || (expired && !use_expired)) {
00bde9ae9eab9e720462bf6ec9a4dd85e88c3bbfTimo Sirainen auth_request_log_debug(request, "cache",
00bde9ae9eab9e720462bf6ec9a4dd85e88c3bbfTimo Sirainen value == NULL ? "miss" : "expired");
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen return FALSE;
00bde9ae9eab9e720462bf6ec9a4dd85e88c3bbfTimo Sirainen }
7ace5117d5f2395bd66f20b09e77dac05492f7ceTimo Sirainen passdb_cache_log_hit(request, value);
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen if (*value == '\0') {
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen /* negative cache entry */
a3dd97fb6d92a89c3de0597fed2d4b044c7aeb84Timo Sirainen *result_r = PASSDB_RESULT_USER_UNKNOWN;
a3dd97fb6d92a89c3de0597fed2d4b044c7aeb84Timo Sirainen *password_r = NULL;
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen *scheme_r = NULL;
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen return TRUE;
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen }
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen list = t_strsplit(value, "\t");
553308791c097219e8eb31cbd03a29e9e1333848Timo Sirainen auth_request_set_fields(request, list + 1, NULL);
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen
a3dd97fb6d92a89c3de0597fed2d4b044c7aeb84Timo Sirainen *result_r = PASSDB_RESULT_OK;
a3dd97fb6d92a89c3de0597fed2d4b044c7aeb84Timo Sirainen *password_r = list[0];
a3dd97fb6d92a89c3de0597fed2d4b044c7aeb84Timo Sirainen *scheme_r = password_get_scheme(password_r);
cc0495b3bbe3c3e41c512274b302d6f0fa028187Timo Sirainen i_assert(*scheme_r != NULL || *password_r == NULL);
0b47a03ce89751b2c04b03da255ba68b796864a7Timo Sirainen
cc0495b3bbe3c3e41c512274b302d6f0fa028187Timo Sirainen if (*password_r == NULL)
0b47a03ce89751b2c04b03da255ba68b796864a7Timo Sirainen *result_r = PASSDB_RESULT_SCHEME_NOT_AVAILABLE;
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen return TRUE;
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen}
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenvoid passdb_cache_init(const struct auth_settings *set)
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen{
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (set->cache_size == 0 || set->cache_ttl == 0)
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen return;
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen passdb_cache = auth_cache_new(set->cache_size * 1024UL, set->cache_ttl,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen set->cache_negative_ttl);
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen}
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainenvoid passdb_cache_deinit(void)
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen{
8ef7c24178fd798c3e0301c5b8afa1a9bdedd27fTimo Sirainen if (passdb_cache != NULL)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen auth_cache_free(&passdb_cache);
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen}