client-common-auth.c revision 5a250816ffc4cc5db203f9410ea99b6601c7b91a
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen/* Copyright (c) 2002-2011 Dovecot authors, see the included COPYING file */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#define PROXY_FAILURE_MSG "Account is temporarily unavailable."
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#define LOGIN_DNS_CLIENT_SOCKET_PATH "dns-client"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen/* If we've been waiting auth server to respond for over this many milliseconds,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen send a "waiting" message. */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (client->auth_initializing || client->destroyed)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen client->io = io_add(client->fd, IO_READ, client_input, client);
17fe695b985e9d6e9dc39c05b24e6b3c3b7e1ba1Timo Sirainenstatic void client_auth_waiting_timeout(struct client *client)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen client_send_line(client, CLIENT_CMD_REPLY_STATUS,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen AUTH_SERVER_WAITING_MSG : AUTH_MASTER_WAITING_MSG);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid client_set_auth_waiting(struct client *client)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic void client_auth_parse_args(struct client *client,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *const *args,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen reply_r->proxy_timeout_msecs = 1000*atoi(value);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen reply_r->ssl_flags |= PROXY_SSL_FLAG_ANY_CERT;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen reply_r->port = login_binary->default_ssl_port;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen reply_r->ssl_flags |= PROXY_SSL_FLAG_ANY_CERT;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* already handled in login-common */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_debug("Ignoring unknown passdb extra field: %s", key);
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainenstatic void proxy_free_password(struct client *client)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen safe_memset(client->proxy_password, 0, strlen(client->proxy_password));
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid client_proxy_finish_destroy_client(struct client *client)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen str_printfa(str, "proxy(%s): started proxying to %s:%u",
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (strcmp(client->virtual_user, client->proxy_user) != 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* remote username is different, log it */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen str_printfa(str, " (master %s)", client->proxy_master_user);
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainenvoid client_proxy_log_failure(struct client *client, const char *line)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen str_printfa(str, "proxy(%s): Login failed to %s:%u",
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (strcmp(client->virtual_user, client->proxy_user) != 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* remote username is different, log it */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen str_printfa(str, " (master %s)", client->proxy_master_user);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid client_proxy_failed(struct client *client, bool send_line)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen client_send_line(client, CLIENT_CMD_REPLY_AUTH_FAIL_TEMP,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* call this last - it may destroy the client */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic const char *get_disconnect_reason(struct istream *input)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return errno == 0 || errno == EPIPE ? "Connection closed" :
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen /* we're just freeing the proxy */
17fe695b985e9d6e9dc39c05b24e6b3c3b7e1ba1Timo Sirainen input = login_proxy_get_istream(client->login_proxy);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* we came here from client_destroy() */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* failed for some reason, probably server disconnected */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen client_log_err(client, "proxy: Remote input buffer full");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "proxy: Remote %s:%u disconnected: %s (state=%u)",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen get_disconnect_reason(input), client->proxy_state));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen while ((line = i_stream_next_line(input)) != NULL) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (client->v.proxy_parse_line(client, line) != 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen client_log_err(client, "proxy: password not given");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen client_send_line(client, CLIENT_CMD_REPLY_AUTH_FAIL_TEMP,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (reply->host == NULL || *reply->host == '\0') {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen client_log_err(client, "proxy: host not given");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen client_send_line(client, CLIENT_CMD_REPLY_AUTH_FAIL_TEMP,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* connection_queue_add() decided that we were the oldest
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen connection and killed us. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (login_proxy_is_ourself(client, reply->host, reply->port,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen client_log_err(client, "Proxying loops to itself");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen client_send_line(client, CLIENT_CMD_REPLY_AUTH_FAIL_TEMP,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen proxy_set.dns_client_socket_path = LOGIN_DNS_CLIENT_SOCKET_PATH;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen proxy_set.connect_timeout_msecs = reply->proxy_timeout_msecs;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen proxy_set.notify_refresh_secs = reply->proxy_refresh_secs;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (login_proxy_new(client, &proxy_set, proxy_input) < 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen client_send_line(client, CLIENT_CMD_REPLY_AUTH_FAIL_TEMP,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen client->proxy_user = i_strdup(reply->destuser);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen client->proxy_master_user = i_strdup(reply->master_user);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen client->proxy_password = i_strdup(reply->password);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* disable input until authentication is finished */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenclient_auth_handle_reply(struct client *client,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const struct client_auth_reply *reply, bool success)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* we want to proxy the connection to another server.
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen don't do this unless authentication succeeded. with
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen master user proxying we can get FAIL with proxy still set.
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen proxy host=.. [port=..] [destuser=..] pass=.. */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return client->v.auth_handle_reply(client, reply);
9240d99920783c56405dda74a1f6c7ff1ebed8e6Timo Sirainenstatic int client_auth_read_line(struct client *client)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const unsigned char *data;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen unsigned int len;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (i_stream_read_data(client->input, &data, &size, 0) == -1) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* see if we have a full line */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen for (i = 0; i < size; i++) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (str_len(client->auth_response) + i > CLIENT_AUTH_BUF_MAX_SIZE) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen client_destroy(client, "Authentication response too large");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_stream_skip(client->input, i == size ? size : i+1);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* drop trailing \r */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (len > 0 && str_c(client->auth_response)[len-1] == '\r')
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenint client_auth_parse_response(struct client *client)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if ((ret = client_auth_read_line(client)) <= 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (strcmp(str_c(client->auth_response), "*") == 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic void client_auth_input(struct client *client)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (client->v.auth_parse_response(client) <= 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen auth_client_request_continue(client->auth_request,
b2d562f9c7fd13f9a16e9b3bcee904630b80b1feTimo Sirainen memset(str_c_modifiable(client->auth_response), 0,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid client_auth_send_challenge(struct client *client, const char *data)
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainensasl_callback(struct client *client, enum sasl_server_reply sasl_reply,
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen sasl_reply == SASL_SERVER_REPLY_AUTH_ABORTED ||
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen sasl_reply == SASL_SERVER_REPLY_MASTER_FAILED);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (client_auth_handle_reply(client, &reply, TRUE))
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (client_auth_handle_reply(client, &reply, FALSE))
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (sasl_reply == SASL_SERVER_REPLY_AUTH_ABORTED) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen client_send_line(client, CLIENT_CMD_REPLY_BAD,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "Authentication aborted by client.");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen client_send_line(client, CLIENT_CMD_REPLY_AUTH_FAILED,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* authentication itself succeeded, we just hit some
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen internal failure. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* the fd may still be hanging somewhere in kernel or another
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen process. make sure the client gets disconnected. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (shutdown(client->fd, SHUT_RDWR) < 0 && errno != ENOTCONN)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenint client_auth_begin(struct client *client, const char *mech_name,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (!client->secured && strcmp(client->set->ssl, "required") == 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "SSL required for authentication");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen client_send_line(client, CLIENT_CMD_REPLY_AUTH_FAIL_NOSSL,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "Authentication not allowed until SSL/TLS is enabled.");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen client->auth_response = str_new(default_pool, 256);
e3540e734a79fd4f971652925079c2e26a4b5524Timo Sirainen sasl_server_auth_begin(client, login_binary->protocol, mech_name,
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen /* don't handle input until we get the initial auth reply */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenbool client_check_plaintext_auth(struct client *client, bool pass_sent)
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen if (client->secured || !client->set->disable_plaintext_auth)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "Plaintext authentication disabled");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen client_send_line(client, CLIENT_CMD_REPLY_STATUS_BAD,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "Plaintext authentication not allowed "
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "without SSL/TLS, but your client did it anyway. "
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "If anyone was listening, the password was exposed.");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen client_send_line(client, CLIENT_CMD_REPLY_AUTH_FAIL_NOSSL,
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen for (client = clients; client != NULL; client = next) {