auth-request-handler.c revision 1cc683c5d442a1a3bed5a18c1fb37180cb7ef84b
657afb33796f8216c568ad813627da89970760beTimo Sirainen/* Copyright (c) 2005-2010 Dovecot authors, see the included COPYING file */
657afb33796f8216c568ad813627da89970760beTimo Sirainen
657afb33796f8216c568ad813627da89970760beTimo Sirainen#include "auth-common.h"
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen#include "ioloop.h"
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen#include "array.h"
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen#include "aqueue.h"
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen#include "base64.h"
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen#include "hash.h"
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen#include "str.h"
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen#include "str-sanitize.h"
657afb33796f8216c568ad813627da89970760beTimo Sirainen#include "auth-penalty.h"
657afb33796f8216c568ad813627da89970760beTimo Sirainen#include "auth-request.h"
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen#include "auth-master-connection.h"
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen#include "auth-request-handler.h"
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen#include <stdlib.h>
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen#define AUTH_FAILURE_DELAY_CHECK_MSECS 500
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainenstruct auth_request_handler {
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen int refcount;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen pool_t pool;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen struct hash_table *requests;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen unsigned int connect_uid, client_pid;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_request_callback_t *callback;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen void *context;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_request_callback_t *master_callback;
657afb33796f8216c568ad813627da89970760beTimo Sirainen};
657afb33796f8216c568ad813627da89970760beTimo Sirainen
9b62bbaf33d4516b5dffb36c3ea32ce217e7fbb1Timo Sirainenstatic ARRAY_DEFINE(auth_failures_arr, struct auth_request *);
657afb33796f8216c568ad813627da89970760beTimo Sirainenstatic struct aqueue *auth_failures;
ad49932dae8ba31e07544b66bbc4f4de707a751cTimo Sirainenstatic struct timeout *to_auth_failures;
657afb33796f8216c568ad813627da89970760beTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainenstatic void auth_failure_timeout(void *context);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen#undef auth_request_handler_create
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainenstruct auth_request_handler *
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainenauth_request_handler_create(auth_request_callback_t *callback, void *context,
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_request_callback_t *master_callback)
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen{
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen struct auth_request_handler *handler;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen pool_t pool;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen pool = pool_alloconly_create("auth request handler", 4096);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen handler = p_new(pool, struct auth_request_handler, 1);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen handler->refcount = 1;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen handler->pool = pool;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen handler->requests = hash_table_create(default_pool, pool, 0, NULL, NULL);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen handler->callback = callback;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen handler->context = context;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen handler->master_callback = master_callback;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen return handler;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen}
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainenvoid auth_request_handler_unref(struct auth_request_handler **_handler)
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen{
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen struct auth_request_handler *handler = *_handler;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen struct hash_iterate_context *iter;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen void *key, *value;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
b1e6ea3323b4d753909f79226a8a98d854f819faTimo Sirainen *_handler = NULL;
b1e6ea3323b4d753909f79226a8a98d854f819faTimo Sirainen i_assert(handler->refcount > 0);
b1e6ea3323b4d753909f79226a8a98d854f819faTimo Sirainen if (--handler->refcount > 0)
b1e6ea3323b4d753909f79226a8a98d854f819faTimo Sirainen return;
b1e6ea3323b4d753909f79226a8a98d854f819faTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen iter = hash_table_iterate_init(handler->requests);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen while (hash_table_iterate(iter, &key, &value)) {
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen struct auth_request *auth_request = value;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_request_unref(&auth_request);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen }
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen hash_table_iterate_deinit(&iter);
657afb33796f8216c568ad813627da89970760beTimo Sirainen
657afb33796f8216c568ad813627da89970760beTimo Sirainen /* notify parent that we're done with all requests */
70905e51a5148bd5613cb04720807177474a2496Timo Sirainen handler->callback(NULL, handler->context);
70905e51a5148bd5613cb04720807177474a2496Timo Sirainen
70905e51a5148bd5613cb04720807177474a2496Timo Sirainen hash_table_destroy(&handler->requests);
657afb33796f8216c568ad813627da89970760beTimo Sirainen pool_unref(&handler->pool);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen}
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
657afb33796f8216c568ad813627da89970760beTimo Sirainenvoid auth_request_handler_set(struct auth_request_handler *handler,
657afb33796f8216c568ad813627da89970760beTimo Sirainen unsigned int connect_uid,
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen unsigned int client_pid)
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen{
657afb33796f8216c568ad813627da89970760beTimo Sirainen handler->connect_uid = connect_uid;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen handler->client_pid = client_pid;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen}
657afb33796f8216c568ad813627da89970760beTimo Sirainen
657afb33796f8216c568ad813627da89970760beTimo Sirainenstatic void auth_request_handler_remove(struct auth_request_handler *handler,
70905e51a5148bd5613cb04720807177474a2496Timo Sirainen struct auth_request *request)
657afb33796f8216c568ad813627da89970760beTimo Sirainen{
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen i_assert(request->handler == handler);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen hash_table_remove(handler->requests, POINTER_CAST(request->id));
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_request_unref(&request);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen}
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainenstatic void get_client_extra_fields(struct auth_request *request,
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen struct auth_stream_reply *reply)
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen{
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen const char **fields, *extra_fields;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen unsigned int src, dest;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen bool seen_pass = FALSE;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen if (auth_stream_is_empty(request->extra_fields))
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen return;
1e0bdb2d0fa7bbd0a0a254754680f6c6d0195333Timo Sirainen
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen extra_fields = auth_stream_reply_export(request->extra_fields);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
662a9000b1788f1cdf765e6b1c89df9a42cc3e32Timo Sirainen if (!request->proxy) {
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen /* we only wish to remove all fields prefixed with "userdb_" */
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen if (strstr(extra_fields, "userdb_") == NULL) {
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen auth_stream_reply_import(reply, extra_fields);
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen return;
1e0bdb2d0fa7bbd0a0a254754680f6c6d0195333Timo Sirainen }
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen }
1e0bdb2d0fa7bbd0a0a254754680f6c6d0195333Timo Sirainen
1e0bdb2d0fa7bbd0a0a254754680f6c6d0195333Timo Sirainen fields = t_strsplit(extra_fields, "\t");
1e0bdb2d0fa7bbd0a0a254754680f6c6d0195333Timo Sirainen for (src = dest = 0; fields[src] != NULL; src++) {
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen if (strncmp(fields[src], "userdb_", 7) != 0) {
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen if (!seen_pass && strncmp(fields[src], "pass=", 5) == 0)
1e0bdb2d0fa7bbd0a0a254754680f6c6d0195333Timo Sirainen seen_pass = TRUE;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_stream_reply_import(reply, fields[src]);
1e0bdb2d0fa7bbd0a0a254754680f6c6d0195333Timo Sirainen }
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen }
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
1e0bdb2d0fa7bbd0a0a254754680f6c6d0195333Timo Sirainen if (request->proxy) {
1e0bdb2d0fa7bbd0a0a254754680f6c6d0195333Timo Sirainen /* we're proxying */
1e0bdb2d0fa7bbd0a0a254754680f6c6d0195333Timo Sirainen if (!seen_pass && request->mech_password != NULL) {
662a9000b1788f1cdf765e6b1c89df9a42cc3e32Timo Sirainen /* send back the password that was sent by user
662a9000b1788f1cdf765e6b1c89df9a42cc3e32Timo Sirainen (not the password in passdb). */
1e0bdb2d0fa7bbd0a0a254754680f6c6d0195333Timo Sirainen auth_stream_reply_add(reply, "pass",
1e0bdb2d0fa7bbd0a0a254754680f6c6d0195333Timo Sirainen request->mech_password);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen }
662a9000b1788f1cdf765e6b1c89df9a42cc3e32Timo Sirainen if (request->master_user != NULL) {
662a9000b1788f1cdf765e6b1c89df9a42cc3e32Timo Sirainen /* the master username needs to be forwarded */
662a9000b1788f1cdf765e6b1c89df9a42cc3e32Timo Sirainen auth_stream_reply_add(reply, "master",
662a9000b1788f1cdf765e6b1c89df9a42cc3e32Timo Sirainen request->master_user);
52d3cbc21e8fe482b9b8c832f3921824a7aa6ebeTimo Sirainen }
662a9000b1788f1cdf765e6b1c89df9a42cc3e32Timo Sirainen }
662a9000b1788f1cdf765e6b1c89df9a42cc3e32Timo Sirainen}
8e176dbc6e220c4658afdcc17b097dab83b0d014Timo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainenstatic void
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainenauth_request_handle_failure(struct auth_request *request,
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen struct auth_stream_reply *reply)
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen{
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen struct auth_request_handler *handler = request->context;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen if (request->delayed_failure) {
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen /* we came here from flush_failures() */
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen handler->callback(reply, handler->context);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen return;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen }
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen /* remove the request from requests-list */
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_request_ref(request);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_request_handler_remove(handler, request);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen if (request->no_failure_delay) {
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen /* passdb specifically requested not to delay the
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen reply. */
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen handler->callback(reply, handler->context);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_request_unref(&request);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen return;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen }
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen /* failure. don't announce it immediately to avoid
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen a) timing attacks, b) flooding */
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen request->delayed_failure = TRUE;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen handler->refcount++;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_penalty_update(auth_penalty, request,
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen request->last_penalty + 1);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_request_refresh_last_access(request);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen aqueue_append(auth_failures, &request);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen if (to_auth_failures == NULL) {
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen to_auth_failures =
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen timeout_add(AUTH_FAILURE_DELAY_CHECK_MSECS,
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_failure_timeout, NULL);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen }
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen}
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainenstatic void auth_callback(struct auth_request *request,
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen enum auth_client_result result,
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen const void *auth_reply, size_t reply_size)
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen{
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen struct auth_request_handler *handler = request->context;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen struct auth_stream_reply *reply;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen string_t *str;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen reply = auth_stream_reply_init(pool_datastack_create());
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen switch (result) {
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen case AUTH_CLIENT_RESULT_CONTINUE:
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_stream_reply_add(reply, "CONT", NULL);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_stream_reply_add(reply, NULL, dec2str(request->id));
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen str = t_str_new(MAX_BASE64_ENCODED_SIZE(reply_size));
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen base64_encode(auth_reply, reply_size, str);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_stream_reply_add(reply, NULL, str_c(str));
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen request->accept_input = TRUE;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen handler->callback(reply, handler->context);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen break;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen case AUTH_CLIENT_RESULT_SUCCESS:
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_request_proxy_finish(request, TRUE);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen if (request->last_penalty != 0) {
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen /* reset penalty */
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_penalty_update(auth_penalty, request, 0);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen }
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_stream_reply_add(reply, "OK", NULL);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_stream_reply_add(reply, NULL, dec2str(request->id));
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_stream_reply_add(reply, "user", request->user);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen if (reply_size > 0) {
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen str = t_str_new(MAX_BASE64_ENCODED_SIZE(reply_size));
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen base64_encode(auth_reply, reply_size, str);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_stream_reply_add(reply, "resp", str_c(str));
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen }
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen get_client_extra_fields(request, reply);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen if (request->no_login || handler->master_callback == NULL) {
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen /* this request doesn't have to wait for master
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen process to pick it up. delete it */
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_request_handler_remove(handler, request);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen }
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen handler->callback(reply, handler->context);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen break;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen case AUTH_CLIENT_RESULT_FAILURE:
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_request_proxy_finish(request, FALSE);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_stream_reply_add(reply, "FAIL", NULL);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_stream_reply_add(reply, NULL, dec2str(request->id));
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen if (request->user != NULL)
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_stream_reply_add(reply, "user", request->user);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen if (request->internal_failure)
657afb33796f8216c568ad813627da89970760beTimo Sirainen auth_stream_reply_add(reply, "temp", NULL);
657afb33796f8216c568ad813627da89970760beTimo Sirainen else if (request->master_user != NULL) {
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen /* authentication succeeded, but we can't log in
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen as the wanted user */
657afb33796f8216c568ad813627da89970760beTimo Sirainen auth_stream_reply_add(reply, "authz", NULL);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen }
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen if (request->no_failure_delay)
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_stream_reply_add(reply, "nodelay", NULL);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen get_client_extra_fields(request, reply);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_request_handle_failure(request, reply);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen break;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen }
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen /* NOTE: request may be destroyed now */
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_request_handler_unref(&handler);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen}
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainenstatic void auth_request_handler_auth_fail(struct auth_request_handler *handler,
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen struct auth_request *request,
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen const char *reason)
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen{
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen struct auth_stream_reply *reply;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_request_log_info(request, request->mech->mech_name, "%s", reason);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen reply = auth_stream_reply_init(pool_datastack_create());
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_stream_reply_add(reply, "FAIL", NULL);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_stream_reply_add(reply, NULL, dec2str(request->id));
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_stream_reply_add(reply, "reason", reason);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen handler->callback(reply, handler->context);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_request_handler_remove(handler, request);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen}
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainenstatic void auth_request_timeout(struct auth_request *request)
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen{
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_request_handler_remove(request->handler, request);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen}
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainenstatic void auth_request_penalty_finish(struct auth_request *request)
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen{
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen timeout_remove(&request->to_penalty);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_request_initial(request);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen}
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainenstatic void
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainenauth_penalty_callback(unsigned int penalty, struct auth_request *request)
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen{
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen unsigned int secs;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen request->last_penalty = penalty;
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen if (penalty == 0)
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_request_initial(request);
382c7aec3e3449ed8271c2a202b67cefaa31dc8eTimo Sirainen else {
382c7aec3e3449ed8271c2a202b67cefaa31dc8eTimo Sirainen secs = auth_penalty_to_secs(penalty);
382c7aec3e3449ed8271c2a202b67cefaa31dc8eTimo Sirainen request->to_penalty = timeout_add(secs * 1000,
382c7aec3e3449ed8271c2a202b67cefaa31dc8eTimo Sirainen auth_request_penalty_finish,
382c7aec3e3449ed8271c2a202b67cefaa31dc8eTimo Sirainen request);
382c7aec3e3449ed8271c2a202b67cefaa31dc8eTimo Sirainen }
382c7aec3e3449ed8271c2a202b67cefaa31dc8eTimo Sirainen}
382c7aec3e3449ed8271c2a202b67cefaa31dc8eTimo Sirainen
382c7aec3e3449ed8271c2a202b67cefaa31dc8eTimo Sirainenbool auth_request_handler_auth_begin(struct auth *auth,
382c7aec3e3449ed8271c2a202b67cefaa31dc8eTimo Sirainen struct auth_request_handler *handler,
382c7aec3e3449ed8271c2a202b67cefaa31dc8eTimo Sirainen const char *args)
382c7aec3e3449ed8271c2a202b67cefaa31dc8eTimo Sirainen{
382c7aec3e3449ed8271c2a202b67cefaa31dc8eTimo Sirainen const struct mech_module *mech;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen struct auth_request *request;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen const char *const *list, *name, *arg, *initial_resp;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen void *initial_resp_data;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen unsigned int id;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen buffer_t *buf;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen /* <id> <mechanism> [...] */
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen list = t_strsplit(args, "\t");
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen if (list[0] == NULL || list[1] == NULL) {
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen i_error("BUG: Authentication client %u "
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen "sent broken AUTH request", handler->client_pid);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen return FALSE;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen }
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen id = (unsigned int)strtoul(list[0], NULL, 10);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen mech = mech_module_find(list[1]);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen if (mech == NULL) {
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen /* unsupported mechanism */
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen i_error("BUG: Authentication client %u requested unsupported "
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen "authentication mechanism %s", handler->client_pid,
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen str_sanitize(list[1], MAX_MECH_NAME_LEN));
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen return FALSE;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen }
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen request = auth_request_new(auth, mech, auth_callback, handler);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen request->handler = handler;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen request->connect_uid = handler->connect_uid;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen request->client_pid = handler->client_pid;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen request->id = id;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen /* parse optional parameters */
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen initial_resp = NULL;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen for (list += 2; *list != NULL; list++) {
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen arg = strchr(*list, '=');
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen if (arg == NULL) {
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen name = *list;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen arg = "";
657afb33796f8216c568ad813627da89970760beTimo Sirainen } else {
657afb33796f8216c568ad813627da89970760beTimo Sirainen name = t_strdup_until(*list, arg);
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen arg++;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen }
657afb33796f8216c568ad813627da89970760beTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen if (auth_request_import(request, name, arg))
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen ;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen else if (strcmp(name, "resp") == 0) {
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen initial_resp = arg;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen /* this must be the last parameter */
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen list++;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen break;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen }
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen }
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen if (*list != NULL) {
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen i_error("BUG: Authentication client %u "
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen "sent AUTH parameters after 'resp'",
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen handler->client_pid);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_request_unref(&request);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen return FALSE;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen }
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen if (request->service == NULL) {
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen i_error("BUG: Authentication client %u "
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen "didn't specify service in request",
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen handler->client_pid);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_request_unref(&request);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen return FALSE;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen }
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen request->to_abort = timeout_add(AUTH_REQUEST_TIMEOUT * 1000,
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_request_timeout, request);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen hash_table_insert(handler->requests, POINTER_CAST(id), request);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen if (request->auth->set->ssl_require_client_cert &&
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen !request->valid_client_cert) {
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen /* we fail without valid certificate */
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_request_handler_auth_fail(handler, request,
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen "Client didn't present valid SSL certificate");
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen return TRUE;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen }
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen /* Empty initial response is a "=" base64 string. Completely empty
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen string shouldn't really be sent, but at least Exim does it,
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen so just allow it for backwards compatibility.. */
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen if (initial_resp != NULL && *initial_resp != '\0') {
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen size_t len = strlen(initial_resp);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen buf = buffer_create_dynamic(pool_datastack_create(),
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen MAX_BASE64_DECODED_SIZE(len));
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen if (base64_decode(initial_resp, len, NULL, buf) < 0) {
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen auth_request_handler_auth_fail(handler, request,
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen "Invalid base64 data in initial response");
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen return TRUE;
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen }
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen initial_resp_data =
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen p_malloc(request->pool, I_MAX(buf->used, 1));
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen memcpy(initial_resp_data, buf->data, buf->used);
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen request->initial_response = initial_resp_data;
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen request->initial_response_len = buf->used;
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen }
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen /* handler is referenced until auth_callback is called. */
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen handler->refcount++;
7e078be0d6f12ca56860641d36e3c517e3046895Timo Sirainen
7e078be0d6f12ca56860641d36e3c517e3046895Timo Sirainen /* before we start authenticating, see if we need to wait first */
7e078be0d6f12ca56860641d36e3c517e3046895Timo Sirainen auth_penalty_lookup(auth_penalty, request,
7e078be0d6f12ca56860641d36e3c517e3046895Timo Sirainen auth_penalty_callback);
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen return TRUE;
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen}
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainenbool auth_request_handler_auth_continue(struct auth_request_handler *handler,
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen const char *args)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen{
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen struct auth_request *request;
657afb33796f8216c568ad813627da89970760beTimo Sirainen const char *data;
657afb33796f8216c568ad813627da89970760beTimo Sirainen size_t data_len;
657afb33796f8216c568ad813627da89970760beTimo Sirainen buffer_t *buf;
ad49932dae8ba31e07544b66bbc4f4de707a751cTimo Sirainen unsigned int id;
657afb33796f8216c568ad813627da89970760beTimo Sirainen
657afb33796f8216c568ad813627da89970760beTimo Sirainen data = strchr(args, '\t');
657afb33796f8216c568ad813627da89970760beTimo Sirainen if (data == NULL) {
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen i_error("BUG: Authentication client sent broken CONT request");
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen return FALSE;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen }
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen data++;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen id = (unsigned int)strtoul(args, NULL, 10);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen request = hash_table_lookup(handler->requests, POINTER_CAST(id));
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen if (request == NULL) {
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen struct auth_stream_reply *reply;
ad49932dae8ba31e07544b66bbc4f4de707a751cTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen reply = auth_stream_reply_init(pool_datastack_create());
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_stream_reply_add(reply, "FAIL", NULL);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_stream_reply_add(reply, NULL, dec2str(id));
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_stream_reply_add(reply, "reason", "Timeouted");
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen handler->callback(reply, handler->context);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen return TRUE;
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen }
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen /* accept input only once after mechanism has sent a CONT reply */
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen if (!request->accept_input) {
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_request_handler_auth_fail(handler, request,
ad49932dae8ba31e07544b66bbc4f4de707a751cTimo Sirainen "Unexpected continuation");
0a8ec3c561c26c492a50511692650ea302cc8c14Timo Sirainen return TRUE;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen }
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen request->accept_input = FALSE;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen data_len = strlen(data);
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen buf = buffer_create_dynamic(pool_datastack_create(),
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen MAX_BASE64_DECODED_SIZE(data_len));
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen if (base64_decode(data, data_len, NULL, buf) < 0) {
ad49932dae8ba31e07544b66bbc4f4de707a751cTimo Sirainen auth_request_handler_auth_fail(handler, request,
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen "Invalid base64 data in continued response");
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen return TRUE;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen }
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen /* handler is referenced until auth_callback is called. */
657afb33796f8216c568ad813627da89970760beTimo Sirainen handler->refcount++;
657afb33796f8216c568ad813627da89970760beTimo Sirainen auth_request_continue(request, buf->data, buf->used);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen return TRUE;
657afb33796f8216c568ad813627da89970760beTimo Sirainen}
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainenstatic void userdb_callback(enum userdb_result result,
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen struct auth_request *request)
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen{
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen struct auth_request_handler *handler = request->context;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen struct auth_stream_reply *reply;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen i_assert(request->state == AUTH_REQUEST_STATE_USERDB);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen request->state = AUTH_REQUEST_STATE_FINISHED;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen if (request->userdb_lookup_failed)
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen result = USERDB_RESULT_INTERNAL_FAILURE;
657afb33796f8216c568ad813627da89970760beTimo Sirainen
657afb33796f8216c568ad813627da89970760beTimo Sirainen reply = auth_stream_reply_init(pool_datastack_create());
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen switch (result) {
657afb33796f8216c568ad813627da89970760beTimo Sirainen case USERDB_RESULT_INTERNAL_FAILURE:
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_stream_reply_add(reply, "FAIL", NULL);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_stream_reply_add(reply, NULL, dec2str(request->id));
657afb33796f8216c568ad813627da89970760beTimo Sirainen break;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen case USERDB_RESULT_USER_UNKNOWN:
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_stream_reply_add(reply, "NOTFOUND", NULL);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_stream_reply_add(reply, NULL, dec2str(request->id));
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen break;
657afb33796f8216c568ad813627da89970760beTimo Sirainen case USERDB_RESULT_OK:
657afb33796f8216c568ad813627da89970760beTimo Sirainen auth_stream_reply_add(reply, "USER", NULL);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_stream_reply_add(reply, NULL, dec2str(request->id));
657afb33796f8216c568ad813627da89970760beTimo Sirainen if (request->master_user != NULL) {
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_stream_reply_add(request->userdb_reply,
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen "master_user",
657afb33796f8216c568ad813627da89970760beTimo Sirainen request->master_user);
}
auth_stream_reply_import(reply,
auth_stream_reply_export(request->userdb_reply));
break;
}
handler->master_callback(reply, request->master);
auth_master_connection_unref(&request->master);
auth_request_unref(&request);
auth_request_handler_unref(&handler);
}
void auth_request_handler_master_request(struct auth_request_handler *handler,
struct auth_master_connection *master,
unsigned int id,
unsigned int client_id)
{
struct auth_request *request;
struct auth_stream_reply *reply;
reply = auth_stream_reply_init(pool_datastack_create());
request = hash_table_lookup(handler->requests, POINTER_CAST(client_id));
if (request == NULL) {
i_error("Master request %u.%u not found",
handler->client_pid, client_id);
auth_stream_reply_add(reply, "FAIL", NULL);
auth_stream_reply_add(reply, NULL, dec2str(id));
handler->master_callback(reply, master);
return;
}
auth_request_ref(request);
auth_request_handler_remove(handler, request);
if (request->state != AUTH_REQUEST_STATE_FINISHED ||
!request->successful) {
i_error("Master requested unfinished authentication request "
"%u.%u", handler->client_pid, client_id);
auth_stream_reply_add(reply, "FAIL", NULL);
auth_stream_reply_add(reply, NULL, dec2str(id));
handler->master_callback(reply, master);
auth_request_unref(&request);
} else {
/* the request isn't being referenced anywhere anymore,
so we can do a bit of kludging.. replace the request's
old client_id with master's id. */
request->state = AUTH_REQUEST_STATE_USERDB;
request->id = id;
request->context = handler;
request->master = master;
/* master and handler are referenced until userdb_callback i
s called. */
auth_master_connection_ref(master);
handler->refcount++;
auth_request_lookup_user(request, userdb_callback);
}
}
void auth_request_handler_flush_failures(bool flush_all)
{
struct auth_request **auth_requests, *auth_request;
unsigned int i, count;
time_t diff;
count = aqueue_count(auth_failures);
if (count == 0) {
if (to_auth_failures != NULL)
timeout_remove(&to_auth_failures);
return;
}
auth_requests = array_idx_modifiable(&auth_failures_arr, 0);
for (i = 0; i < count; i++) {
auth_request = auth_requests[aqueue_idx(auth_failures, 0)];
/* FIXME: assumess that failure_delay is always the same. */
diff = ioloop_time - auth_request->last_access;
if (diff < (time_t)auth_request->auth->set->failure_delay &&
!flush_all)
break;
aqueue_delete_tail(auth_failures);
i_assert(auth_request->state == AUTH_REQUEST_STATE_FINISHED);
auth_request->callback(auth_request,
AUTH_CLIENT_RESULT_FAILURE, NULL, 0);
auth_request_unref(&auth_request);
}
}
static void auth_failure_timeout(void *context ATTR_UNUSED)
{
auth_request_handler_flush_failures(FALSE);
}
void auth_request_handler_init(void)
{
i_array_init(&auth_failures_arr, 128);
auth_failures = aqueue_init(&auth_failures_arr.arr);
}
void auth_request_handler_deinit(void)
{
auth_request_handler_flush_failures(TRUE);
array_free(&auth_failures_arr);
aqueue_deinit(&auth_failures);
if (to_auth_failures != NULL)
timeout_remove(&to_auth_failures);
}