auth-request-handler.c revision 9be4e6701d086c009f3db1913a148139ea180420
657afb33796f8216c568ad813627da89970760beTimo Sirainen/* Copyright (c) 2005-2010 Dovecot authors, see the included COPYING file */
9b62bbaf33d4516b5dffb36c3ea32ce217e7fbb1Timo Sirainenstatic ARRAY_DEFINE(auth_failures_arr, struct auth_request *);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainenstatic void auth_failure_timeout(void *context);
66d2db642fe24d555d113ba463e446b038d476efTimo 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);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen handler->requests = hash_table_create(default_pool, pool, 0, NULL, NULL);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainenvoid auth_request_handler_unref(struct auth_request_handler **_handler)
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen struct auth_request_handler *handler = *_handler;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen iter = hash_table_iterate_init(handler->requests);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen while (hash_table_iterate(iter, &key, &value)) {
657afb33796f8216c568ad813627da89970760beTimo Sirainen /* notify parent that we're done with all requests */
657afb33796f8216c568ad813627da89970760beTimo Sirainenvoid auth_request_handler_set(struct auth_request_handler *handler,
657afb33796f8216c568ad813627da89970760beTimo Sirainenstatic void auth_request_handler_remove(struct auth_request_handler *handler,
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen hash_table_remove(handler->requests, POINTER_CAST(request->id));
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainenstatic void get_client_extra_fields(struct auth_request *request,
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen if (auth_stream_is_empty(request->extra_fields))
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen extra_fields = auth_stream_reply_export(request->extra_fields);
137ea7ca34005345aa2304a940149b7f3774d727Timo 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 for (src = dest = 0; fields[src] != NULL; src++) {
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen if (strncmp(fields[src], "userdb_", 7) != 0) {
1e0bdb2d0fa7bbd0a0a254754680f6c6d0195333Timo Sirainen if (!seen_pass && strncmp(fields[src], "pass=", 5) == 0)
1e0bdb2d0fa7bbd0a0a254754680f6c6d0195333Timo Sirainen /* we're proxying */
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen if (!seen_pass && request->mech_password != NULL) {
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen /* send back the password that was sent by user
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen (not the password in passdb). */
1e0bdb2d0fa7bbd0a0a254754680f6c6d0195333Timo Sirainen /* the master username needs to be forwarded */
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainenauth_request_handle_failure(struct auth_request *request,
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen struct auth_request_handler *handler = request->context;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen /* we came here from flush_failures() */
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen /* remove the request from requests-list */
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_request_handler_remove(handler, request);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen /* passdb specifically requested not to delay the
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen /* failure. don't announce it immediately to avoid
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen a) timing attacks, b) flooding */
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_penalty_update(request->auth->penalty, request,
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainenstatic void auth_callback(struct auth_request *request,
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen struct auth_request_handler *handler = request->context;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen reply = auth_stream_reply_init(pool_datastack_create());
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_stream_reply_add(reply, NULL, dec2str(request->id));
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen str = t_str_new(MAX_BASE64_ENCODED_SIZE(reply_size));
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_stream_reply_add(reply, NULL, str_c(str));
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen /* reset penalty */
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_penalty_update(request->auth->penalty, request, 0);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_stream_reply_add(reply, NULL, dec2str(request->id));
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_stream_reply_add(reply, "user", request->user);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen str = t_str_new(MAX_BASE64_ENCODED_SIZE(reply_size));
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_stream_reply_add(reply, "resp", str_c(str));
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 auth_stream_reply_add(reply, NULL, dec2str(request->id));
657afb33796f8216c568ad813627da89970760beTimo Sirainen auth_stream_reply_add(reply, "user", request->user);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen /* authentication succeeded, but we can't log in
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen as the wanted user */
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_stream_reply_add(reply, "nodelay", NULL);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen /* NOTE: request may be destroyed now */
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainenstatic void auth_request_handler_auth_fail(struct auth_request_handler *handler,
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_request_log_info(request, request->mech->mech_name, "%s", reason);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen reply = auth_stream_reply_init(pool_datastack_create());
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_stream_reply_add(reply, NULL, dec2str(request->id));
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_stream_reply_add(reply, "reason", reason);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_request_handler_remove(handler, request);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainenstatic void auth_request_timeout(struct auth_request *request)
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_request_handler_remove(request->handler, request);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainenstatic void auth_request_penalty_finish(struct auth_request *request)
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainenauth_penalty_callback(unsigned int penalty, struct auth_request *request)
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen unsigned int secs;
382c7aec3e3449ed8271c2a202b67cefaa31dc8eTimo Sirainen request->to_penalty = timeout_add(secs * 1000,
382c7aec3e3449ed8271c2a202b67cefaa31dc8eTimo Sirainenbool auth_request_handler_auth_begin(struct auth *auth,
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen const char *const *list, *name, *arg, *initial_resp;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen unsigned int id;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen /* <id> <mechanism> [...] */
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen "sent broken AUTH request", handler->client_pid);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen id = (unsigned int)strtoul(list[0], NULL, 10);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen /* unsupported mechanism */
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen i_error("BUG: Authentication client %u requested unsupported "
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen "authentication mechanism %s", handler->client_pid,
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen request = auth_request_new(auth, mech, auth_callback, handler);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen /* parse optional parameters */
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 request->to_abort = timeout_add(AUTH_REQUEST_TIMEOUT * 1000,
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen hash_table_insert(handler->requests, POINTER_CAST(id), request);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen if (request->auth->set->ssl_require_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 /* 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 buf = buffer_create_dynamic(pool_datastack_create(),
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen if (base64_decode(initial_resp, len, NULL, buf) < 0) {
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_request_handler_auth_fail(handler, request,
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen "Invalid base64 data in initial response");
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen memcpy(initial_resp_data, buf->data, buf->used);
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen request->initial_response = initial_resp_data;
7e078be0d6f12ca56860641d36e3c517e3046895Timo Sirainen /* handler is referenced until auth_callback is called. */
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen /* before we start authenticating, see if we need to wait first */
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_penalty_lookup(request->auth->penalty, request,
657afb33796f8216c568ad813627da89970760beTimo Sirainenbool auth_request_handler_auth_continue(struct auth_request_handler *handler,
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen unsigned int id;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen i_error("BUG: Authentication client sent broken CONT request");
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen request = hash_table_lookup(handler->requests, POINTER_CAST(id));
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen reply = auth_stream_reply_init(pool_datastack_create());
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen auth_stream_reply_add(reply, NULL, dec2str(id));
615c4aba4cc0b17eefba3263b85972adaba04586Timo Sirainen auth_stream_reply_add(reply, "reason", "Timeouted");
0a8ec3c561c26c492a50511692650ea302cc8c14Timo Sirainen /* accept input only once after mechanism has sent a CONT reply */
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_request_handler_auth_fail(handler, request,
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen "Unexpected continuation");
66d2db642fe24d555d113ba463e446b038d476efTimo 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");
657afb33796f8216c568ad813627da89970760beTimo Sirainen /* handler is referenced until auth_callback is called. */
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_request_continue(request, buf->data, buf->used);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainenstatic void userdb_callback(enum userdb_result result,
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen struct auth_request_handler *handler = request->context;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen i_assert(request->state == AUTH_REQUEST_STATE_USERDB);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen reply = auth_stream_reply_init(pool_datastack_create());
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_stream_reply_add(reply, NULL, dec2str(request->id));
657afb33796f8216c568ad813627da89970760beTimo Sirainen auth_stream_reply_add(reply, "NOTFOUND", NULL);
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen auth_stream_reply_add(reply, NULL, dec2str(request->id));
657afb33796f8216c568ad813627da89970760beTimo Sirainen auth_stream_reply_add(reply, NULL, dec2str(request->id));
unsigned int id,
unsigned int client_id)
unsigned int i, count;
if (count == 0) {
for (i = 0; i < count; i++) {
void auth_request_handler_init(void)
void auth_request_handler_deinit(void)