user-directory.c revision 27006b32276426acf449bd0ea7a35ed19389ae6b
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2010-2017 Dovecot authors, see the included COPYING file */
c2cda8cd0043443566efc5da30f79865508a1947Timo Sirainen/* n% of timeout_secs */
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen/* but min/max. of this many secs */
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen/* This shouldn't matter what it is exactly, just try it sometimes later. */
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen /* unsigned int username_hash => user */
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen /* sorted by time */
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen /* If user's expire time is less than this many seconds away,
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen don't assume that other directors haven't yet expired it */
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainenstatic void user_move_iters(struct user_directory *dir, struct user *user)
b3fc5293379feb3640b23622bcc8f5f8d7f1e81dJosef 'Jeff' Sipekstatic void user_free(struct user_directory *dir, struct user *user)
5a1b498b646b5c5dbd1b3f3861df766f560578c5Timo Sirainen hash_table_remove(dir->hash, POINTER_CAST(user->username_hash));
204ee6ed414f5e4eeb6f6c10763b55daf56f11acJosef 'Jeff' Sipek DLLIST2_REMOVE(&dir->head, &dir->tail, user);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic bool user_directory_user_has_connections(struct user_directory *dir,
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen time_t expire_timestamp = user->timestamp + dir->timeout_secs;
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen /* don't free this user until the kill is finished */
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen if (expire_timestamp + USER_NEAR_EXPIRING_MAX > ioloop_time) {
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen i_warning("User %u weakness appears to be stuck, removing it",
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainenstatic void user_directory_drop_expired(struct user_directory *dir)
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen !user_directory_user_has_connections(dir, dir->head, &expire_timestamp)) {
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen i_assert(expire_timestamp > ioloop_time || expire_timestamp == 0);
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen if (expire_timestamp != dir->to_expire_timestamp) {
5af5137f6dc0c9f358b7813e941e26f7bd735b3aTimo Sirainen struct timeval tv = { .tv_sec = expire_timestamp };
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainenunsigned int user_directory_count(struct user_directory *dir)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstruct user *user_directory_lookup(struct user_directory *dir,
71aed7ba87b5fd5e96e97a22d89ac025b883d60aTimo Sirainen user = hash_table_lookup(dir->hash, POINTER_CAST(username_hash));
71aed7ba87b5fd5e96e97a22d89ac025b883d60aTimo Sirainen if (user != NULL && !user_directory_user_has_connections(dir, user, &expire_timestamp)) {
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainenuser_directory_insert_backwards(struct user_directory *dir,
463f6ea04af934a68facaca0ff089bc306de3f98Timo Sirainen DLLIST2_PREPEND(&dir->head, &dir->tail, user);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainenuser_directory_insert_forwards(struct user_directory *dir,
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainenuser_directory_add(struct user_directory *dir, unsigned int username_hash,
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen /* make sure we don't add timestamps higher than ioloop time */
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen if (dir->tail == NULL || (time_t)dir->tail->timestamp <= timestamp)
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen /* need to insert to correct position. we should get here
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen only when handshaking. the handshaking USER requests should
e4c81823af1fc43ca3f2ce9eb4af7fc8f57b13a5Timo Sirainen come sorted by timestamp. so keep track of the previous
e4c81823af1fc43ca3f2ce9eb4af7fc8f57b13a5Timo Sirainen insert position, the next USER should be inserted after
e4c81823af1fc43ca3f2ce9eb4af7fc8f57b13a5Timo Sirainen /* find the position starting from tail */
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen user_directory_insert_backwards(dir, dir->tail, user);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen } else if (timestamp < (time_t)dir->prev_insert_pos->timestamp) {
fb502495e9306fe51e9d2c0019e622a98e9803abTimo Sirainen user_directory_insert_backwards(dir, dir->prev_insert_pos,
fb502495e9306fe51e9d2c0019e622a98e9803abTimo Sirainen user_directory_insert_forwards(dir, dir->prev_insert_pos,
c2cda8cd0043443566efc5da30f79865508a1947Timo Sirainen struct timeval tv = { .tv_sec = ioloop_time + dir->timeout_secs };
c2cda8cd0043443566efc5da30f79865508a1947Timo Sirainen dir->to_expire = timeout_add_absolute(&tv, user_directory_drop_expired, dir);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen hash_table_insert(dir->hash, POINTER_CAST(user->username_hash), user);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainenvoid user_directory_refresh(struct user_directory *dir, struct user *user)
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainenvoid user_directory_remove_host(struct user_directory *dir,
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen for (user = dir->head; user != NULL; user = next) {
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainenstatic int user_timestamp_cmp(struct user *const *user1,
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen if ((*user1)->timestamp < (*user2)->timestamp)
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen if ((*user1)->timestamp > (*user2)->timestamp)
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenvoid user_directory_sort(struct user_directory *dir)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen unsigned int i, users_count = hash_table_count(dir->hash);
463f6ea04af934a68facaca0ff089bc306de3f98Timo Sirainen /* place all users into array and sort it */
463f6ea04af934a68facaca0ff089bc306de3f98Timo Sirainen for (i = 0; i < users_count; i++, user = user->next)
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* recreate the linked list */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen DLLIST2_APPEND(&dir->head, &dir->tail, *userp);
52041ed691a26ca80e4e805765e9f55ec097c8f1Martti Rannanjärvi dir->head->timestamp <= dir->tail->timestamp);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenbool user_directory_user_is_recently_updated(struct user_directory *dir,
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen return (time_t)(user->timestamp + dir->timeout_secs/2) >= ioloop_time;
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainenbool user_directory_user_is_near_expiring(struct user_directory *dir,
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen (dir->timeout_secs - dir->user_near_expiring_secs);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen i_assert(timeout_secs > USER_NEAR_EXPIRING_MIN);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen timeout_secs * USER_NEAR_EXPIRING_PERCENTAGE / 100;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen I_MIN(dir->user_near_expiring_secs, USER_NEAR_EXPIRING_MAX);
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen I_MAX(dir->user_near_expiring_secs, USER_NEAR_EXPIRING_MIN);
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen i_assert(dir->timeout_secs/2 > dir->user_near_expiring_secs);
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen hash_table_create_direct(&dir->hash, default_pool, 0);
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainenvoid user_directory_deinit(struct user_directory **_dir)
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainenuser_directory_iter_init(struct user_directory *dir)
52041ed691a26ca80e4e805765e9f55ec097c8f1Martti Rannanjärvi iter = i_new(struct user_directory_iter, 1);
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainenstruct user *user_directory_iter_next(struct user_directory_iter *iter)
a85c629c5d75a5fd9489ba14d5d4f54f3cddd591Aki Tuomivoid user_directory_iter_deinit(struct user_directory_iter **_iter)
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen unsigned int i, count;
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen for (i = 0; i < count; i++) {