client-common-auth.c revision 4c6ddf2491104f917d00e6900e833e80ea02c7b6
7cb128dc4cae2a03a742f63ba7afee23c78e3af0Phil Carmody/* Copyright (c) 2002-2009 Dovecot authors, see the included COPYING file */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen/* If we've been waiting auth server to respond for over this many milliseconds,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen send a "waiting" message. */
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen#if CLIENT_LOGIN_IDLE_TIMEOUT_MSECS < AUTH_REQUEST_TIMEOUT*1000
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen# error client idle timeout must be larger than authentication timeout
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainenstatic void client_authfail_delay_timeout(struct client *client)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* get back to normal client input. */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen client->io = io_add(client->fd, IO_READ, client_input, client);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenvoid client_auth_failed(struct client *client, bool nodelay)
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen client->io = io_add(client->fd, IO_READ, client_input, client);
788a0754cfd38dcfec1902844b085e4e84cfe7e6Timo Sirainen /* increase the timeout after each unsuccessful attempt, but don't
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen increase it so high that the idle timeout would be triggered */
788a0754cfd38dcfec1902844b085e4e84cfe7e6Timo Sirainen delay_msecs = client->auth_attempts * AUTH_FAILURE_DELAY_INCREASE_MSECS;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen if (delay_msecs > CLIENT_LOGIN_IDLE_TIMEOUT_MSECS)
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen delay_msecs = CLIENT_LOGIN_IDLE_TIMEOUT_MSECS - 1000;
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen timeout_add(delay_msecs, client_authfail_delay_timeout, client);
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainenstatic void client_auth_waiting_timeout(struct client *client)
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen client_send_line(client, CLIENT_CMD_REPLY_STATUS,
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen AUTH_SERVER_WAITING_MSG : AUTH_MASTER_WAITING_MSG);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenvoid client_set_auth_waiting(struct client *client)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic void client_auth_parse_args(struct client *client,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const char *const *args,
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen reply_r->ssl_flags |= PROXY_SSL_FLAG_STARTTLS;
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen /* already handled in login-common */
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen i_info("Ignoring unknown passdb extra field: %s", key);
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainenstatic void proxy_free_password(struct client *client)
a138ac12134564b151f00fdef86fba9cd9ba8af0Timo Sirainen safe_memset(client->proxy_password, 0, strlen(client->proxy_password));
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenvoid client_proxy_finish_destroy_client(struct client *client)
31633d676642b83305b8d46da495d9bb4e2d1ff8Timo Sirainen str_printfa(str, "proxy(%s): started proxying to %s:%u",
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen if (strcmp(client->virtual_user, client->proxy_user) != 0) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* remote username is different, log it */
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen str_printfa(str, " (master %s)", client->proxy_master_user);
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen login_proxy_detach(client->login_proxy, client->input, client->output);
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainenvoid client_proxy_log_failure(struct client *client, const char *line)
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen str_printfa(str, "proxy(%s): Login failed to %s:%u",
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (strcmp(client->virtual_user, client->proxy_user) != 0) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* remote username is different, log it */
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen str_printfa(str, " (master %s)", client->proxy_master_user);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenvoid client_proxy_failed(struct client *client, bool send_line)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen client_send_line(client, CLIENT_CMD_REPLY_AUTH_FAIL_TEMP,
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen /* call this last - it may destroy the client */
8eb94c5190ba09bb6f6f068eec7bf96750f08d1dTimo Sirainen /* we're just freeing the proxy */
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen input = login_proxy_get_istream(client->login_proxy);
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen /* we came here from client_destroy() */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* failed for some reason, probably server disconnected */
31633d676642b83305b8d46da495d9bb4e2d1ff8Timo Sirainen client_log_err(client, "proxy: Remote input buffer full");
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen client_log_err(client, "proxy: Remote disconnected");
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen while ((line = i_stream_next_line(input)) != NULL) {
b0e9375a1ff97c9c7d40655922af5ccc73ecaa76Timo Sirainen if (client->v.proxy_parse_line(client, line) != 0)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen client_log_err(client, "proxy: password not given");
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen client_send_line(client, CLIENT_CMD_REPLY_AUTH_FAIL_TEMP,
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen /* connection_queue_add() decided that we were the oldest
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen connection and killed us. */
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen if (login_proxy_is_ourself(client, reply->host, reply->port,
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen client_log_err(client, "Proxying loops to itself");
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen client_send_line(client, CLIENT_CMD_REPLY_AUTH_FAIL_TEMP,
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen login_proxy_new(client, reply->host, reply->port,
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen client_send_line(client, CLIENT_CMD_REPLY_AUTH_FAIL_TEMP,
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen client->proxy_user = i_strdup(reply->destuser);
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen client->proxy_master_user = i_strdup(reply->master_user);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen client->proxy_password = i_strdup(reply->password);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen /* disable input until authentication is finished */
430c0b0c370bebeeceba2e206be76bc134742f41Timo Sirainenclient_auth_handle_reply(struct client *client,
25ee72451d16374ed27fdbf829f4ec756c778352Timo Sirainen const struct client_auth_reply *reply, bool success)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* we want to proxy the connection to another server.
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen don't do this unless authentication succeeded. with
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen master user proxying we can get FAIL with proxy still set.
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen proxy host=.. [port=..] [destuser=..] pass=.. */
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen return client->v.auth_handle_reply(client, reply);
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainenstatic void client_auth_input(struct client *client)
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen /* @UNSAFE */
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen auth_client_request_continue(client->auth_request, line);
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen /* clear sensitive data */
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainenvoid client_auth_send_continue(struct client *client, const char *data)
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainensasl_callback(struct client *client, enum sasl_server_reply sasl_reply,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen sasl_reply == SASL_SERVER_REPLY_AUTH_ABORTED ||
6fabfb7bbfd88d0c1de66981e52850f26067623bTimo Sirainen sasl_reply == SASL_SERVER_REPLY_MASTER_FAILED);
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen if (client_auth_handle_reply(client, &reply, TRUE))
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen if (client_auth_handle_reply(client, &reply, FALSE))
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (sasl_reply == SASL_SERVER_REPLY_AUTH_ABORTED) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen client_send_line(client, CLIENT_CMD_REPLY_BAD,
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen "Authentication aborted by client.");
f0c01ca67be18ed9c8011a094db2773f8795a1ebTimo Sirainen client_send_line(client, CLIENT_CMD_REPLY_AUTH_FAILED,
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen /* authentication itself succeeded, we just hit some
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen internal failure. */
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainenint client_auth_begin(struct client *client, const char *mech_name,
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen if (!client->secured && strcmp(client->set->ssl, "required") == 0) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen "SSL required for authentication");
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen client_send_line(client, CLIENT_CMD_REPLY_AUTH_FAIL_NOSSL,
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen "Authentication not allowed until SSL/TLS is enabled.");
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen sasl_server_auth_begin(client, login_protocol, mech_name,
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen /* don't handle input until we get the initial auth reply */
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainenbool client_check_plaintext_auth(struct client *client, bool pass_sent)
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen if (client->secured || !client->set->disable_plaintext_auth)
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen "Plaintext authentication disabled");
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen client_send_line(client, CLIENT_CMD_REPLY_STATUS_BAD,
c0757c70cfd2c9b44de3504b753a4d2f38690ef0Timo Sirainen "Plaintext authentication not allowed "
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen "without SSL/TLS, but your client did it anyway. "
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen "If anyone was listening, the password was exposed.");
5afc76d0215c5f7631dec06ef864d59f0686a0a8Timo Sirainen client_send_line(client, CLIENT_CMD_REPLY_AUTH_FAIL_NOSSL,
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen for (client = clients; client != NULL; client = client->next) {