auth-request-handler.c revision 533929e773388b28e0932fb5cfbdf455def58fe6
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2005-2011 Dovecot authors, see the included COPYING file */
2872c818f9c6704609f4d67d984b033a63e3a108Timo Sirainenstatic ARRAY_DEFINE(auth_failures_arr, struct auth_request *);
2872c818f9c6704609f4d67d984b033a63e3a108Timo Sirainenstatic void auth_failure_timeout(void *context);
9be4e6701d086c009f3db1913a148139ea180420Timo Sirainenauth_request_handler_create(auth_request_callback_t *callback, void *context,
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen pool = pool_alloconly_create("auth request handler", 4096);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen handler = p_new(pool, struct auth_request_handler, 1);
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen handler->requests = hash_table_create(default_pool, pool, 0, NULL, NULL);
a7e2c98560cf54dc656711a237cb07da8a5a9ee4Timo Sirainenauth_request_handler_get_request_count(struct auth_request_handler *handler)
9d75363d3fbabc2fbc2d80f06672e3ed8965804aTimo Sirainenvoid auth_request_handler_abort_requests(struct auth_request_handler *handler)
f19cf95ae8fc233567b1c7751595eb66876d684aTimo Sirainen iter = hash_table_iterate_init(handler->requests);
f19cf95ae8fc233567b1c7751595eb66876d684aTimo Sirainen while (hash_table_iterate(iter, &key, &value)) {
cc4d0d30fbba883d5d1b600646491fb77bdb989cTimo Sirainen /* can't abort a pending passdb/userdb lookup */
9d75363d3fbabc2fbc2d80f06672e3ed8965804aTimo Sirainenvoid auth_request_handler_unref(struct auth_request_handler **_handler)
fbee9bffb56d882b98146dd0de76a5bcccc2bdc3Timo Sirainen struct auth_request_handler *handler = *_handler;
9d75363d3fbabc2fbc2d80f06672e3ed8965804aTimo Sirainen i_assert(hash_table_count(handler->requests) == 0);
9d75363d3fbabc2fbc2d80f06672e3ed8965804aTimo Sirainen /* notify parent that we're done with all requests */
5363f51ad46344f4e5952f2fef211a7cf8f95ddcTimo Sirainenvoid auth_request_handler_destroy(struct auth_request_handler **_handler)
5363f51ad46344f4e5952f2fef211a7cf8f95ddcTimo Sirainen struct auth_request_handler *handler = *_handler;
70905e51a5148bd5613cb04720807177474a2496Timo Sirainenvoid auth_request_handler_set(struct auth_request_handler *handler,
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainenstatic void auth_request_handler_remove(struct auth_request_handler *handler,
ea95a057fa5f02d50027122cacd3147fce7679faTimo Sirainen /* already removed it */
e69e7b734b625de1f8921b7e0d92afa1df6b900dTimo Sirainen /* if db lookup is stuck, this call doesn't actually free the auth
e69e7b734b625de1f8921b7e0d92afa1df6b900dTimo Sirainen request, so make sure we don't get back here. */
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen hash_table_remove(handler->requests, POINTER_CAST(request->id));
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainenstatic void get_client_extra_fields(struct auth_request *request,
8bb360f9e5de1c25e4f875205bb06e8bf15dae14Timo Sirainen unsigned int src;
bbf81c8fc6f21382707673dc6bd7b87ffc27981bTimo Sirainen if (auth_stream_is_empty(request->extra_fields))
bbf81c8fc6f21382707673dc6bd7b87ffc27981bTimo Sirainen extra_fields = auth_stream_reply_export(request->extra_fields);
aefe17424820c57bcb05b0aaec4a930e8222baccTimo Sirainen /* we only wish to remove all fields prefixed with "userdb_" */
aefe17424820c57bcb05b0aaec4a930e8222baccTimo Sirainen if (strstr(extra_fields, "userdb_") == NULL) {
aefe17424820c57bcb05b0aaec4a930e8222baccTimo Sirainen auth_stream_reply_import(reply, extra_fields);
662a9000b1788f1cdf765e6b1c89df9a42cc3e32Timo Sirainen if (strncmp(fields[src], "userdb_", 7) != 0) {
662a9000b1788f1cdf765e6b1c89df9a42cc3e32Timo Sirainen if (!seen_pass && strncmp(fields[src], "pass=", 5) == 0)
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen /* we're proxying */
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen if (!seen_pass && request->mech_password != NULL) {
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen /* send back the password that was sent by user
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen (not the password in passdb). */
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen /* the master username needs to be forwarded */
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainenauth_request_handle_failure(struct auth_request *request,
2872c818f9c6704609f4d67d984b033a63e3a108Timo Sirainen struct auth_request_handler *handler = request->handler;
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen /* we came here from flush_failures() */
2872c818f9c6704609f4d67d984b033a63e3a108Timo Sirainen /* remove the request from requests-list */
2872c818f9c6704609f4d67d984b033a63e3a108Timo Sirainen auth_request_handler_remove(handler, request);
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen /* passdb specifically requested not to delay the reply. */
2872c818f9c6704609f4d67d984b033a63e3a108Timo Sirainen /* failure. don't announce it immediately to avoid
2872c818f9c6704609f4d67d984b033a63e3a108Timo Sirainen a) timing attacks, b) flooding */
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainenvoid auth_request_handler_reply(struct auth_request *request,
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen struct auth_request_handler *handler = request->handler;
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen /* the client connection was already closed. we can't do
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen anything but abort this request */
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen /* make sure this request is set to finished state
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen (it's not with result=continue) */
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen auth_request_set_state(request, AUTH_REQUEST_STATE_FINISHED);
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen reply = auth_stream_reply_init(pool_datastack_create());
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen auth_stream_reply_add(reply, NULL, dec2str(request->id));
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen str = t_str_new(MAX_BASE64_ENCODED_SIZE(reply_size));
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen auth_stream_reply_add(reply, NULL, str_c(str));
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen if (request->last_penalty != 0 && auth_penalty != NULL) {
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen /* reset penalty */
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen auth_penalty_update(auth_penalty, request, 0);
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen auth_stream_reply_add(reply, NULL, dec2str(request->id));
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen auth_stream_reply_add(reply, "user", request->user);
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen str = t_str_new(MAX_BASE64_ENCODED_SIZE(reply_size));
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen auth_stream_reply_add(reply, "resp", str_c(str));
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen if (request->no_login || handler->master_callback == NULL) {
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen /* this request doesn't have to wait for master
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen process to pick it up. delete it */
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen auth_request_handler_remove(handler, request);
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen auth_stream_reply_add(reply, NULL, dec2str(request->id));
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen auth_stream_reply_add(reply, "user", request->user);
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen else if (request->original_username != NULL) {
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen /* authentication succeeded, but we can't log in
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen as the wanted user */
5363f51ad46344f4e5952f2fef211a7cf8f95ddcTimo Sirainen auth_stream_reply_add(reply, "nodelay", NULL);
e8a96ad5c10e9d5c0c4e2e88dd09a38fdb3e34b4Timo Sirainen /* NOTE: request may be destroyed now */
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainenvoid auth_request_handler_reply_continue(struct auth_request *request,
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen auth_request_handler_reply(request, AUTH_CLIENT_RESULT_CONTINUE,
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainenstatic void auth_request_handler_auth_fail(struct auth_request_handler *handler,
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen auth_request_log_info(request, request->mech->mech_name, "%s", reason);
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen reply = auth_stream_reply_init(pool_datastack_create());
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen auth_stream_reply_add(reply, NULL, dec2str(request->id));
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen auth_stream_reply_add(reply, "reason", reason);
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen auth_request_handler_remove(handler, request);
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainenstatic void auth_request_timeout(struct auth_request *request)
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen const char *str;
91233a89f0060f95542ed661683e5d99a50f1778Timo Sirainen str = t_strdup_printf("Request %u.%u timeouted after %u secs, state=%d",
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen (unsigned int)(time(NULL) - request->last_access),
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen if (request->state != AUTH_REQUEST_STATE_MECH_CONTINUE) {
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen /* client's fault */
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_request_log_error(request, request->mech->mech_name,
50782de8a9d5ebe11ee61496b4e695a1d3875230Timo Sirainen auth_request_log_info(request, request->mech->mech_name,
50782de8a9d5ebe11ee61496b4e695a1d3875230Timo Sirainen auth_request_handler_remove(request->handler, request);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainenstatic void auth_request_penalty_finish(struct auth_request *request)
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainenauth_penalty_callback(unsigned int penalty, struct auth_request *request)
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen unsigned int secs;
48ac75465ae154b1d705f18de6d95045ab714b65Timo Sirainen request->to_penalty = timeout_add(secs * 1000,
a72dde3805d0e9148de4caf44d6f4dc167431380Timo Sirainenbool auth_request_handler_auth_begin(struct auth_request_handler *handler,
a72dde3805d0e9148de4caf44d6f4dc167431380Timo Sirainen const char *const *list, *name, *arg, *initial_resp;
a72dde3805d0e9148de4caf44d6f4dc167431380Timo Sirainen unsigned int id;
48ac75465ae154b1d705f18de6d95045ab714b65Timo Sirainen /* <id> <mechanism> [...] */
e76073ebaf90fa29abfdc364873acf78983949aaTimo Sirainen "sent broken AUTH request", handler->client_pid);
e76073ebaf90fa29abfdc364873acf78983949aaTimo Sirainen /* unsupported mechanism */
e76073ebaf90fa29abfdc364873acf78983949aaTimo Sirainen i_error("BUG: Authentication client %u requested unsupported "
e76073ebaf90fa29abfdc364873acf78983949aaTimo Sirainen "authentication mechanism %s", handler->client_pid,
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen /* parse optional parameters */
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen if (auth_request_import_auth(request, name, arg))
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen /* this must be the last parameter */
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen "sent AUTH parameters after 'resp'",
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen "didn't specify service in request",
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen if (hash_table_lookup(handler->requests, POINTER_CAST(id)) != NULL) {
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen "sent a duplicate ID %u", handler->client_pid, id);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen request->to_abort = timeout_add(MASTER_AUTH_SERVER_TIMEOUT_SECS * 1000,
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen hash_table_insert(handler->requests, POINTER_CAST(id), request);
382c7aec3e3449ed8271c2a202b67cefaa31dc8eTimo Sirainen /* we fail without valid certificate */
382c7aec3e3449ed8271c2a202b67cefaa31dc8eTimo Sirainen auth_request_handler_auth_fail(handler, request,
382c7aec3e3449ed8271c2a202b67cefaa31dc8eTimo Sirainen "Client didn't present valid SSL certificate");
382c7aec3e3449ed8271c2a202b67cefaa31dc8eTimo Sirainen /* Empty initial response is a "=" base64 string. Completely empty
382c7aec3e3449ed8271c2a202b67cefaa31dc8eTimo Sirainen string shouldn't really be sent, but at least Exim does it,
382c7aec3e3449ed8271c2a202b67cefaa31dc8eTimo Sirainen so just allow it for backwards compatibility.. */
382c7aec3e3449ed8271c2a202b67cefaa31dc8eTimo Sirainen if (initial_resp != NULL && *initial_resp != '\0') {
382c7aec3e3449ed8271c2a202b67cefaa31dc8eTimo Sirainen buf = buffer_create_dynamic(pool_datastack_create(),
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen if (base64_decode(initial_resp, len, NULL, buf) < 0) {
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_request_handler_auth_fail(handler, request,
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen "Invalid base64 data in initial response");
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen memcpy(initial_resp_data, buf->data, buf->used);
b5322c8270616a28f2e65cb3a09580c410bb0941Timo Sirainen request->initial_response = initial_resp_data;
b5322c8270616a28f2e65cb3a09580c410bb0941Timo Sirainen /* handler is referenced until auth_request_handler_reply()
b5322c8270616a28f2e65cb3a09580c410bb0941Timo Sirainen is called. */
d99107ddf4d9bccb710994482daf65276a9d6321Timo Sirainen /* before we start authenticating, see if we need to wait first */
48ac75465ae154b1d705f18de6d95045ab714b65Timo Sirainen auth_penalty_lookup(auth_penalty, request, auth_penalty_callback);
258ff7d4f03dd9d29eca3664e4acacdf7f528234Timo Sirainenbool auth_request_handler_auth_continue(struct auth_request_handler *handler,
4f2248a8a70985c7295afc3bf91c848e81d740d9Timo Sirainen unsigned int id;
e76073ebaf90fa29abfdc364873acf78983949aaTimo Sirainen if (data == NULL || str_to_uint(t_strdup_until(args, data), &id) < 0) {
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen i_error("BUG: Authentication client sent broken CONT request");
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen request = hash_table_lookup(handler->requests, POINTER_CAST(id));
e76073ebaf90fa29abfdc364873acf78983949aaTimo Sirainen reply = auth_stream_reply_init(pool_datastack_create());
e76073ebaf90fa29abfdc364873acf78983949aaTimo Sirainen auth_stream_reply_add(reply, NULL, dec2str(id));
e76073ebaf90fa29abfdc364873acf78983949aaTimo Sirainen "Authentication request timed out");
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen /* accept input only once after mechanism has sent a CONT reply */
e76073ebaf90fa29abfdc364873acf78983949aaTimo Sirainen auth_request_handler_auth_fail(handler, request,
2c8ff32886e56a5e037169c9ebef4219f85a5629Timo Sirainen "Unexpected continuation");
657afb33796f8216c568ad813627da89970760beTimo Sirainen buf = buffer_create_dynamic(pool_datastack_create(),
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen if (base64_decode(data, data_len, NULL, buf) < 0) {
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_request_handler_auth_fail(handler, request,
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen "Invalid base64 data in continued response");
c53a3c54d388c0031aaa642e6b14d46eb86d9485Timo Sirainen /* handler is referenced until auth_request_handler_reply()
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen is called. */
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_request_continue(request, buf->data, buf->used);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainenstatic void userdb_callback(enum userdb_result result,
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen struct auth_request_handler *handler = request->handler;
cac6735a6cd73f2b815a1f3c1e21855075e7c81eTimo Sirainen i_assert(request->state == AUTH_REQUEST_STATE_USERDB);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_request_set_state(request, AUTH_REQUEST_STATE_FINISHED);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen reply = auth_stream_reply_init(pool_datastack_create());
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_stream_reply_add(reply, NULL, dec2str(request->id));
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen value = auth_stream_reply_find(request->userdb_reply,
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_stream_reply_add(reply, "reason", value);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_stream_reply_add(reply, "NOTFOUND", NULL);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_stream_reply_add(reply, NULL, dec2str(request->id));
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_stream_reply_add(reply, NULL, dec2str(request->id));
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen "master_user",
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen if (*request->set->anonymous_username != '\0' &&
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen /* this is an anonymous login, either via ANONYMOUS
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen SASL mechanism or simply logging in as the anonymous
401b0787fff2dc986a5321ddb32acb1947ff66b0Timo Sirainen user via another mechanism */
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen auth_stream_reply_export(request->userdb_reply));
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen handler->master_callback(reply, request->master);
3313a51ef9b245248d672c20f930c52a577a42f7Timo Sirainen auth_master_connection_unref(&request->master);
3313a51ef9b245248d672c20f930c52a577a42f7Timo Sirainenbool auth_request_handler_master_request(struct auth_request_handler *handler,
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen unsigned int id,
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen reply = auth_stream_reply_init(pool_datastack_create());
533929e773388b28e0932fb5cfbdf455def58fe6Timo Sirainen request = hash_table_lookup(handler->requests, POINTER_CAST(client_id));
7e078be0d6f12ca56860641d36e3c517e3046895Timo Sirainen auth_stream_reply_add(reply, NULL, dec2str(id));
e8e966468f2667c18ec3f0a22ee48f01fa3a6eeaTimo Sirainen auth_request_handler_remove(handler, request);
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen if (request->state != AUTH_REQUEST_STATE_FINISHED ||
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen i_error("Master requested unfinished authentication request "
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_stream_reply_add(reply, NULL, dec2str(id));
657afb33796f8216c568ad813627da89970760beTimo Sirainen /* the request isn't being referenced anywhere anymore,
657afb33796f8216c568ad813627da89970760beTimo Sirainen so we can do a bit of kludging.. replace the request's
daa7e7459749ae8f82cd3eed9c44522d81c609a3Timo Sirainen old client_id with master's id. */
ad49932dae8ba31e07544b66bbc4f4de707a751cTimo Sirainen auth_request_set_state(request, AUTH_REQUEST_STATE_USERDB);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen /* master and handler are referenced until userdb_callback i
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_request_lookup_user(request, userdb_callback);
647eed98cb795ee9e42911750402dab720b57514Timo Sirainenvoid auth_request_handler_cancel_request(struct auth_request_handler *handler,
daa7e7459749ae8f82cd3eed9c44522d81c609a3Timo Sirainen request = hash_table_lookup(handler->requests, POINTER_CAST(client_id));
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_request_handler_remove(handler, request);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainenvoid auth_request_handler_flush_failures(bool flush_all)
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen struct auth_request **auth_requests, *auth_request;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen unsigned int i, count;
401b0787fff2dc986a5321ddb32acb1947ff66b0Timo Sirainen auth_requests = array_idx_modifiable(&auth_failures_arr, 0);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen for (i = 0; i < count; i++) {
ad49932dae8ba31e07544b66bbc4f4de707a751cTimo Sirainen auth_request = auth_requests[aqueue_idx(auth_failures, 0)];
ecb1b2d6236942bf82f822e8d0167f0e160b206dTimo Sirainen /* FIXME: assumess that failure_delay is always the same. */
ecb1b2d6236942bf82f822e8d0167f0e160b206dTimo Sirainen diff = ioloop_time - auth_request->last_access;
ecb1b2d6236942bf82f822e8d0167f0e160b206dTimo Sirainen if (diff < (time_t)auth_request->set->failure_delay &&
657afb33796f8216c568ad813627da89970760beTimo Sirainen i_assert(auth_request->state == AUTH_REQUEST_STATE_FINISHED);
3b8d05391336c0e4d24c8ddcc962f350409ffbd3Timo Sirainenstatic void auth_failure_timeout(void *context ATTR_UNUSED)