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