pop3-proxy.c revision 5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2004-2013 Dovecot authors, see the included COPYING file */
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen#include "login-common.h"
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen#include "ioloop.h"
70ead6466f9baa8294e71fc2fba0a4f54f488b5eTimo Sirainen#include "istream.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "ostream.h"
dd7cbb32412c2f4d2d223af66672535bc1237246Timo Sirainen#include "base64.h"
57f5683fd9dc9bc79816c418bb30fdbc33b68a8cTimo Sirainen#include "safe-memset.h"
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen#include "str.h"
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen#include "str-sanitize.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "client.h"
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen#include "pop3-proxy.h"
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic void proxy_free_password(struct client *client)
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen{
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (client->proxy_password == NULL)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen return;
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen
70ead6466f9baa8294e71fc2fba0a4f54f488b5eTimo Sirainen safe_memset(client->proxy_password, 0, strlen(client->proxy_password));
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen i_free_and_null(client->proxy_password);
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen}
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainenstatic void get_plain_auth(struct client *client, string_t *dest)
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen{
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen string_t *str;
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen str = t_str_new(128);
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen str_append(str, client->proxy_user);
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen str_append_c(str, '\0');
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen str_append(str, client->proxy_master_user);
318ef3683d67683173f1b552cf5f9af4375b3017Timo Sirainen str_append_c(str, '\0');
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen str_append(str, client->proxy_password);
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen base64_encode(str_data(str), str_len(str), dest);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen}
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenstatic void proxy_send_login(struct pop3_client *client, struct ostream *output)
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen{
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen string_t *str;
a8d47e2427558d5011dfc75694b704760c1ef8baTimo Sirainen
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen i_assert(client->common.proxy_ttl > 0);
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen if (client->proxy_xclient) {
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen /* remote supports XCLIENT, send it */
4c892b0d94c5b1d6853dbe8e0b38059ea5b08ecaTimo Sirainen o_stream_nsend_str(output, t_strdup_printf(
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen "XCLIENT ADDR=%s PORT=%u SESSION=%s TTL=%u\r\n",
abc79eec93e58e0152cd1d483f37be66c26811b9Timo Sirainen net_ip2addr(&client->common.ip),
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen client->common.remote_port,
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen client_get_session_id(&client->common),
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen client->common.proxy_ttl - 1));
4c892b0d94c5b1d6853dbe8e0b38059ea5b08ecaTimo Sirainen client->common.proxy_state = POP3_PROXY_XCLIENT;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen } else {
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen client->common.proxy_state = POP3_PROXY_LOGIN1;
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen }
013a8a91c83c6ea24bc75322b81235f19e26fa8fTimo Sirainen
a8d47e2427558d5011dfc75694b704760c1ef8baTimo Sirainen str = t_str_new(128);
a8d47e2427558d5011dfc75694b704760c1ef8baTimo Sirainen if (client->common.proxy_master_user == NULL) {
a8d47e2427558d5011dfc75694b704760c1ef8baTimo Sirainen /* send USER command */
a8d47e2427558d5011dfc75694b704760c1ef8baTimo Sirainen str_append(str, "USER ");
a8d47e2427558d5011dfc75694b704760c1ef8baTimo Sirainen str_append(str, client->common.proxy_user);
a8d47e2427558d5011dfc75694b704760c1ef8baTimo Sirainen str_append(str, "\r\n");
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen } else {
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen /* master user login - use AUTH PLAIN. */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen str_append(str, "AUTH PLAIN\r\n");
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen o_stream_nsend(output, str_data(str), str_len(str));
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen}
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainenint pop3_proxy_parse_line(struct client *client, const char *line)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen{
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen struct pop3_client *pop3_client = (struct pop3_client *)client;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen struct ostream *output;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen enum login_proxy_ssl_flags ssl_flags;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen string_t *str;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen i_assert(!client->destroyed);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen output = login_proxy_get_ostream(client->login_proxy);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen switch (client->proxy_state) {
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen case POP3_PROXY_BANNER:
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen /* this is a banner */
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if (strncmp(line, "+OK", 3) != 0) {
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen client_log_err(client, t_strdup_printf(
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen "proxy: Remote returned invalid banner: %s",
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen str_sanitize(line, 160)));
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen client_proxy_failed(client, TRUE);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen return -1;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen }
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen pop3_client->proxy_xclient =
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen strncmp(line+3, " [XCLIENT]", 10) == 0;
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen ssl_flags = login_proxy_get_ssl_flags(client->login_proxy);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if ((ssl_flags & PROXY_SSL_FLAG_STARTTLS) == 0) {
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen proxy_send_login(pop3_client, output);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen } else {
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen o_stream_nsend_str(output, "STLS\r\n");
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen client->proxy_state = POP3_PROXY_STARTTLS;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen return 0;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen case POP3_PROXY_STARTTLS:
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen if (strncmp(line, "+OK", 3) != 0) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen client_log_err(client, t_strdup_printf(
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen "proxy: Remote STLS failed: %s",
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen str_sanitize(line, 160)));
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen client_proxy_failed(client, TRUE);
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen return -1;
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen }
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen if (login_proxy_starttls(client->login_proxy) < 0) {
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen client_proxy_failed(client, TRUE);
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen return -1;
39993536eaef0a23954105e41040dcf88afd2e7eTimo Sirainen }
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen /* i/ostreams changed. */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen output = login_proxy_get_ostream(client->login_proxy);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen proxy_send_login(pop3_client, output);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return 1;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen case POP3_PROXY_XCLIENT:
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (strncmp(line, "+OK", 3) != 0) {
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen client_log_err(client, t_strdup_printf(
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen "proxy: Remote XCLIENT failed: %s",
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen str_sanitize(line, 160)));
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen client_proxy_failed(client, TRUE);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen return -1;
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen }
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen client->proxy_state = POP3_PROXY_LOGIN1;
5666a3d6a7ea89362b8d9e8b39b15424cd9d6388Timo Sirainen return 0;
a26b7e87b4157cfa800f9bcd8c4c044462d21268Timo Sirainen case POP3_PROXY_LOGIN1:
a26b7e87b4157cfa800f9bcd8c4c044462d21268Timo Sirainen str = t_str_new(128);
a26b7e87b4157cfa800f9bcd8c4c044462d21268Timo Sirainen if (client->proxy_master_user == NULL) {
a26b7e87b4157cfa800f9bcd8c4c044462d21268Timo Sirainen if (strncmp(line, "+OK", 3) != 0)
a26b7e87b4157cfa800f9bcd8c4c044462d21268Timo Sirainen break;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen /* USER successful, send PASS */
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen str_append(str, "PASS ");
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen str_append(str, client->proxy_password);
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen str_append(str, "\r\n");
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen } else {
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen if (*line != '+')
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen break;
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen /* AUTH successful, send the authentication data */
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen get_plain_auth(client, str);
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen str_append(str, "\r\n");
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen }
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen o_stream_nsend(output, str_data(str), str_len(str));
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen proxy_free_password(client);
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen client->proxy_state = POP3_PROXY_LOGIN2;
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen return 0;
d80f37f025593d959bdfa9c378915e4322f4f504Timo Sirainen case POP3_PROXY_LOGIN2:
e51cfb5506de764499cb5b81a098b23cf46f90f1Timo Sirainen if (strncmp(line, "+OK", 3) != 0)
e51cfb5506de764499cb5b81a098b23cf46f90f1Timo Sirainen break;
e51cfb5506de764499cb5b81a098b23cf46f90f1Timo Sirainen
e51cfb5506de764499cb5b81a098b23cf46f90f1Timo Sirainen /* Login successful. Send this line to client. */
e51cfb5506de764499cb5b81a098b23cf46f90f1Timo Sirainen line = t_strconcat(line, "\r\n", NULL);
e51cfb5506de764499cb5b81a098b23cf46f90f1Timo Sirainen o_stream_nsend_str(client->output, line);
e51cfb5506de764499cb5b81a098b23cf46f90f1Timo Sirainen
e51cfb5506de764499cb5b81a098b23cf46f90f1Timo Sirainen client_proxy_finish_destroy_client(client);
e51cfb5506de764499cb5b81a098b23cf46f90f1Timo Sirainen return 1;
e51cfb5506de764499cb5b81a098b23cf46f90f1Timo Sirainen }
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen
67c47dbb3fde79218320fd38a45c33f61bbf3012Timo Sirainen /* Login failed. Pass through the error message to client.
a443e5aaf632257bfd1e7aa9b3c42c09512bbe43Timo Sirainen
a443e5aaf632257bfd1e7aa9b3c42c09512bbe43Timo Sirainen If the backend server isn't Dovecot, the error message may
a443e5aaf632257bfd1e7aa9b3c42c09512bbe43Timo Sirainen be different from Dovecot's "user doesn't exist" error. This
a443e5aaf632257bfd1e7aa9b3c42c09512bbe43Timo Sirainen would allow an attacker to find out what users exist in the
a443e5aaf632257bfd1e7aa9b3c42c09512bbe43Timo Sirainen system.
a443e5aaf632257bfd1e7aa9b3c42c09512bbe43Timo Sirainen
a443e5aaf632257bfd1e7aa9b3c42c09512bbe43Timo Sirainen The optimal way to handle this would be to replace the
a443e5aaf632257bfd1e7aa9b3c42c09512bbe43Timo Sirainen backend's "password failed" error message with Dovecot's
a443e5aaf632257bfd1e7aa9b3c42c09512bbe43Timo Sirainen AUTH_FAILED_MSG, but this would require a new setting and
a443e5aaf632257bfd1e7aa9b3c42c09512bbe43Timo Sirainen the sysadmin to actually bother setting it properly.
a443e5aaf632257bfd1e7aa9b3c42c09512bbe43Timo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen So for now we'll just forward the error message. This
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen shouldn't be a real problem since of course everyone will
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen be using only Dovecot as their backend :) */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (strncmp(line, "-ERR ", 5) != 0) {
013a8a91c83c6ea24bc75322b81235f19e26fa8fTimo Sirainen client_send_reply(client, POP3_CMD_REPLY_ERROR,
013a8a91c83c6ea24bc75322b81235f19e26fa8fTimo Sirainen AUTH_FAILED_MSG);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen } else {
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen client_send_raw(client, t_strconcat(line, "\r\n", NULL));
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if (client->set->auth_verbose) {
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen if (strncmp(line, "-ERR ", 5) == 0)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen line += 5;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen client_proxy_log_failure(client, line);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen client->proxy_auth_failed = TRUE;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen client_proxy_failed(client, FALSE);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen return -1;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen}
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenvoid pop3_proxy_reset(struct client *client)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen{
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen client->proxy_state = POP3_PROXY_BANNER;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen}
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenvoid pop3_proxy_error(struct client *client, const char *text)
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen{
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen client_send_reply(client, POP3_CMD_REPLY_ERROR, text);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen}
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen