auth-cache.c revision 5f5870385cff47efd2f58e7892f251cf13761528
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2004-2012 Dovecot authors, see the included COPYING file */
12a34eb68607d0f8c7c3dc973ee605e89d44ba30Timo Sirainenchar *auth_cache_parse_key(pool_t pool, const char *query)
ee3cb11d230d549367a1213aefe4598345796256Timo Sirainen if (key != '\0' && key != '%' && !key_seen[key]) {
4e21cef121b8ad20439ccbcb4e9072c208f08611Timo Sirainen /* @UNSAFE */
8759adc67109b5a12a7af3ed717c7040622a0a04Timo Sirainenauth_cache_node_unlink(struct auth_cache *cache, struct auth_cache_node *node)
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen /* unlinking tail */
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen /* unlinking head */
8759adc67109b5a12a7af3ed717c7040622a0a04Timo Sirainenauth_cache_node_link_head(struct auth_cache *cache,
8759adc67109b5a12a7af3ed717c7040622a0a04Timo Sirainenauth_cache_node_destroy(struct auth_cache *cache, struct auth_cache_node *node)
1c7fa51b35231f375998f66d5756f214519218f8Timo Sirainenstatic void sig_auth_cache_clear(const siginfo_t *si ATTR_UNUSED, void *context)
1c7fa51b35231f375998f66d5756f214519218f8Timo Sirainenstatic void sig_auth_cache_stats(const siginfo_t *si ATTR_UNUSED, void *context)
321221ddc2dedc4ad79839770765adc40d311a0dTimo Sirainen total_count = cache->hit_count + cache->miss_count;
321221ddc2dedc4ad79839770765adc40d311a0dTimo Sirainen i_info("Authentication cache hits %u/%u (%u%%)",
cdc7e0c3492f8b68699e4d19f0c96ba67f880e48Timo Sirainen total_count == 0 ? 100 : (cache->hit_count * 100 / total_count));
20df5a94b36be8e6c2d0e481973cab6715c61bb8Timo Sirainen "positive: %u %lluB, negative: %u %lluB",
20df5a94b36be8e6c2d0e481973cab6715c61bb8Timo Sirainen /* reset counters */
b522f391ef6aa4e527f2eeb5f7daa3da188790b0Timo Sirainenstruct auth_cache *auth_cache_new(size_t max_size, unsigned int ttl_secs,
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen cache->hash = hash_table_create(default_pool, default_pool, 0, str_hash,
5512d420d826a2f9d4e7cb4e4919e1864fe688b0Timo Sirainen lib_signals_set_handler(SIGHUP, LIBSIG_FLAGS_SAFE,
5512d420d826a2f9d4e7cb4e4919e1864fe688b0Timo Sirainen lib_signals_set_handler(SIGUSR2, LIBSIG_FLAGS_SAFE,
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainenvoid auth_cache_free(struct auth_cache **_cache)
321221ddc2dedc4ad79839770765adc40d311a0dTimo Sirainen lib_signals_unset_handler(SIGHUP, sig_auth_cache_clear, cache);
321221ddc2dedc4ad79839770765adc40d311a0dTimo Sirainen lib_signals_unset_handler(SIGUSR2, sig_auth_cache_stats, cache);
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainenvoid auth_cache_clear(struct auth_cache *cache)
8759adc67109b5a12a7af3ed717c7040622a0a04Timo Sirainenauth_cache_lookup(struct auth_cache *cache, const struct auth_request *request,
8759adc67109b5a12a7af3ed717c7040622a0a04Timo Sirainen const char *key, struct auth_cache_node **node_r,
3e077925c47a7a18d5f7f266179f5f82862bf81eTimo Sirainen /* %! is prepended automatically. it contains the passdb ID number. */
c5383a0ed56a188a7d5efaaa4c6f8243af432d65Timo Sirainen var_expand(str, t_strconcat(request->userdb_lookup ? "U" : "P",
b229f116305761bc5784cc9c9c47d4498d339263Timo Sirainen auth_request_get_var_expand_table(request, NULL));
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen node = hash_table_lookup(cache->hash, str_c(str));
b522f391ef6aa4e527f2eeb5f7daa3da188790b0Timo Sirainen ttl_secs = *value == '\0' ? cache->neg_ttl_secs : cache->ttl_secs;
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen /* TTL expired */
42061dd44f742de25d0a52ed1ef766a56df421f1Timo Sirainen /* move to head */
145d2eef238ed8bbff635e3b06951a83f0ee5a03Timo Sirainen if (node->created < now - (time_t)cache->neg_ttl_secs)
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 size_t data_size, alloc_size, value_len = strlen(value);
b522f391ef6aa4e527f2eeb5f7daa3da188790b0Timo Sirainen if (*value == '\0' && cache->neg_ttl_secs == 0) {
b522f391ef6aa4e527f2eeb5f7daa3da188790b0Timo Sirainen /* we're not caching negative entries */
d24a5c09373ec890da5736882c1756aa7fa651ebTimo Sirainen /* store into cache using the translated username, except if we're doing
814b1e8e301bf58cc03ddf35a380b43c581af4dfTimo Sirainen a master user login */
d24a5c09373ec890da5736882c1756aa7fa651ebTimo Sirainen request->user = t_strdup_noconst(request->translated_username);
c5383a0ed56a188a7d5efaaa4c6f8243af432d65Timo Sirainen /* %! is prepended automatically. it contains the db ID number. */
c5383a0ed56a188a7d5efaaa4c6f8243af432d65Timo Sirainen var_expand(str, t_strconcat(request->userdb_lookup ? "U" : "P",
b229f116305761bc5784cc9c9c47d4498d339263Timo Sirainen auth_request_get_var_expand_table(request, NULL));
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen /* make sure we have enough space */
1e50a4f930a028ab5fcf690503bfd13b54ff6787Timo Sirainen while (cache->size_left < alloc_size && cache->tail != NULL)
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen node = hash_table_lookup(cache->hash, str_c(str));
e361b5386c77ee25685b5ad2bd2519a077dea882Timo Sirainen /* key is already in cache (probably expired), remove it */
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen /* @UNSAFE */
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen memcpy(node->data, str_data(str), str_len(str));
dc9bfb7dc057964238e181d3d8b08751527bb08aTimo Sirainen memcpy(node->data + str_len(str) + 1, value, value_len);
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen hash_table_insert(cache->hash, node->data, node);
121221dd2970a6f5ec601abb3b1c505c238e0b60Timo Sirainenvoid auth_cache_remove(struct auth_cache *cache,
121221dd2970a6f5ec601abb3b1c505c238e0b60Timo Sirainen const char *key)
b229f116305761bc5784cc9c9c47d4498d339263Timo Sirainen auth_request_get_var_expand_table(request, NULL));