pop3-proxy.c revision 80980955bb1bbcc1bd73623fe0912f334194ddd2
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2004-2011 Dovecot authors, see the included COPYING file */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen#include "login-common.h"
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen#include "ioloop.h"
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen#include "istream.h"
cbc61fcb33b370d049c16a3c44568b4deb4e2b33Timo Sirainen#include "ostream.h"
a1607f6001a9949e1cf9d49eb0aa936dbb4c77ffTimo Sirainen#include "base64.h"
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen#include "safe-memset.h"
00d58fcfe8191d6ce7efa801d289a5c0fe88d1aeTimo Sirainen#include "str.h"
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen#include "str-sanitize.h"
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen#include "client.h"
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen#include "pop3-proxy.h"
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainenstatic void proxy_free_password(struct client *client)
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen{
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (client->proxy_password == NULL)
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen return;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen safe_memset(client->proxy_password, 0, strlen(client->proxy_password));
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen i_free_and_null(client->proxy_password);
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen}
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainenstatic void get_plain_auth(struct client *client, string_t *dest)
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen{
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen string_t *str;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen str = t_str_new(128);
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen str_append(str, client->proxy_user);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen str_append_c(str, '\0');
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen str_append(str, client->proxy_master_user);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen str_append_c(str, '\0');
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen str_append(str, client->proxy_password);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen base64_encode(str_data(str), str_len(str), dest);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen}
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainenstatic void proxy_send_login(struct pop3_client *client, struct ostream *output)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen{
cbc61fcb33b370d049c16a3c44568b4deb4e2b33Timo Sirainen string_t *str;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen str = t_str_new(128);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (client->common.proxy_master_user == NULL) {
4462bd7b4c7ef3de006f060e155a90e5de7cae21Timo Sirainen /* send USER command */
f6c1297c26b355c4aec2a08978f51ec3efecb351Timo Sirainen str_append(str, "USER ");
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen str_append(str, client->common.proxy_user);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen str_append(str, "\r\n");
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen } else {
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen /* master user login - use AUTH PLAIN. */
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen str_append(str, "AUTH PLAIN\r\n");
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen }
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen (void)o_stream_send(output, str_data(str), str_len(str));
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen client->common.proxy_state = POP3_PROXY_LOGIN1;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen}
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainenint pop3_proxy_parse_line(struct client *client, const char *line)
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen{
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen struct pop3_client *pop3_client = (struct pop3_client *)client;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen struct ostream *output;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen enum login_proxy_ssl_flags ssl_flags;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen string_t *str;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen i_assert(!client->destroyed);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen output = login_proxy_get_ostream(client->login_proxy);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen switch (client->proxy_state) {
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen case POP3_PROXY_BANNER:
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen /* this is a banner */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (strncmp(line, "+OK", 3) != 0) {
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen client_log_err(client, t_strdup_printf(
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen "proxy: Remote returned invalid banner: %s",
cbc61fcb33b370d049c16a3c44568b4deb4e2b33Timo Sirainen str_sanitize(line, 160)));
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen client_proxy_failed(client, TRUE);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen return -1;
cd83124e5d070a016c590bb0b1096d7828c7b6adTimo Sirainen }
cbc61fcb33b370d049c16a3c44568b4deb4e2b33Timo Sirainen
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen ssl_flags = login_proxy_get_ssl_flags(client->login_proxy);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if ((ssl_flags & PROXY_SSL_FLAG_STARTTLS) == 0) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen proxy_send_login(pop3_client, output);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen } else {
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen (void)o_stream_send_str(output, "STLS\r\n");
cbc61fcb33b370d049c16a3c44568b4deb4e2b33Timo Sirainen client->proxy_state = POP3_PROXY_STARTTLS;
e07bf3772a2bc075de4915ad0961beb8d083c22dTimo Sirainen }
e07bf3772a2bc075de4915ad0961beb8d083c22dTimo Sirainen return 0;
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen case POP3_PROXY_STARTTLS:
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (strncmp(line, "+OK", 3) != 0) {
cbc61fcb33b370d049c16a3c44568b4deb4e2b33Timo Sirainen client_log_err(client, t_strdup_printf(
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen "proxy: Remote STLS failed: %s",
e07bf3772a2bc075de4915ad0961beb8d083c22dTimo Sirainen str_sanitize(line, 160)));
e07bf3772a2bc075de4915ad0961beb8d083c22dTimo Sirainen client_proxy_failed(client, TRUE);
e07bf3772a2bc075de4915ad0961beb8d083c22dTimo Sirainen return -1;
e07bf3772a2bc075de4915ad0961beb8d083c22dTimo Sirainen }
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (login_proxy_starttls(client->login_proxy) < 0) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen client_proxy_failed(client, TRUE);
bbd4c4cf902539c25c471157eb9849459734759cTimo Sirainen return -1;
bbd4c4cf902539c25c471157eb9849459734759cTimo Sirainen }
bbd4c4cf902539c25c471157eb9849459734759cTimo Sirainen /* i/ostreams changed. */
bbd4c4cf902539c25c471157eb9849459734759cTimo Sirainen output = login_proxy_get_ostream(client->login_proxy);
bbd4c4cf902539c25c471157eb9849459734759cTimo Sirainen proxy_send_login(pop3_client, output);
bbd4c4cf902539c25c471157eb9849459734759cTimo Sirainen return 1;
bbd4c4cf902539c25c471157eb9849459734759cTimo Sirainen case POP3_PROXY_LOGIN1:
bbd4c4cf902539c25c471157eb9849459734759cTimo Sirainen str = t_str_new(128);
bbd4c4cf902539c25c471157eb9849459734759cTimo Sirainen if (client->proxy_master_user == NULL) {
bbd4c4cf902539c25c471157eb9849459734759cTimo Sirainen if (strncmp(line, "+OK", 3) != 0)
bbd4c4cf902539c25c471157eb9849459734759cTimo Sirainen break;
bbd4c4cf902539c25c471157eb9849459734759cTimo Sirainen
bbd4c4cf902539c25c471157eb9849459734759cTimo Sirainen /* USER successful, send PASS */
bbd4c4cf902539c25c471157eb9849459734759cTimo Sirainen str_append(str, "PASS ");
bbd4c4cf902539c25c471157eb9849459734759cTimo Sirainen str_append(str, client->proxy_password);
bbd4c4cf902539c25c471157eb9849459734759cTimo Sirainen str_append(str, "\r\n");
bbd4c4cf902539c25c471157eb9849459734759cTimo Sirainen } else {
bbd4c4cf902539c25c471157eb9849459734759cTimo Sirainen if (*line != '+')
bbd4c4cf902539c25c471157eb9849459734759cTimo Sirainen break;
bbd4c4cf902539c25c471157eb9849459734759cTimo Sirainen /* AUTH successful, send the authentication data */
bbd4c4cf902539c25c471157eb9849459734759cTimo Sirainen get_plain_auth(client, str);
bbd4c4cf902539c25c471157eb9849459734759cTimo Sirainen str_append(str, "\r\n");
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen }
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen (void)o_stream_send(output, str_data(str), str_len(str));
96308127e006bb3b1108093bcf4cc1fd9481cb7aTimo Sirainen proxy_free_password(client);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen client->proxy_state = POP3_PROXY_LOGIN2;
bbd4c4cf902539c25c471157eb9849459734759cTimo Sirainen return 0;
bbd4c4cf902539c25c471157eb9849459734759cTimo Sirainen case POP3_PROXY_LOGIN2:
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (strncmp(line, "+OK", 3) != 0)
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen break;
d66be2bebfa96e7d3d20e2153f60e6e25dcc9a18Timo Sirainen
e376e08040b5f21ff79a15ae728d2532a34207f6Timo Sirainen /* Login successful. Send this line to client. */
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen line = t_strconcat(line, "\r\n", NULL);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen (void)o_stream_send_str(client->output, line);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen client_proxy_finish_destroy_client(client);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen return 1;
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen }
fd35227c47190afc832579ca5c76524792701bf7Timo Sirainen
fd35227c47190afc832579ca5c76524792701bf7Timo Sirainen /* Login failed. Pass through the error message to client.
fd35227c47190afc832579ca5c76524792701bf7Timo Sirainen
fd35227c47190afc832579ca5c76524792701bf7Timo Sirainen If the backend server isn't Dovecot, the error message may
fd35227c47190afc832579ca5c76524792701bf7Timo Sirainen be different from Dovecot's "user doesn't exist" error. This
2e263a9d901483a902720a30c474761bd3324fe8Timo Sirainen would allow an attacker to find out what users exist in the
2e263a9d901483a902720a30c474761bd3324fe8Timo Sirainen system.
2e263a9d901483a902720a30c474761bd3324fe8Timo Sirainen
2e263a9d901483a902720a30c474761bd3324fe8Timo Sirainen The optimal way to handle this would be to replace the
2e263a9d901483a902720a30c474761bd3324fe8Timo Sirainen backend's "password failed" error message with Dovecot's
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen AUTH_FAILED_MSG, but this would require a new setting and
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen the sysadmin to actually bother setting it properly.
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen
96308127e006bb3b1108093bcf4cc1fd9481cb7aTimo Sirainen So for now we'll just forward the error message. This
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen shouldn't be a real problem since of course everyone will
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen be using only Dovecot as their backend :) */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (strncmp(line, "-ERR ", 5) != 0) {
d66be2bebfa96e7d3d20e2153f60e6e25dcc9a18Timo Sirainen client_send_line(client, CLIENT_CMD_REPLY_AUTH_FAILED,
d66be2bebfa96e7d3d20e2153f60e6e25dcc9a18Timo Sirainen AUTH_FAILED_MSG);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen } else {
cbc61fcb33b370d049c16a3c44568b4deb4e2b33Timo Sirainen client_send_raw(client, t_strconcat(line, "\r\n", NULL));
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen }
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
783278c012551bc2f25f065a8d3ec1a3cfc0d296Timo Sirainen if (client->set->auth_verbose) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (strncmp(line, "-ERR ", 5) == 0)
5d49cbcf87354f0ddf3b71bc5f0cefdc02b14f68Timo Sirainen line += 5;
ce3faaaaab3e2d45b023396287e02f88e5c76e74Timo Sirainen client_proxy_log_failure(client, line);
fd35227c47190afc832579ca5c76524792701bf7Timo Sirainen }
ce3faaaaab3e2d45b023396287e02f88e5c76e74Timo Sirainen client->proxy_auth_failed = TRUE;
ce3faaaaab3e2d45b023396287e02f88e5c76e74Timo Sirainen client_proxy_failed(client, FALSE);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen return -1;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen}
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainenvoid pop3_proxy_reset(struct client *client)
3e7565a7b39694bcdf448d8eb2a7f0774733297bTimo Sirainen{
3e7565a7b39694bcdf448d8eb2a7f0774733297bTimo Sirainen client->proxy_state = POP3_PROXY_BANNER;
3e7565a7b39694bcdf448d8eb2a7f0774733297bTimo Sirainen}
3e7565a7b39694bcdf448d8eb2a7f0774733297bTimo Sirainen