auth-request-handler.c revision 814bf67459ad405a157af0b8940602024d7fadfe
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek/* Copyright (c) 2005-2015 Dovecot authors, see the included COPYING file */
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek HASH_TABLE(void *, struct auth_request *) requests;
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidekstatic ARRAY(struct auth_request *) auth_failures_arr;
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidekstatic void auth_failure_timeout(void *context) ATTR_NULL(1);
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidekauth_request_handler_create(bool token_auth, auth_request_callback_t *callback,
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek void *context, auth_request_callback_t *master_callback)
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek pool = pool_alloconly_create("auth request handler", 4096);
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek handler = p_new(pool, struct auth_request_handler, 1);
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek hash_table_create_direct(&handler->requests, pool, 0);
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidekauth_request_handler_get_request_count(struct auth_request_handler *handler)
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidekvoid auth_request_handler_abort_requests(struct auth_request_handler *handler)
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek iter = hash_table_iterate_init(handler->requests);
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek while (hash_table_iterate(iter, handler->requests, &key, &auth_request)) {
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek /* can't abort a pending passdb/userdb lookup */
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidekvoid auth_request_handler_unref(struct auth_request_handler **_handler)
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek struct auth_request_handler *handler = *_handler;
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek i_assert(hash_table_count(handler->requests) == 0);
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek /* notify parent that we're done with all requests */
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidekvoid auth_request_handler_destroy(struct auth_request_handler **_handler)
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek struct auth_request_handler *handler = *_handler;
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidekvoid auth_request_handler_set(struct auth_request_handler *handler,
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidekstatic void auth_request_handler_remove(struct auth_request_handler *handler,
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek /* already removed it */
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek /* if db lookup is stuck, this call doesn't actually free the auth
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek request, so make sure we don't get back here. */
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek hash_table_remove(handler->requests, POINTER_CAST(request->id));
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidekauth_str_add_keyvalue(string_t *dest, const char *key, const char *value)
2d6836a90bd326391782a5753f70e8ba666b5defJan Cholastaauth_str_append_extra_fields(struct auth_request *request, string_t *dest)
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek if (!auth_fields_is_empty(request->extra_fields)) {
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek auth_fields_append(request->extra_fields, dest,
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek null_strcmp(request->original_username, request->user) != 0 &&
965428847850f1b154130e249f2d942c6065e88dSimo Sorce !auth_fields_exists(request->extra_fields, "original_user")) {
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek !auth_fields_exists(request->extra_fields, "auth_user"))
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek auth_str_add_keyvalue(dest, "auth_user", request->master_user);
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek auth_fields_exists(request->extra_fields, "proxy")) {
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek /* we're proxying */
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek if (!auth_fields_exists(request->extra_fields, "pass") &&
965428847850f1b154130e249f2d942c6065e88dSimo Sorce /* send back the password that was sent by user
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek (not the password in passdb). */
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek !auth_fields_exists(request->extra_fields, "master")) {
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek /* the master username needs to be forwarded */
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidekauth_request_handle_failure(struct auth_request *request, const char *reply)
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek struct auth_request_handler *handler = request->handler;
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek /* we came here from flush_failures() */
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek /* remove the request from requests-list */
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek if (auth_fields_exists(request->extra_fields, "nodelay")) {
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek /* passdb specifically requested not to delay the reply. */
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek /* failure. don't announce it immediately to avoid
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek a) timing attacks, b) flooding */
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek timeout_add_short(AUTH_FAILURE_DELAY_CHECK_MSECS,
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidekauth_request_handler_reply_success_finish(struct auth_request *request)
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek struct auth_request_handler *handler = request->handler;
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek if (request->last_penalty != 0 && auth_penalty != NULL) {
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek /* reset penalty */
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek /* sanitize these fields, since the login code currently assumes they
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek are exactly in this format. */
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek auth_fields_booleanize(request->extra_fields, "nologin");
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek auth_fields_booleanize(request->extra_fields, "proxy");
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek str_printfa(str, "OK\t%u\tuser=", request->id);
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek auth_fields_exists(request->extra_fields, "nologin") ||
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek auth_fields_exists(request->extra_fields, "proxy")) {
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek /* this request doesn't have to wait for master
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek process to pick it up. delete it */
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek handler->callback(str_c(str), handler->context);
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidekauth_request_handler_reply_failure_finish(struct auth_request *request)
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek auth_fields_remove(request->extra_fields, "nologin");
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek auth_str_add_keyvalue(str, "user", request->user);
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek /* authentication succeeded, but we can't log in
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek as the wanted user */
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek if (auth_fields_exists(request->extra_fields, "nodelay")) {
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek /* this is normally a hidden field, need to add it explicitly */
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek auth_request_handle_failure(request, str_c(str));
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidekauth_request_handler_proxy_callback(bool success, struct auth_request *request)
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek struct auth_request_handler *handler = request->handler;
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek auth_request_handler_reply_success_finish(request);
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek auth_request_handler_reply_failure_finish(request);
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidekvoid auth_request_handler_reply(struct auth_request *request,
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek struct auth_request_handler *handler = request->handler;
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek /* the client connection was already closed. we can't do
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek anything but abort this request */
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek /* make sure this request is set to finished state
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek (it's not with result=continue) */
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek auth_request_set_state(request, AUTH_REQUEST_STATE_FINISHED);
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek str = t_str_new(16 + MAX_BASE64_ENCODED_SIZE(reply_size));
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek handler->callback(str_c(str), handler->context);
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek str = t_str_new(MAX_BASE64_ENCODED_SIZE(reply_size));
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek auth_request_handler_reply_failure_finish(request);
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek else if (ret > 0)
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek auth_request_handler_reply_success_finish(request);
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek auth_request_handler_reply_failure_finish(request);
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek /* NOTE: request may be destroyed now */
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidekvoid auth_request_handler_reply_continue(struct auth_request *request,
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek auth_request_handler_reply(request, AUTH_CLIENT_RESULT_CONTINUE,
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidekstatic void auth_request_handler_auth_fail(struct auth_request_handler *handler,
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek auth_request_log_info(request, AUTH_SUBSYS_MECH, "%s", reason);
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek str_printfa(str, "FAIL\t%u\treason=", request->id);
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek handler->callback(str_c(str), handler->context);
9e2c64c6d4f5560e27207193efea6536a566865eMichal Zidekstatic void auth_request_timeout(struct auth_request *request)
dfe84158c49e44f2207b94d25e61ab4f3fe38366Michal Zidek unsigned int secs = (unsigned int)(time(NULL) - request->last_access);
dfe84158c49e44f2207b94d25e61ab4f3fe38366Michal Zidek if (request->state != AUTH_REQUEST_STATE_MECH_CONTINUE) {
dfe84158c49e44f2207b94d25e61ab4f3fe38366Michal Zidek /* client's fault */
dfe84158c49e44f2207b94d25e61ab4f3fe38366Michal Zidek auth_request_log_error(request, AUTH_SUBSYS_MECH,
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek "Request %u.%u timed out after %u secs, state=%d",
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek auth_request_log_info(request, AUTH_SUBSYS_MECH,
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek "Request timed out waiting for client to continue authentication "
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek auth_request_handler_remove(request->handler, request);
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidekstatic void auth_request_penalty_finish(struct auth_request *request)
unsigned int secs;
if (penalty == 0)
request);
const char *args)
void *initial_resp_data;
unsigned int id;
return FALSE;
return FALSE;
return FALSE;
arg++;
list++;
return FALSE;
return FALSE;
return FALSE;
return TRUE;
return TRUE;
return TRUE;
const char *args)
const char *data;
unsigned int id;
return FALSE;
data++;
return TRUE;
return TRUE;
return TRUE;
return TRUE;
const char *auth_token =
const char *value;
switch (result) {
case USERDB_RESULT_OK:
unsigned int id)
return FALSE;
return TRUE;
const char *const *params)
param++;
master);
return TRUE;
unsigned int client_id)
unsigned int i, count;
if (count == 0) {
for (i = 0; i < count; i++) {
&uchar_nul, 0);
void auth_request_handler_init(void)
void auth_request_handler_deinit(void)