passdb-cache.c revision 31a12066e4cd9310d64091c81b59fb8eb1986023
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen/* Copyright (c) 2004-2012 Dovecot authors, see the included COPYING file */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "auth-common.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "restrict-process-size.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "password-scheme.h"
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen#include "passdb.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "passdb-cache.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include <stdlib.h>
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainenstruct auth_cache *passdb_cache = NULL;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic void
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenpassdb_cache_log_hit(struct auth_request *request, const char *value)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *p;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (!request->set->debug_passwords &&
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen *value != '\0' && *value != '\t') {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* hide the password */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen p = strchr(value, '\t');
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen value = t_strconcat(PASSWORD_HIDDEN_STR, p, NULL);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen auth_request_log_debug(request, "cache", "hit: %s", value);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenbool passdb_cache_verify_plain(struct auth_request *request, const char *key,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *password,
4d4d6d4745682790c20d759ba93dbea46b812c5dTimo Sirainen enum passdb_result *result_r, int use_expired)
4d4d6d4745682790c20d759ba93dbea46b812c5dTimo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const char *value, *cached_pw, *scheme, *const *list;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct auth_cache_node *node;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen int ret;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen bool expired, neg_expired;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (passdb_cache == NULL || key == NULL || request->master_user != NULL)
17fe695b985e9d6e9dc39c05b24e6b3c3b7e1ba1Timo Sirainen return FALSE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* value = password \t ... */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen value = auth_cache_lookup(passdb_cache, request, key, &node,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen &expired, &neg_expired);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (value == NULL || (expired && !use_expired)) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen auth_request_log_debug(request, "cache",
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen value == NULL ? "miss" : "expired");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return FALSE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen passdb_cache_log_hit(request, value);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (*value == '\0') {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* negative cache entry */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen auth_request_log_info(request, "cache", "User unknown");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen *result_r = PASSDB_RESULT_USER_UNKNOWN;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return TRUE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen list = t_strsplit(value, "\t");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen cached_pw = list[0];
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (*cached_pw == '\0') {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* NULL password */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen auth_request_log_info(request, "cache", "NULL password access");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ret = 1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen } else {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen scheme = password_get_scheme(&cached_pw);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_assert(scheme != NULL);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ret = auth_request_password_verify(request, password, cached_pw,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen scheme, "cache");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (ret == 0 && (node->last_success || neg_expired)) {
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen /* a) the last authentication was successful. assume
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen that the password was changed and cache is expired.
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen b) negative TTL reached, use it for password
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mismatches too. */
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen node->last_success = FALSE;
0c22bef8f5b35c645de8affd8746307fc53bd222Timo Sirainen return FALSE;
0c22bef8f5b35c645de8affd8746307fc53bd222Timo Sirainen }
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen }
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen node->last_success = ret > 0;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen /* save the extra_fields only after we know we're using the
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen cached data */
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen auth_request_set_fields(request, list + 1, NULL);
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen *result_r = ret > 0 ? PASSDB_RESULT_OK :
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen PASSDB_RESULT_PASSWORD_MISMATCH;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return TRUE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenbool passdb_cache_lookup_credentials(struct auth_request *request,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *key, const char **password_r,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char **scheme_r,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen enum passdb_result *result_r,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen bool use_expired)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *value, *const *list;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct auth_cache_node *node;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen bool expired, neg_expired;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (passdb_cache == NULL || request->master_user != NULL)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return FALSE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
01230de017cd273de41143d88e9c18df1243ae8aTimo Sirainen value = auth_cache_lookup(passdb_cache, request, key, &node,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen &expired, &neg_expired);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (value == NULL || (expired && !use_expired)) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen auth_request_log_debug(request, "cache",
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen value == NULL ? "miss" : "expired");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return FALSE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen passdb_cache_log_hit(request, value);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (*value == '\0') {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* negative cache entry */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen *result_r = PASSDB_RESULT_USER_UNKNOWN;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen *password_r = NULL;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen *scheme_r = NULL;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen return TRUE;
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen }
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen list = t_strsplit(value, "\t");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen auth_request_set_fields(request, list + 1, NULL);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen *result_r = PASSDB_RESULT_OK;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen *password_r = *list[0] == '\0' ? NULL : list[0];
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen *scheme_r = password_get_scheme(password_r);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_assert(*scheme_r != NULL || *password_r == NULL);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return TRUE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid passdb_cache_init(const struct auth_settings *set)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen rlim_t limit;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (set->cache_size == 0 || set->cache_ttl == 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (restrict_get_process_size(&limit) == 0 &&
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen set->cache_size > limit) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_warning("auth_cache_size (%luM) is higher than "
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "process VSZ limit (%luM)",
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen (unsigned long)(set->cache_size/1024/1024),
c6335901c67a4c9365319190a111a2168f3b06f5Timo Sirainen (unsigned long)(limit/1024/1024));
c6335901c67a4c9365319190a111a2168f3b06f5Timo Sirainen }
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen passdb_cache = auth_cache_new(set->cache_size, set->cache_ttl,
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen set->cache_negative_ttl);
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen}
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid passdb_cache_deinit(void)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (passdb_cache != NULL)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen auth_cache_free(&passdb_cache);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen