auth-cache.c revision 5f5870385cff47efd2f58e7892f251cf13761528
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2004-2012 Dovecot authors, see the included COPYING file */
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen
08d6658a4e2ec8104cd1307f6baa75fdb07a24f8Mark Washenberger#include "auth-common.h"
019a610a5ce14a80f6b017f94829933664879021Timo Sirainen#include "lib-signals.h"
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen#include "hash.h"
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen#include "str.h"
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen#include "strescape.h"
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen#include "var-expand.h"
e80203675151ef9d4f3f850cf02041042eb13096Timo Sirainen#include "auth-request.h"
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen#include "auth-cache.h"
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen#include <time.h>
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainenstruct auth_cache {
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen struct hash_table *hash;
8759adc67109b5a12a7af3ed717c7040622a0a04Timo Sirainen struct auth_cache_node *head, *tail;
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen size_t size_left;
b522f391ef6aa4e527f2eeb5f7daa3da188790b0Timo Sirainen unsigned int ttl_secs, neg_ttl_secs;
078aac578d08e348836c53939782afb10479def5Timo Sirainen
078aac578d08e348836c53939782afb10479def5Timo Sirainen unsigned int hit_count, miss_count;
20df5a94b36be8e6c2d0e481973cab6715c61bb8Timo Sirainen unsigned int pos_entries, neg_entries;
20df5a94b36be8e6c2d0e481973cab6715c61bb8Timo Sirainen unsigned long long pos_size, neg_size;
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen};
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen
12a34eb68607d0f8c7c3dc973ee605e89d44ba30Timo Sirainenchar *auth_cache_parse_key(pool_t pool, const char *query)
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen{
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen string_t *str;
4e21cef121b8ad20439ccbcb4e9072c208f08611Timo Sirainen char key_seen[256];
ee3cb11d230d549367a1213aefe4598345796256Timo Sirainen uint8_t key;
4e21cef121b8ad20439ccbcb4e9072c208f08611Timo Sirainen
4e21cef121b8ad20439ccbcb4e9072c208f08611Timo Sirainen memset(key_seen, 0, sizeof(key_seen));
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen
12a34eb68607d0f8c7c3dc973ee605e89d44ba30Timo Sirainen str = str_new(pool, 32);
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen for (; *query != '\0'; query++) {
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen if (*query == '%' && query[1] != '\0') {
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen query++;
ee3cb11d230d549367a1213aefe4598345796256Timo Sirainen key = var_get_key(query);
ee3cb11d230d549367a1213aefe4598345796256Timo Sirainen if (key != '\0' && key != '%' && !key_seen[key]) {
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen if (str_len(str) != 0)
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen str_append_c(str, '\t');
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen str_append_c(str, '%');
ee3cb11d230d549367a1213aefe4598345796256Timo Sirainen str_append_c(str, key);
4e21cef121b8ad20439ccbcb4e9072c208f08611Timo Sirainen
4e21cef121b8ad20439ccbcb4e9072c208f08611Timo Sirainen /* @UNSAFE */
ee3cb11d230d549367a1213aefe4598345796256Timo Sirainen key_seen[key] = 1;
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen }
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen }
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen }
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen return str_free_without_data(&str);
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen}
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainenstatic void
8759adc67109b5a12a7af3ed717c7040622a0a04Timo Sirainenauth_cache_node_unlink(struct auth_cache *cache, struct auth_cache_node *node)
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen{
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen if (node->prev != NULL)
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen node->prev->next = node->next;
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen else {
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen /* unlinking tail */
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen cache->tail = node->next;
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen }
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen if (node->next != NULL)
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen node->next->prev = node->prev;
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen else {
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen /* unlinking head */
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen cache->head = node->prev;
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen }
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen}
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainenstatic void
8759adc67109b5a12a7af3ed717c7040622a0a04Timo Sirainenauth_cache_node_link_head(struct auth_cache *cache,
8759adc67109b5a12a7af3ed717c7040622a0a04Timo Sirainen struct auth_cache_node *node)
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen{
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen node->prev = cache->head;
5d2e422f9971ca9f0ad77508c1e7c315546e2765Timo Sirainen node->next = NULL;
5d2e422f9971ca9f0ad77508c1e7c315546e2765Timo Sirainen
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen cache->head = node;
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen if (node->prev != NULL)
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen node->prev->next = node;
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen else
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen cache->tail = node;
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen}
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainenstatic void
8759adc67109b5a12a7af3ed717c7040622a0a04Timo Sirainenauth_cache_node_destroy(struct auth_cache *cache, struct auth_cache_node *node)
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen{
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen auth_cache_node_unlink(cache, node);
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen cache->size_left += node->alloc_size;
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen hash_table_remove(cache->hash, node->data);
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen i_free(node);
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen}
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen
1c7fa51b35231f375998f66d5756f214519218f8Timo Sirainenstatic void sig_auth_cache_clear(const siginfo_t *si ATTR_UNUSED, void *context)
321221ddc2dedc4ad79839770765adc40d311a0dTimo Sirainen{
321221ddc2dedc4ad79839770765adc40d311a0dTimo Sirainen struct auth_cache *cache = context;
321221ddc2dedc4ad79839770765adc40d311a0dTimo Sirainen
321221ddc2dedc4ad79839770765adc40d311a0dTimo Sirainen i_info("SIGHUP received, clearing cache");
321221ddc2dedc4ad79839770765adc40d311a0dTimo Sirainen auth_cache_clear(cache);
321221ddc2dedc4ad79839770765adc40d311a0dTimo Sirainen}
321221ddc2dedc4ad79839770765adc40d311a0dTimo Sirainen
1c7fa51b35231f375998f66d5756f214519218f8Timo Sirainenstatic void sig_auth_cache_stats(const siginfo_t *si ATTR_UNUSED, void *context)
321221ddc2dedc4ad79839770765adc40d311a0dTimo Sirainen{
321221ddc2dedc4ad79839770765adc40d311a0dTimo Sirainen struct auth_cache *cache = context;
321221ddc2dedc4ad79839770765adc40d311a0dTimo Sirainen unsigned int total_count;
321221ddc2dedc4ad79839770765adc40d311a0dTimo Sirainen
321221ddc2dedc4ad79839770765adc40d311a0dTimo Sirainen total_count = cache->hit_count + cache->miss_count;
321221ddc2dedc4ad79839770765adc40d311a0dTimo Sirainen i_info("Authentication cache hits %u/%u (%u%%)",
321221ddc2dedc4ad79839770765adc40d311a0dTimo Sirainen cache->hit_count, total_count,
cdc7e0c3492f8b68699e4d19f0c96ba67f880e48Timo Sirainen total_count == 0 ? 100 : (cache->hit_count * 100 / total_count));
321221ddc2dedc4ad79839770765adc40d311a0dTimo Sirainen
20df5a94b36be8e6c2d0e481973cab6715c61bb8Timo Sirainen i_info("Authentication cache inserts: "
20df5a94b36be8e6c2d0e481973cab6715c61bb8Timo Sirainen "positive: %u %lluB, negative: %u %lluB",
20df5a94b36be8e6c2d0e481973cab6715c61bb8Timo Sirainen cache->pos_entries, cache->pos_size,
20df5a94b36be8e6c2d0e481973cab6715c61bb8Timo Sirainen cache->neg_entries, cache->neg_size);
20df5a94b36be8e6c2d0e481973cab6715c61bb8Timo Sirainen
20df5a94b36be8e6c2d0e481973cab6715c61bb8Timo Sirainen /* reset counters */
321221ddc2dedc4ad79839770765adc40d311a0dTimo Sirainen cache->hit_count = cache->miss_count = 0;
20df5a94b36be8e6c2d0e481973cab6715c61bb8Timo Sirainen cache->pos_entries = cache->neg_entries = 0;
20df5a94b36be8e6c2d0e481973cab6715c61bb8Timo Sirainen cache->pos_size = cache->neg_size = 0;
321221ddc2dedc4ad79839770765adc40d311a0dTimo Sirainen}
321221ddc2dedc4ad79839770765adc40d311a0dTimo Sirainen
b522f391ef6aa4e527f2eeb5f7daa3da188790b0Timo Sirainenstruct auth_cache *auth_cache_new(size_t max_size, unsigned int ttl_secs,
b522f391ef6aa4e527f2eeb5f7daa3da188790b0Timo Sirainen unsigned int neg_ttl_secs
b522f391ef6aa4e527f2eeb5f7daa3da188790b0Timo Sirainen)
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen{
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen struct auth_cache *cache;
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen cache = i_new(struct auth_cache, 1);
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen cache->hash = hash_table_create(default_pool, default_pool, 0, str_hash,
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen (hash_cmp_callback_t *)strcmp);
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen cache->size_left = max_size;
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen cache->ttl_secs = ttl_secs;
b522f391ef6aa4e527f2eeb5f7daa3da188790b0Timo Sirainen cache->neg_ttl_secs = neg_ttl_secs;
321221ddc2dedc4ad79839770765adc40d311a0dTimo Sirainen
5512d420d826a2f9d4e7cb4e4919e1864fe688b0Timo Sirainen lib_signals_set_handler(SIGHUP, LIBSIG_FLAGS_SAFE,
5512d420d826a2f9d4e7cb4e4919e1864fe688b0Timo Sirainen sig_auth_cache_clear, cache);
5512d420d826a2f9d4e7cb4e4919e1864fe688b0Timo Sirainen lib_signals_set_handler(SIGUSR2, LIBSIG_FLAGS_SAFE,
5512d420d826a2f9d4e7cb4e4919e1864fe688b0Timo Sirainen sig_auth_cache_stats, cache);
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen return cache;
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen}
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainenvoid auth_cache_free(struct auth_cache **_cache)
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen{
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen struct auth_cache *cache = *_cache;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen *_cache = NULL;
321221ddc2dedc4ad79839770765adc40d311a0dTimo Sirainen lib_signals_unset_handler(SIGHUP, sig_auth_cache_clear, cache);
321221ddc2dedc4ad79839770765adc40d311a0dTimo Sirainen lib_signals_unset_handler(SIGUSR2, sig_auth_cache_stats, cache);
321221ddc2dedc4ad79839770765adc40d311a0dTimo Sirainen
321221ddc2dedc4ad79839770765adc40d311a0dTimo Sirainen auth_cache_clear(cache);
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen hash_table_destroy(&cache->hash);
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen i_free(cache);
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen}
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainenvoid auth_cache_clear(struct auth_cache *cache)
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen{
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen while (cache->tail != NULL)
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen auth_cache_node_destroy(cache, cache->tail);
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen hash_table_clear(cache->hash, FALSE);
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen}
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen
8759adc67109b5a12a7af3ed717c7040622a0a04Timo Sirainenconst char *
8759adc67109b5a12a7af3ed717c7040622a0a04Timo Sirainenauth_cache_lookup(struct auth_cache *cache, const struct auth_request *request,
8759adc67109b5a12a7af3ed717c7040622a0a04Timo Sirainen const char *key, struct auth_cache_node **node_r,
145d2eef238ed8bbff635e3b06951a83f0ee5a03Timo Sirainen bool *expired_r, bool *neg_expired_r)
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen{
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen string_t *str;
8759adc67109b5a12a7af3ed717c7040622a0a04Timo Sirainen struct auth_cache_node *node;
b522f391ef6aa4e527f2eeb5f7daa3da188790b0Timo Sirainen const char *value;
b522f391ef6aa4e527f2eeb5f7daa3da188790b0Timo Sirainen unsigned int ttl_secs;
145d2eef238ed8bbff635e3b06951a83f0ee5a03Timo Sirainen time_t now;
019a610a5ce14a80f6b017f94829933664879021Timo Sirainen
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen *expired_r = FALSE;
145d2eef238ed8bbff635e3b06951a83f0ee5a03Timo Sirainen *neg_expired_r = FALSE;
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen
3e077925c47a7a18d5f7f266179f5f82862bf81eTimo Sirainen /* %! is prepended automatically. it contains the passdb ID number. */
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen str = t_str_new(256);
c5383a0ed56a188a7d5efaaa4c6f8243af432d65Timo Sirainen var_expand(str, t_strconcat(request->userdb_lookup ? "U" : "P",
c5383a0ed56a188a7d5efaaa4c6f8243af432d65Timo Sirainen "%!/", key, NULL),
b229f116305761bc5784cc9c9c47d4498d339263Timo Sirainen auth_request_get_var_expand_table(request, NULL));
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen node = hash_table_lookup(cache->hash, str_c(str));
078aac578d08e348836c53939782afb10479def5Timo Sirainen if (node == NULL) {
078aac578d08e348836c53939782afb10479def5Timo Sirainen cache->miss_count++;
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen return NULL;
078aac578d08e348836c53939782afb10479def5Timo Sirainen }
078aac578d08e348836c53939782afb10479def5Timo Sirainen cache->hit_count++;
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen
b522f391ef6aa4e527f2eeb5f7daa3da188790b0Timo Sirainen value = node->data + strlen(node->data) + 1;
b522f391ef6aa4e527f2eeb5f7daa3da188790b0Timo Sirainen ttl_secs = *value == '\0' ? cache->neg_ttl_secs : cache->ttl_secs;
b522f391ef6aa4e527f2eeb5f7daa3da188790b0Timo Sirainen
145d2eef238ed8bbff635e3b06951a83f0ee5a03Timo Sirainen now = time(NULL);
145d2eef238ed8bbff635e3b06951a83f0ee5a03Timo Sirainen if (node->created < now - (time_t)ttl_secs) {
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen /* TTL expired */
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen *expired_r = TRUE;
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen } else {
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen /* move to head */
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen if (node != cache->head) {
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen auth_cache_node_unlink(cache, node);
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen auth_cache_node_link_head(cache, node);
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen }
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen }
145d2eef238ed8bbff635e3b06951a83f0ee5a03Timo Sirainen if (node->created < now - (time_t)cache->neg_ttl_secs)
145d2eef238ed8bbff635e3b06951a83f0ee5a03Timo Sirainen *neg_expired_r = TRUE;
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen
8759adc67109b5a12a7af3ed717c7040622a0a04Timo Sirainen if (node_r != NULL)
8759adc67109b5a12a7af3ed717c7040622a0a04Timo Sirainen *node_r = node;
8759adc67109b5a12a7af3ed717c7040622a0a04Timo Sirainen
b522f391ef6aa4e527f2eeb5f7daa3da188790b0Timo Sirainen return value;
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen}
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen
814b1e8e301bf58cc03ddf35a380b43c581af4dfTimo Sirainenvoid auth_cache_insert(struct auth_cache *cache, struct auth_request *request,
8759adc67109b5a12a7af3ed717c7040622a0a04Timo Sirainen const char *key, const char *value, bool last_success)
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen{
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen string_t *str;
8759adc67109b5a12a7af3ed717c7040622a0a04Timo Sirainen struct auth_cache_node *node;
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen size_t data_size, alloc_size, value_len = strlen(value);
814b1e8e301bf58cc03ddf35a380b43c581af4dfTimo Sirainen char *current_username;
814b1e8e301bf58cc03ddf35a380b43c581af4dfTimo Sirainen
b522f391ef6aa4e527f2eeb5f7daa3da188790b0Timo Sirainen if (*value == '\0' && cache->neg_ttl_secs == 0) {
b522f391ef6aa4e527f2eeb5f7daa3da188790b0Timo Sirainen /* we're not caching negative entries */
b522f391ef6aa4e527f2eeb5f7daa3da188790b0Timo Sirainen return;
b522f391ef6aa4e527f2eeb5f7daa3da188790b0Timo Sirainen }
b522f391ef6aa4e527f2eeb5f7daa3da188790b0Timo Sirainen
d24a5c09373ec890da5736882c1756aa7fa651ebTimo Sirainen /* store into cache using the translated username, except if we're doing
814b1e8e301bf58cc03ddf35a380b43c581af4dfTimo Sirainen a master user login */
814b1e8e301bf58cc03ddf35a380b43c581af4dfTimo Sirainen current_username = request->user;
d24a5c09373ec890da5736882c1756aa7fa651ebTimo Sirainen if (request->translated_username != NULL &&
814b1e8e301bf58cc03ddf35a380b43c581af4dfTimo Sirainen request->requested_login_user == NULL)
d24a5c09373ec890da5736882c1756aa7fa651ebTimo Sirainen request->user = t_strdup_noconst(request->translated_username);
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen
c5383a0ed56a188a7d5efaaa4c6f8243af432d65Timo Sirainen /* %! is prepended automatically. it contains the db ID number. */
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen str = t_str_new(256);
c5383a0ed56a188a7d5efaaa4c6f8243af432d65Timo Sirainen var_expand(str, t_strconcat(request->userdb_lookup ? "U" : "P",
c5383a0ed56a188a7d5efaaa4c6f8243af432d65Timo Sirainen "%!/", key, NULL),
b229f116305761bc5784cc9c9c47d4498d339263Timo Sirainen auth_request_get_var_expand_table(request, NULL));
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen
814b1e8e301bf58cc03ddf35a380b43c581af4dfTimo Sirainen request->user = current_username;
814b1e8e301bf58cc03ddf35a380b43c581af4dfTimo Sirainen
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen data_size = str_len(str) + 1 + value_len + 1;
8759adc67109b5a12a7af3ed717c7040622a0a04Timo Sirainen alloc_size = sizeof(struct auth_cache_node) -
8759adc67109b5a12a7af3ed717c7040622a0a04Timo Sirainen sizeof(node->data) + data_size;
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen /* make sure we have enough space */
1e50a4f930a028ab5fcf690503bfd13b54ff6787Timo Sirainen while (cache->size_left < alloc_size && cache->tail != NULL)
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen auth_cache_node_destroy(cache, cache->tail);
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen node = hash_table_lookup(cache->hash, str_c(str));
e361b5386c77ee25685b5ad2bd2519a077dea882Timo Sirainen if (node != NULL) {
e361b5386c77ee25685b5ad2bd2519a077dea882Timo Sirainen /* key is already in cache (probably expired), remove it */
e361b5386c77ee25685b5ad2bd2519a077dea882Timo Sirainen auth_cache_node_destroy(cache, node);
e361b5386c77ee25685b5ad2bd2519a077dea882Timo Sirainen }
e361b5386c77ee25685b5ad2bd2519a077dea882Timo Sirainen
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen /* @UNSAFE */
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen node = i_malloc(alloc_size);
e361b5386c77ee25685b5ad2bd2519a077dea882Timo Sirainen node->created = time(NULL);
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen node->alloc_size = alloc_size;
8759adc67109b5a12a7af3ed717c7040622a0a04Timo Sirainen node->last_success = last_success;
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen memcpy(node->data, str_data(str), str_len(str));
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen memcpy(node->data + str_len(str) + 1, value, value_len);
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen auth_cache_node_link_head(cache, node);
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen cache->size_left -= alloc_size;
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen hash_table_insert(cache->hash, node->data, node);
20df5a94b36be8e6c2d0e481973cab6715c61bb8Timo Sirainen
20df5a94b36be8e6c2d0e481973cab6715c61bb8Timo Sirainen if (*value != '\0') {
20df5a94b36be8e6c2d0e481973cab6715c61bb8Timo Sirainen cache->pos_entries++;
20df5a94b36be8e6c2d0e481973cab6715c61bb8Timo Sirainen cache->pos_size += alloc_size;
20df5a94b36be8e6c2d0e481973cab6715c61bb8Timo Sirainen } else {
20df5a94b36be8e6c2d0e481973cab6715c61bb8Timo Sirainen cache->neg_entries++;
20df5a94b36be8e6c2d0e481973cab6715c61bb8Timo Sirainen cache->neg_size += alloc_size;
20df5a94b36be8e6c2d0e481973cab6715c61bb8Timo Sirainen }
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen}
121221dd2970a6f5ec601abb3b1c505c238e0b60Timo Sirainen
121221dd2970a6f5ec601abb3b1c505c238e0b60Timo Sirainenvoid auth_cache_remove(struct auth_cache *cache,
121221dd2970a6f5ec601abb3b1c505c238e0b60Timo Sirainen const struct auth_request *request,
121221dd2970a6f5ec601abb3b1c505c238e0b60Timo Sirainen const char *key)
121221dd2970a6f5ec601abb3b1c505c238e0b60Timo Sirainen{
121221dd2970a6f5ec601abb3b1c505c238e0b60Timo Sirainen string_t *str;
121221dd2970a6f5ec601abb3b1c505c238e0b60Timo Sirainen struct auth_cache_node *node;
121221dd2970a6f5ec601abb3b1c505c238e0b60Timo Sirainen
121221dd2970a6f5ec601abb3b1c505c238e0b60Timo Sirainen str = t_str_new(256);
121221dd2970a6f5ec601abb3b1c505c238e0b60Timo Sirainen var_expand(str, key,
b229f116305761bc5784cc9c9c47d4498d339263Timo Sirainen auth_request_get_var_expand_table(request, NULL));
121221dd2970a6f5ec601abb3b1c505c238e0b60Timo Sirainen
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen node = hash_table_lookup(cache->hash, str_c(str));
121221dd2970a6f5ec601abb3b1c505c238e0b60Timo Sirainen if (node == NULL)
121221dd2970a6f5ec601abb3b1c505c238e0b60Timo Sirainen return;
121221dd2970a6f5ec601abb3b1c505c238e0b60Timo Sirainen
121221dd2970a6f5ec601abb3b1c505c238e0b60Timo Sirainen auth_cache_node_destroy(cache, node);
121221dd2970a6f5ec601abb3b1c505c238e0b60Timo Sirainen}