pop3-proxy.c revision e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2004-2012 Dovecot authors, see the included COPYING file */
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen
08d6658a4e2ec8104cd1307f6baa75fdb07a24f8Mark Washenberger#include "login-common.h"
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen#include "ioloop.h"
6789ed17e7ca4021713507baf0dcf6979bb42e0cTimo Sirainen#include "istream.h"
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen#include "ostream.h"
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen#include "base64.h"
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen#include "safe-memset.h"
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen#include "str.h"
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen#include "str-sanitize.h"
636f017be100bce67d66fd3ae1544a47681efd33Timo Sirainen#include "client.h"
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen#include "pop3-proxy.h"
08d6658a4e2ec8104cd1307f6baa75fdb07a24f8Mark Washenberger
06ff2a72c39cb34cc6425f17fc82c5e93fef2018Timo Sirainenstatic void proxy_free_password(struct client *client)
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (client->proxy_password == NULL)
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen return;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
de76b960297406115cf6bae473f004c08174b16aTimo Sirainen safe_memset(client->proxy_password, 0, strlen(client->proxy_password));
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen i_free_and_null(client->proxy_password);
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen}
c519de264df14a9d525e2604671c332590ce54e3Timo Sirainen
61530b48694398df42744204e35535dbe3f745c4Timo Sirainenstatic void get_plain_auth(struct client *client, string_t *dest)
61530b48694398df42744204e35535dbe3f745c4Timo Sirainen{
3ddbbe03fe74b3ee7b1dff4e08ec706d7880d052Timo Sirainen string_t *str;
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen str = t_str_new(128);
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen str_append(str, client->proxy_user);
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen str_append_c(str, '\0');
6789ed17e7ca4021713507baf0dcf6979bb42e0cTimo Sirainen str_append(str, client->proxy_master_user);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen str_append_c(str, '\0');
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen str_append(str, client->proxy_password);
6789ed17e7ca4021713507baf0dcf6979bb42e0cTimo Sirainen base64_encode(str_data(str), str_len(str), dest);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen}
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainenstatic void proxy_send_login(struct pop3_client *client, struct ostream *output)
2b3b0df76184799317584b596af8df5afec3ebddTimo Sirainen{
c9dea5c23355dea35c6fa423de69f6507852efe4Timo Sirainen string_t *str;
6789ed17e7ca4021713507baf0dcf6979bb42e0cTimo Sirainen
6789ed17e7ca4021713507baf0dcf6979bb42e0cTimo Sirainen i_assert(client->common.proxy_ttl > 0);
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen if (client->proxy_xclient) {
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen /* remote supports XCLIENT, send it */
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen o_stream_nsend_str(output, t_strdup_printf(
d244c6cadd5f077f5d0f1e00c3652d0108a2d908Timo Sirainen "XCLIENT ADDR=%s PORT=%u SESSION=%s TTL=%u\r\n",
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen net_ip2addr(&client->common.ip),
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen client->common.remote_port,
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen client_get_session_id(&client->common),
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen client->common.proxy_ttl - 1));
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen client->common.proxy_state = POP3_PROXY_XCLIENT;
d244c6cadd5f077f5d0f1e00c3652d0108a2d908Timo Sirainen } else {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client->common.proxy_state = POP3_PROXY_LOGIN1;
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen }
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen
d244c6cadd5f077f5d0f1e00c3652d0108a2d908Timo Sirainen str = t_str_new(128);
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen if (client->common.proxy_master_user == NULL) {
fde0b1793a2842da00eaa105d5e13fec465f0443Timo Sirainen /* send USER command */
baf1148108b7d9739626b47cc57298c36929586aTimo Sirainen str_append(str, "USER ");
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen str_append(str, client->common.proxy_user);
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen str_append(str, "\r\n");
baf1148108b7d9739626b47cc57298c36929586aTimo Sirainen } else {
baf1148108b7d9739626b47cc57298c36929586aTimo Sirainen /* master user login - use AUTH PLAIN. */
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen str_append(str, "AUTH PLAIN\r\n");
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen }
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen o_stream_nsend(output, str_data(str), str_len(str));
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen}
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainenint pop3_proxy_parse_line(struct client *client, const char *line)
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen{
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen struct pop3_client *pop3_client = (struct pop3_client *)client;
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen struct ostream *output;
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen enum login_proxy_ssl_flags ssl_flags;
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen string_t *str;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen i_assert(!client->destroyed);
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen output = login_proxy_get_ostream(client->login_proxy);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen switch (client->proxy_state) {
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen case POP3_PROXY_BANNER:
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen /* this is a banner */
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen if (strncmp(line, "+OK", 3) != 0) {
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen client_log_err(client, t_strdup_printf(
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen "proxy: Remote returned invalid banner: %s",
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen str_sanitize(line, 160)));
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen client_proxy_failed(client, TRUE);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return -1;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen }
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen pop3_client->proxy_xclient =
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen strncmp(line+3, " [XCLIENT]", 10) == 0;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen ssl_flags = login_proxy_get_ssl_flags(client->login_proxy);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if ((ssl_flags & PROXY_SSL_FLAG_STARTTLS) == 0) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen proxy_send_login(pop3_client, output);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen } else {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen o_stream_nsend_str(output, "STLS\r\n");
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen client->proxy_state = POP3_PROXY_STARTTLS;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen }
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return 0;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen case POP3_PROXY_STARTTLS:
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (strncmp(line, "+OK", 3) != 0) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen client_log_err(client, t_strdup_printf(
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen "proxy: Remote STLS failed: %s",
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen str_sanitize(line, 160)));
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen client_proxy_failed(client, TRUE);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return -1;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen }
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (login_proxy_starttls(client->login_proxy) < 0) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen client_proxy_failed(client, TRUE);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return -1;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen }
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* i/ostreams changed. */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen output = login_proxy_get_ostream(client->login_proxy);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen proxy_send_login(pop3_client, output);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return 1;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen case POP3_PROXY_XCLIENT:
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen if (strncmp(line, "+OK", 3) != 0) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen client_log_err(client, t_strdup_printf(
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen "proxy: Remote XCLIENT failed: %s",
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen str_sanitize(line, 160)));
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen client_proxy_failed(client, TRUE);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return -1;
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen }
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen client->proxy_state = POP3_PROXY_LOGIN1;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen return 0;
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen case POP3_PROXY_LOGIN1:
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen str = t_str_new(128);
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen if (client->proxy_master_user == NULL) {
8039af9679af6fb56116b353fe44f7dd4c08f031Timo Sirainen if (strncmp(line, "+OK", 3) != 0)
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen break;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen /* USER successful, send PASS */
2cfe9983ce7a6280636ee12beccc2e865111967bTimo Sirainen str_append(str, "PASS ");
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen str_append(str, client->proxy_password);
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen str_append(str, "\r\n");
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen } else {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (*line != '+')
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen break;
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen /* AUTH successful, send the authentication data */
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen get_plain_auth(client, str);
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen str_append(str, "\r\n");
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen }
d10a370b2614712d9cb6a1dd8625f62a071b6377Timo Sirainen o_stream_nsend(output, str_data(str), str_len(str));
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen proxy_free_password(client);
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen client->proxy_state = POP3_PROXY_LOGIN2;
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen return 0;
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen case POP3_PROXY_LOGIN2:
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen if (strncmp(line, "+OK", 3) != 0)
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen break;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen /* Login successful. Send this line to client. */
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen line = t_strconcat(line, "\r\n", NULL);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen o_stream_nsend_str(client->output, line);
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen client_proxy_finish_destroy_client(client);
e20e638805c4bd54e039891a3e92760b1dfa189aTimo Sirainen return 1;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* Login failed. Pass through the error message to client.
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen If the backend server isn't Dovecot, the error message may
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen be different from Dovecot's "user doesn't exist" error. This
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen would allow an attacker to find out what users exist in the
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen system.
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen The optimal way to handle this would be to replace the
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen backend's "password failed" error message with Dovecot's
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen AUTH_FAILED_MSG, but this would require a new setting and
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen the sysadmin to actually bother setting it properly.
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen So for now we'll just forward the error message. This
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen shouldn't be a real problem since of course everyone will
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen be using only Dovecot as their backend :) */
d6c5ceea8521b92d10e51a59da00c792f6140b1dTimo Sirainen if (strncmp(line, "-ERR ", 5) != 0) {
88ea893b45d3ed8d68000921db9156c03cbe1b00Timo Sirainen client_send_reply(client, POP3_CMD_REPLY_ERROR,
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen AUTH_FAILED_MSG);
5ce2084ada06ade9f44fc2914c34658e9a842dc1Timo Sirainen } else {
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen client_send_raw(client, t_strconcat(line, "\r\n", NULL));
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen }
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen if (client->set->auth_verbose) {
4145aa5025b57ec64418e503c2a5a6bf5a02aec5Timo Sirainen if (strncmp(line, "-ERR ", 5) == 0)
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen line += 5;
905951e448e0d0f0778f43ce7673d0cac60b9b61Timo Sirainen client_proxy_log_failure(client, line);
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen }
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen client->proxy_auth_failed = TRUE;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen client_proxy_failed(client, FALSE);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen return -1;
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen}
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainenvoid pop3_proxy_reset(struct client *client)
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen{
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen client->proxy_state = POP3_PROXY_BANNER;
e82e363e7a6917f470412d629db6c5b1f5891a35Timo Sirainen}
eef4ba0cc3e78f8c26804c1c9251a76580a41f0cTimo Sirainen
905951e448e0d0f0778f43ce7673d0cac60b9b61Timo Sirainenvoid pop3_proxy_error(struct client *client, const char *text)
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen{
905951e448e0d0f0778f43ce7673d0cac60b9b61Timo Sirainen client_send_reply(client, POP3_CMD_REPLY_ERROR, text);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen}
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen