pop3-proxy.c revision 01cd9d4a8050a1dbf1da2c830f9755a45d6d004a
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen/* Copyright (c) 2004-2012 Dovecot authors, see the included COPYING file */
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "login-common.h"
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen#include "ioloop.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "istream.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "ostream.h"
bdd7a96c363346f7c38f389791be1487ca08775bTimo Sirainen#include "base64.h"
bdd7a96c363346f7c38f389791be1487ca08775bTimo Sirainen#include "safe-memset.h"
cc833a7a4e2258afdc834ace4bfe6579820a1df3Timo Sirainen#include "str.h"
cc833a7a4e2258afdc834ace4bfe6579820a1df3Timo Sirainen#include "str-sanitize.h"
97cb20eb77d486ef67eac50567e3080faca025c1Timo Sirainen#include "client.h"
97cb20eb77d486ef67eac50567e3080faca025c1Timo Sirainen#include "pop3-proxy.h"
cc833a7a4e2258afdc834ace4bfe6579820a1df3Timo Sirainen
7e235b3a5f622813121cd18f351e036650aaf8f8Timo Sirainenstatic void proxy_free_password(struct client *client)
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainen{
7e235b3a5f622813121cd18f351e036650aaf8f8Timo Sirainen if (client->proxy_password == NULL)
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainen return;
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainen
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainen safe_memset(client->proxy_password, 0, strlen(client->proxy_password));
863ea896fb31a16d1baec31e57650243b5547db6Timo Sirainen i_free_and_null(client->proxy_password);
863ea896fb31a16d1baec31e57650243b5547db6Timo Sirainen}
b66a207ddcfc72a634186ec7e9a82df28ffc1d4eTimo Sirainen
471e447023ab73a73f0f78da2afc0c55905330ddTimo Sirainenstatic void get_plain_auth(struct client *client, string_t *dest)
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen{
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen string_t *str;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen str = t_str_new(128);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen str_append(str, client->proxy_user);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen str_append_c(str, '\0');
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen str_append(str, client->proxy_master_user);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen str_append_c(str, '\0');
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen str_append(str, client->proxy_password);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen base64_encode(str_data(str), str_len(str), dest);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void proxy_send_login(struct pop3_client *client, struct ostream *output)
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen{
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen string_t *str;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (client->proxy_xclient) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* remote supports XCLIENT, send it */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (void)o_stream_send_str(output, t_strdup_printf(
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "XCLIENT ADDR=%s PORT=%u\r\n",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen net_ip2addr(&client->common.ip),
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client->common.remote_port));
55a210942dc7da58b2fd0b11bed8da6b030af5c1Timo Sirainen }
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen str = t_str_new(128);
52d2b356e3ddb4e59ee09c10d47add9d3280284bAki Tuomi if (client->common.proxy_master_user == NULL) {
52d2b356e3ddb4e59ee09c10d47add9d3280284bAki Tuomi /* send USER command */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen str_append(str, "USER ");
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen str_append(str, client->common.proxy_user);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen str_append(str, "\r\n");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* master user login - use AUTH PLAIN. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen str_append(str, "AUTH PLAIN\r\n");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen (void)o_stream_send(output, str_data(str), str_len(str));
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen client->common.proxy_state = POP3_PROXY_LOGIN1;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen}
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainenint pop3_proxy_parse_line(struct client *client, const char *line)
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen{
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen struct pop3_client *pop3_client = (struct pop3_client *)client;
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen struct ostream *output;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen enum login_proxy_ssl_flags ssl_flags;
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen string_t *str;
88b8aea03a24ef7a9efc30399080487b7eb03537Timo Sirainen
88b8aea03a24ef7a9efc30399080487b7eb03537Timo Sirainen i_assert(!client->destroyed);
88b8aea03a24ef7a9efc30399080487b7eb03537Timo Sirainen
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen output = login_proxy_get_ostream(client->login_proxy);
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen switch (client->proxy_state) {
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen case POP3_PROXY_BANNER:
8872e5c991430f96138a46e36b7f3c2c40d8e5c2Timo Sirainen /* this is a banner */
651fc0f1e43fef3e02e0e7b5f498973b05f641d7Timo Sirainen if (strncmp(line, "+OK", 3) != 0) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen client_log_err(client, t_strdup_printf(
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen "proxy: Remote returned invalid banner: %s",
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen str_sanitize(line, 160)));
d9fda7e3a0fa5551547ac3e3054b837fc77f4bfbTimo Sirainen client_proxy_failed(client, TRUE);
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen return -1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen }
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen pop3_client->proxy_xclient =
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen strncmp(line+3, " [XCLIENT]", 10) == 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ssl_flags = login_proxy_get_ssl_flags(client->login_proxy);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((ssl_flags & PROXY_SSL_FLAG_STARTTLS) == 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen proxy_send_login(pop3_client, output);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else {
029cfcdce65b284d5230adf1c920a5f526b03b5cTimo Sirainen (void)o_stream_send_str(output, "STLS\r\n");
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen client->proxy_state = POP3_PROXY_STARTTLS;
45e62043058738e294f89504c319d852e25943ccTimo Sirainen }
45e62043058738e294f89504c319d852e25943ccTimo Sirainen return 0;
45e62043058738e294f89504c319d852e25943ccTimo Sirainen case POP3_PROXY_STARTTLS:
45e62043058738e294f89504c319d852e25943ccTimo Sirainen if (strncmp(line, "+OK", 3) != 0) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen client_log_err(client, t_strdup_printf(
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen "proxy: Remote STLS failed: %s",
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen str_sanitize(line, 160)));
d5960ce1c0adda5c9e259bc429123ebc29c60baeTimo Sirainen client_proxy_failed(client, TRUE);
d5960ce1c0adda5c9e259bc429123ebc29c60baeTimo Sirainen return -1;
13c6532dc104d23061e6901783ceb1ff8872c206Timo Sirainen }
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen if (login_proxy_starttls(client->login_proxy) < 0) {
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen client_proxy_failed(client, TRUE);
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* i/ostreams changed. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen output = login_proxy_get_ostream(client->login_proxy);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen proxy_send_login(pop3_client, output);
6eb30032b4a50c383dea4c9c74342d906de6ad36Timo Sirainen return 1;
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainen case POP3_PROXY_LOGIN1:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen str = t_str_new(128);
bdd7a96c363346f7c38f389791be1487ca08775bTimo Sirainen if (client->proxy_master_user == NULL) {
bdd7a96c363346f7c38f389791be1487ca08775bTimo Sirainen if (strncmp(line, "+OK", 3) != 0)
bdd7a96c363346f7c38f389791be1487ca08775bTimo Sirainen break;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* USER successful, send PASS */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen str_append(str, "PASS ");
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen str_append(str, client->proxy_password);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen str_append(str, "\r\n");
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen } else {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (*line != '+')
c0d1bfc45e224251cb549de8d8804861e8acb517Timo Sirainen break;
c0d1bfc45e224251cb549de8d8804861e8acb517Timo Sirainen /* AUTH successful, send the authentication data */
c0d1bfc45e224251cb549de8d8804861e8acb517Timo Sirainen get_plain_auth(client, str);
c0d1bfc45e224251cb549de8d8804861e8acb517Timo Sirainen str_append(str, "\r\n");
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen }
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen (void)o_stream_send(output, str_data(str), str_len(str));
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen proxy_free_password(client);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen client->proxy_state = POP3_PROXY_LOGIN2;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return 0;
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen case POP3_PROXY_LOGIN2:
6321d9d33937c7fc13a8ff04c220a9e377efeeb8Timo Sirainen if (strncmp(line, "+OK", 3) != 0)
6321d9d33937c7fc13a8ff04c220a9e377efeeb8Timo Sirainen break;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen /* Login successful. Send this line to client. */
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen line = t_strconcat(line, "\r\n", NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (void)o_stream_send_str(client->output, line);
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen
ce9d23c7c1e621398d2572a1d95171136f7ef6a2Timo Sirainen client_proxy_finish_destroy_client(client);
5b809b97673fb0a73aa5b9d82122612d699f6c5bTimo Sirainen return 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* Login failed. Pass through the error message to client.
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen If the backend server isn't Dovecot, the error message may
6ded8819b9002150a95a7615e4f64f091c250464Timo Sirainen be different from Dovecot's "user doesn't exist" error. This
6ded8819b9002150a95a7615e4f64f091c250464Timo Sirainen would allow an attacker to find out what users exist in the
2f8da04d700cc23fcd6630226a4866e828b761bdTimo Sirainen system.
2f8da04d700cc23fcd6630226a4866e828b761bdTimo Sirainen
b87a4156eca6dcf6b29c504eb0cb9be2fdb11b63Timo Sirainen The optimal way to handle this would be to replace the
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen backend's "password failed" error message with Dovecot's
92dab926b2f2270057b40a907a00cf8eb2309ed6Timo Sirainen AUTH_FAILED_MSG, but this would require a new setting and
92dab926b2f2270057b40a907a00cf8eb2309ed6Timo Sirainen the sysadmin to actually bother setting it properly.
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen So for now we'll just forward the error message. This
a0c8af555ec481ab12c2a99518cf7b20debd1627Timo Sirainen shouldn't be a real problem since of course everyone will
a0c8af555ec481ab12c2a99518cf7b20debd1627Timo Sirainen be using only Dovecot as their backend :) */
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (strncmp(line, "-ERR ", 5) != 0) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen client_send_reply(client, POP3_CMD_REPLY_ERROR,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen AUTH_FAILED_MSG);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen } else {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client_send_raw(client, t_strconcat(line, "\r\n", NULL));
}
if (client->set->auth_verbose) {
if (strncmp(line, "-ERR ", 5) == 0)
line += 5;
client_proxy_log_failure(client, line);
}
client->proxy_auth_failed = TRUE;
client_proxy_failed(client, FALSE);
return -1;
}
void pop3_proxy_reset(struct client *client)
{
client->proxy_state = POP3_PROXY_BANNER;
}
void pop3_proxy_error(struct client *client, const char *text)
{
client_send_reply(client, POP3_CMD_REPLY_ERROR, text);
}