auth-request-handler.c revision 190d84a496d6893ed54fe5bdb9e503285583d13f
/* Copyright (c) 2005-2012 Dovecot authors, see the included COPYING file */
#include "auth-common.h"
#include "ioloop.h"
#include "array.h"
#include "aqueue.h"
#include "base64.h"
#include "hash.h"
#include "str.h"
#include "str-sanitize.h"
#include "master-interface.h"
#include "auth-penalty.h"
#include "auth-request.h"
#include "auth-master-connection.h"
#include "auth-request-handler.h"
#include <stdlib.h>
#define AUTH_FAILURE_DELAY_CHECK_MSECS 500
struct auth_request_handler {
int refcount;
struct hash_table *requests;
unsigned int connect_uid, client_pid;
void *context;
unsigned int destroyed:1;
};
static struct aqueue *auth_failures;
static struct timeout *to_auth_failures;
static void auth_failure_timeout(void *context);
struct auth_request_handler *
{
struct auth_request_handler *handler;
return handler;
}
unsigned int
{
}
{
struct hash_iterate_context *iter;
switch (auth_request->state) {
case AUTH_REQUEST_STATE_NEW:
break;
break;
case AUTH_REQUEST_STATE_MAX:
i_unreached();
}
}
}
{
return;
/* notify parent that we're done with all requests */
}
{
}
unsigned int connect_uid,
unsigned int client_pid)
{
}
struct auth_request *request)
{
if (request->removed_from_handler) {
/* already removed it */
return;
}
/* if db lookup is stuck, this call doesn't actually free the auth
request, so make sure we don't get back here. */
}
struct auth_stream_reply *reply)
{
const char **fields, *extra_fields;
unsigned int src;
return;
/* optimization: there are no userdb_* fields, we can just
import */
return;
}
}
}
/* we're proxying */
/* send back the password that was sent by user
(not the password in passdb). */
}
/* the master username needs to be forwarded */
}
}
}
static void
struct auth_stream_reply *reply)
{
if (request->delayed_failure) {
/* we came here from flush_failures() */
return;
}
/* remove the request from requests-list */
if (request->no_failure_delay) {
/* passdb specifically requested not to delay the reply. */
return;
}
/* failure. don't announce it immediately to avoid
a) timing attacks, b) flooding */
if (auth_penalty != NULL) {
}
if (to_auth_failures == NULL) {
}
}
static void
{
struct auth_stream_reply *reply;
/* reset penalty */
}
/* this request doesn't have to wait for master
process to pick it up. delete it */
}
}
static void
{
struct auth_stream_reply *reply;
}
if (request->internal_failure)
/* authentication succeeded, but we can't log in
as the wanted user */
}
if (request->no_failure_delay)
switch (request->passdb_result) {
case PASSDB_RESULT_OK:
break;
break;
break;
}
}
static void
{
if (success)
else
}
enum auth_client_result result,
{
struct auth_stream_reply *reply;
int ret;
/* the client connection was already closed. we can't do
anything but abort this request */
/* make sure this request is set to finished state
(it's not with result=continue) */
}
switch (result) {
break;
if (reply_size > 0) {
}
if (ret < 0)
else if (ret > 0)
else
return;
break;
break;
}
/* NOTE: request may be destroyed now */
}
{
reply, reply_size);
}
struct auth_request *request,
const char *reason)
{
struct auth_stream_reply *reply;
}
{
const char *str;
/* client's fault */
"%s", str);
"%s", str);
}
}
{
}
static void
{
unsigned int secs;
if (penalty == 0)
else {
request);
}
}
const char *args)
{
const struct mech_module *mech;
struct auth_request *request;
void *initial_resp_data;
unsigned int id;
/* <id> <mechanism> [...] */
i_error("BUG: Authentication client %u "
return FALSE;
}
/* unsupported mechanism */
i_error("BUG: Authentication client %u requested unsupported "
return FALSE;
}
/* parse optional parameters */
initial_resp = NULL;
arg = "";
} else {
arg++;
}
;
initial_resp = arg;
/* this must be the last parameter */
list++;
break;
}
}
i_error("BUG: Authentication client %u "
"sent AUTH parameters after 'resp'",
return FALSE;
}
i_error("BUG: Authentication client %u "
"didn't specify service in request",
return FALSE;
}
i_error("BUG: Authentication client %u "
return FALSE;
}
!request->valid_client_cert) {
/* we fail without valid certificate */
"Client didn't present valid SSL certificate");
return TRUE;
}
/* Empty initial response is a "=" base64 string. Completely empty
string shouldn't really be sent, but at least Exim does it,
so just allow it for backwards compatibility.. */
"Invalid base64 data in initial response");
return TRUE;
}
}
/* handler is referenced until auth_request_handler_reply()
is called. */
/* before we start authenticating, see if we need to wait first */
return TRUE;
}
const char *args)
{
struct auth_request *request;
const char *data;
unsigned int id;
i_error("BUG: Authentication client sent broken CONT request");
return FALSE;
}
data++;
struct auth_stream_reply *reply;
"Authentication request timed out");
return TRUE;
}
/* accept input only once after mechanism has sent a CONT reply */
if (!request->accept_input) {
"Unexpected continuation");
return TRUE;
}
"Invalid base64 data in continued response");
return TRUE;
}
/* handler is referenced until auth_request_handler_reply()
is called. */
return TRUE;
}
struct auth_request *request)
{
struct auth_stream_reply *reply;
const char *value;
if (request->userdb_lookup_failed)
switch (result) {
if (request->userdb_lookup_failed) {
"reason");
}
break;
break;
case USERDB_RESULT_OK:
"master_user") == NULL) {
"master_user",
}
/* this is an anonymous login, either via ANONYMOUS
SASL mechanism or simply logging in as the anonymous
user via another mechanism */
"anonymous", NULL);
}
break;
}
}
struct auth_master_connection *master,
unsigned int id,
unsigned int client_id)
{
struct auth_request *request;
struct auth_stream_reply *reply;
i_error("Master request %u.%u not found",
return FALSE;
return TRUE;
}
!request->successful) {
i_error("Master requested unfinished authentication 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. */
/* master and handler are referenced until userdb_callback i
s called. */
}
return TRUE;
}
unsigned int client_id)
{
struct auth_request *request;
}
void auth_request_handler_flush_failures(bool flush_all)
{
unsigned int i, count;
if (count == 0) {
if (to_auth_failures != NULL)
return;
}
for (i = 0; i < count; i++) {
/* FIXME: assumess that failure_delay is always the same. */
break;
}
}
{
}
void auth_request_handler_init(void)
{
}
void auth_request_handler_deinit(void)
{
if (to_auth_failures != NULL)
}