passdb-cache.c revision 25bfe4176b33935ccdbe94bfe26b181c52318e9d
e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen/* Copyright (C) 2004 Timo Sirainen */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "common.h"
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen#include "password-scheme.h"
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen#include "passdb.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "passdb-cache.h"
1dd875d96ab5640f78250079961c10e99ed4aa79Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen#include <stdlib.h>
ffd9a1898a18fadfc5dce399162c25d50548f905Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct auth_cache *passdb_cache = NULL;
89b548af722113acb5d63dfffb44423cb60f91e4Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainenstatic void list_save(struct auth_request *request, const char *password,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *const *list)
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct auth_request_extra *extra;
66ae183b6e895216037bd921367670f4b0665911Timo Sirainen const char *name, *value;
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen if (*list == NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return;
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen extra = auth_request_extra_begin(request, password);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (; *list != NULL; list++) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen t_push();
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen value = strchr(*list, '=');
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen if (value == NULL) {
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen name = *list;
46c31f64b9f0949f00b7819f45b22f2d64b2ea27Timo Sirainen value = "";
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen } else {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen name = t_strcut(*list, '=');
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen value++;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen auth_request_extra_next(extra, name, value);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen t_pop();
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen auth_request_extra_finish(extra, NULL);
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen}
8fa41238067c854435884c459963fde6f8c6436bTimo Sirainen
8fa41238067c854435884c459963fde6f8c6436bTimo Sirainenint passdb_cache_verify_plain(struct auth_request *request, const char *key,
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen const char *password, const char *default_scheme,
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen enum passdb_result *result_r)
46c31f64b9f0949f00b7819f45b22f2d64b2ea27Timo Sirainen{
46c31f64b9f0949f00b7819f45b22f2d64b2ea27Timo Sirainen const char *value, *cached_pw, *scheme, *const *list;
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen int ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(default_scheme != NULL);
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen if (passdb_cache == NULL)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen return FALSE;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
5aeb15e5817fbd4b1d8de540aa7673e3819a8030Timo Sirainen /* value = password \t ... */
5aeb15e5817fbd4b1d8de540aa7673e3819a8030Timo Sirainen value = auth_cache_lookup(passdb_cache, request, key);
41e1c7380edda701719d8ce1fb4d465d2ec4c84dTimo Sirainen if (value == NULL)
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen return FALSE;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen if (*value == '\0') {
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen /* negative cache entry */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen *result_r = PASSDB_RESULT_USER_UNKNOWN;
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen return TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen list = t_strsplit(value, "\t");
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen cached_pw = list[0];
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen scheme = password_get_scheme(&cached_pw);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen if (scheme == NULL)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen scheme = default_scheme;
9f32b9444d2a6db8f556d2c49ffceab1a59791ffTimo Sirainen list_save(request, password, list+1);
9f32b9444d2a6db8f556d2c49ffceab1a59791ffTimo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen ret = password_verify(password, cached_pw, scheme, request->user);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (ret < 0) {
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen i_error("cache(%s): Unknown password scheme %s",
648d24583c1574441c4fa0331a90bd4d6e7996c5Timo Sirainen get_log_prefix(request), scheme);
648d24583c1574441c4fa0331a90bd4d6e7996c5Timo Sirainen } else if (ret == 0) {
ee246b46953e4b94b2f22e093373674fa9155500Timo Sirainen if (verbose) {
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen i_info("cache(%s): Password mismatch",
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen get_log_prefix(request));
46c31f64b9f0949f00b7819f45b22f2d64b2ea27Timo Sirainen }
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen }
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *result_r = ret > 0 ? PASSDB_RESULT_OK :
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen PASSDB_RESULT_PASSWORD_MISMATCH;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint passdb_cache_lookup_credentials(struct auth_request *request,
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen const char *key, const char **result_r,
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen const char **scheme_r)
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen{
80fc743146da5130de34174cdaad2576f103723fTimo Sirainen const char *value, *const *list;
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen if (passdb_cache == NULL)
80fc743146da5130de34174cdaad2576f103723fTimo Sirainen return FALSE;
80fc743146da5130de34174cdaad2576f103723fTimo Sirainen
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen value = auth_cache_lookup(passdb_cache, request, key);
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen if (value == NULL)
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen return FALSE;
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen if (*value == '\0') {
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen /* negative cache entry */
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen *result_r = NULL;
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen *scheme_r = NULL;
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen return TRUE;
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen }
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen list = t_strsplit(value, "\t");
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen list_save(request, NULL, list+1);
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen *result_r = list[0];
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen *scheme_r = password_get_scheme(result_r);
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen return TRUE;
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen}
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainenvoid passdb_cache_init(void)
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen{
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen const char *env;
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen size_t max_size;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen unsigned int cache_ttl;
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen env = getenv("CACHE_SIZE");
d161e3c2cde2bd8d5917840f68823a2259ed426eTimo Sirainen if (env == NULL)
ffd9a1898a18fadfc5dce399162c25d50548f905Timo Sirainen return;
ffd9a1898a18fadfc5dce399162c25d50548f905Timo Sirainen
1e923fcf497665fe071a154c31fb452766b0b2deTimo Sirainen max_size = (size_t)strtoul(env, NULL, 10) * 1024;
d161e3c2cde2bd8d5917840f68823a2259ed426eTimo Sirainen if (max_size == 0)
1e923fcf497665fe071a154c31fb452766b0b2deTimo Sirainen return;
d161e3c2cde2bd8d5917840f68823a2259ed426eTimo Sirainen
d161e3c2cde2bd8d5917840f68823a2259ed426eTimo Sirainen env = getenv("CACHE_TTL");
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen if (env == NULL)
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen return;
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen cache_ttl = (unsigned int)strtoul(env, NULL, 10);
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen if (cache_ttl == 0)
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen return;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen passdb_cache = auth_cache_new(max_size, cache_ttl);
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen}
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainenvoid passdb_cache_deinit(void)
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen{
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen if (passdb_cache != NULL)
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen auth_cache_free(passdb_cache);
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen}
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen