pop3-proxy.c revision 3612ee5c737954d5fb88fd1775aad80f7bf1dc4e
2e37d45867d081db150ab78dad303b9077aea24fTimo Sirainen/* Copyright (c) 2004-2010 Dovecot authors, see the included COPYING file */
1d4f710106fb498750456724628da6063e012e6dTimo Sirainen
46552a931924c2d743f045e95b08c3ce6beda91aTimo Sirainen#include "login-common.h"
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen#include "ioloop.h"
d3d769026fae5d21c2d29614d3bc4579e8d79e81Timo Sirainen#include "istream.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "ostream.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "base64.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "safe-memset.h"
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen#include "str.h"
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen#include "str-sanitize.h"
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen#include "client.h"
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen#include "pop3-proxy.h"
92c49f3005f4dff1a6f576fffa8112ef6d1cae7fTimo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic void proxy_free_password(struct client *client)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (client->proxy_password == NULL)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return;
4ead43ecc06d10047998966c4dc0b142ecce4b66Timo Sirainen
1d4f710106fb498750456724628da6063e012e6dTimo Sirainen safe_memset(client->proxy_password, 0, strlen(client->proxy_password));
1d4f710106fb498750456724628da6063e012e6dTimo Sirainen i_free_and_null(client->proxy_password);
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen}
9439bed2f07d6475febd8a247cd2f0990fb32a13Timo Sirainen
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainenstatic void get_plain_auth(struct client *client, string_t *dest)
ab0d9eecd85f74acae18fe88529302e0776cc500Timo Sirainen{
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainen string_t *str;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen str = t_str_new(128);
336b825e0321b798690351d9899b1b0cb99ec462Timo Sirainen str_append(str, client->proxy_user);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen str_append_c(str, '\0');
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen str_append(str, client->proxy_master_user);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen str_append_c(str, '\0');
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen str_append(str, client->proxy_password);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen base64_encode(str_data(str), str_len(str), dest);
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic void proxy_send_login(struct pop3_client *client, struct ostream *output)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen string_t *str;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen str = t_str_new(128);
f059a046515f4b2b15a6c2a10a6f12f6166e39a5Timo Sirainen if (client->common.proxy_master_user == NULL) {
f059a046515f4b2b15a6c2a10a6f12f6166e39a5Timo Sirainen /* send USER command */
f059a046515f4b2b15a6c2a10a6f12f6166e39a5Timo Sirainen str_append(str, "USER ");
f059a046515f4b2b15a6c2a10a6f12f6166e39a5Timo Sirainen str_append(str, client->common.proxy_user);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen str_append(str, "\r\n");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen } else {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* master user login - use AUTH PLAIN. */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen str_append(str, "AUTH PLAIN\r\n");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
5a250816ffc4cc5db203f9410ea99b6601c7b91aTimo Sirainen (void)o_stream_send(output, str_data(str), str_len(str));
5a250816ffc4cc5db203f9410ea99b6601c7b91aTimo Sirainen client->common.proxy_state = POP3_PROXY_LOGIN1;
46ec792dd4ccf6c34706c4774228301fafde6aa9Timo Sirainen}
46ec792dd4ccf6c34706c4774228301fafde6aa9Timo Sirainen
46ec792dd4ccf6c34706c4774228301fafde6aa9Timo Sirainenint pop3_proxy_parse_line(struct client *client, const char *line)
46ec792dd4ccf6c34706c4774228301fafde6aa9Timo Sirainen{
4c6ddf2491104f917d00e6900e833e80ea02c7b6Timo Sirainen struct pop3_client *pop3_client = (struct pop3_client *)client;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct ostream *output;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen enum login_proxy_ssl_flags ssl_flags;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen string_t *str;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_assert(!client->destroyed);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen output = login_proxy_get_ostream(client->login_proxy);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen switch (client->proxy_state) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen case POP3_PROXY_BANNER:
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* this is a banner */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (strncmp(line, "+OK", 3) != 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_log_err(client, t_strdup_printf(
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen "proxy: Remote returned invalid banner: %s",
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen str_sanitize(line, 160)));
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen client_proxy_failed(client, TRUE);
d3d769026fae5d21c2d29614d3bc4579e8d79e81Timo Sirainen return -1;
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
5a9e240ebf8d0daaf029973973b52e415148070bTimo Sirainen ssl_flags = login_proxy_get_ssl_flags(client->login_proxy);
5a9e240ebf8d0daaf029973973b52e415148070bTimo Sirainen if ((ssl_flags & PROXY_SSL_FLAG_STARTTLS) == 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen proxy_send_login(pop3_client, output);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen } else {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen (void)o_stream_send_str(output, "STLS\r\n");
f059a046515f4b2b15a6c2a10a6f12f6166e39a5Timo Sirainen client->proxy_state = POP3_PROXY_STARTTLS;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return 0;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen case POP3_PROXY_STARTTLS:
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (strncmp(line, "+OK", 3) != 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_log_err(client, t_strdup_printf(
54533aa265f5c87730022cc7576090bc51370f97Timo Sirainen "proxy: Remote STLS failed: %s",
54533aa265f5c87730022cc7576090bc51370f97Timo Sirainen str_sanitize(line, 160)));
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_proxy_failed(client, TRUE);
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainen return -1;
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (login_proxy_starttls(client->login_proxy) < 0) {
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainen client_proxy_failed(client, TRUE);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return -1;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* i/ostreams changed. */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen output = login_proxy_get_ostream(client->login_proxy);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen proxy_send_login(pop3_client, output);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen return 1;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen case POP3_PROXY_LOGIN1:
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen str = t_str_new(128);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (client->proxy_master_user == NULL) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (strncmp(line, "+OK", 3) != 0)
ad004e44be109684521494b5af2ad1da39b8bb27Timo Sirainen break;
54533aa265f5c87730022cc7576090bc51370f97Timo Sirainen
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen /* USER successful, send PASS */
d3d769026fae5d21c2d29614d3bc4579e8d79e81Timo Sirainen str_append(str, "PASS ");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen str_append(str, client->proxy_password);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen str_append(str, "\r\n");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen } else {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (*line != '+')
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen break;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* AUTH successful, send the authentication data */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen get_plain_auth(client, str);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen str_append(str, "\r\n");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen }
c7fca6cbb32388556d9f6d8313486cc4e4a3c058Timo Sirainen (void)o_stream_send(output, str_data(str), str_len(str));
c7fca6cbb32388556d9f6d8313486cc4e4a3c058Timo Sirainen proxy_free_password(client);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen client->proxy_state = POP3_PROXY_LOGIN2;
c7fca6cbb32388556d9f6d8313486cc4e4a3c058Timo Sirainen return 0;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen case POP3_PROXY_LOGIN2:
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (strncmp(line, "+OK", 3) != 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen break;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* Login successful. Send this line to client. */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen line = t_strconcat(line, "\r\n", NULL);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen (void)o_stream_send_str(client->output, line);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_proxy_finish_destroy_client(client);
5a9e240ebf8d0daaf029973973b52e415148070bTimo Sirainen return 1;
5a9e240ebf8d0daaf029973973b52e415148070bTimo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen /* Login failed. Pass through the error message to client.
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen
a75907609d7c410c9e17beedfafbf28b4439fa8aTimo Sirainen If the backend server isn't Dovecot, the error message may
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen be different from Dovecot's "user doesn't exist" error. This
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen would allow an attacker to find out what users exist in the
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen system.
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen The optimal way to handle this would be to replace the
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen backend's "password failed" error message with Dovecot's
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen AUTH_FAILED_MSG, but this would require a new setting and
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen the sysadmin to actually bother setting it properly.
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen So for now we'll just forward the error message. This
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen shouldn't be a real problem since of course everyone will
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen be using only Dovecot as their backend :) */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (strncmp(line, "-ERR ", 5) != 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_send_line(client, CLIENT_CMD_REPLY_AUTH_FAILED,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen AUTH_FAILED_MSG);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen } else {
05e55893a799de645fc8cd2203d6013f0e0f1b79Timo Sirainen client_send_raw(client, t_strconcat(line, "\r\n", NULL));
4de2a17e0a2aed3b57a6c1057329b6a132b56ae2Timo Sirainen }
4de2a17e0a2aed3b57a6c1057329b6a132b56ae2Timo Sirainen
4de2a17e0a2aed3b57a6c1057329b6a132b56ae2Timo Sirainen if (client->set->verbose_auth) {
4de2a17e0a2aed3b57a6c1057329b6a132b56ae2Timo Sirainen if (strncmp(line, "-ERR ", 5) == 0)
4de2a17e0a2aed3b57a6c1057329b6a132b56ae2Timo Sirainen line += 5;
5d2e7ec2ea725c8a6a63f56b771e746f93e782ecTimo Sirainen client_proxy_log_failure(client, line);
4de2a17e0a2aed3b57a6c1057329b6a132b56ae2Timo Sirainen }
5d2e7ec2ea725c8a6a63f56b771e746f93e782ecTimo Sirainen client_proxy_failed(client, FALSE);
54533aa265f5c87730022cc7576090bc51370f97Timo Sirainen return -1;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenvoid pop3_proxy_reset(struct client *client)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client->proxy_state = POP3_PROXY_BANNER;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen}
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen