pop3-proxy.c revision 9f627b360ed38fdc54cb02ec5e67246c3f0d5b0f
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2004-2012 Dovecot authors, see the included COPYING file */
ba90e657bc68a72ab3b3021e2f4a874fac9965baTimo Sirainen
46552a931924c2d743f045e95b08c3ce6beda91aTimo Sirainen#include "login-common.h"
ba90e657bc68a72ab3b3021e2f4a874fac9965baTimo Sirainen#include "ioloop.h"
f30577ff7cf29858f1878abe963b4f40a436434fTimo Sirainen#include "istream.h"
f30577ff7cf29858f1878abe963b4f40a436434fTimo Sirainen#include "ostream.h"
ba90e657bc68a72ab3b3021e2f4a874fac9965baTimo Sirainen#include "base64.h"
f30577ff7cf29858f1878abe963b4f40a436434fTimo Sirainen#include "safe-memset.h"
ba90e657bc68a72ab3b3021e2f4a874fac9965baTimo Sirainen#include "str.h"
45155bb1250cf5a120278f349465aded513a100fTimo Sirainen#include "str-sanitize.h"
ba90e657bc68a72ab3b3021e2f4a874fac9965baTimo Sirainen#include "client.h"
ba90e657bc68a72ab3b3021e2f4a874fac9965baTimo Sirainen#include "pop3-proxy.h"
ba90e657bc68a72ab3b3021e2f4a874fac9965baTimo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic void proxy_free_password(struct client *client)
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen{
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen if (client->proxy_password == NULL)
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen return;
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen safe_memset(client->proxy_password, 0, strlen(client->proxy_password));
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen i_free_and_null(client->proxy_password);
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen}
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic void get_plain_auth(struct client *client, string_t *dest)
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen{
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen string_t *str;
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen str = t_str_new(128);
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen str_append(str, client->proxy_user);
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen str_append_c(str, '\0');
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen str_append(str, client->proxy_master_user);
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen str_append_c(str, '\0');
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen str_append(str, client->proxy_password);
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen base64_encode(str_data(str), str_len(str), dest);
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen}
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainenstatic void proxy_send_login(struct pop3_client *client, struct ostream *output)
ba90e657bc68a72ab3b3021e2f4a874fac9965baTimo Sirainen{
b8cd2f2f99351605725b7260f5da89cff76d0a3aTimo Sirainen string_t *str;
f30577ff7cf29858f1878abe963b4f40a436434fTimo Sirainen
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen str = t_str_new(128);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (client->common.proxy_master_user == NULL) {
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen /* send USER command */
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen str_append(str, "USER ");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen str_append(str, client->common.proxy_user);
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen str_append(str, "\r\n");
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen } else {
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen /* master user login - use AUTH PLAIN. */
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen str_append(str, "AUTH PLAIN\r\n");
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen }
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen (void)o_stream_send(output, str_data(str), str_len(str));
3612ee5c737954d5fb88fd1775aad80f7bf1dc4eTimo Sirainen client->common.proxy_state = POP3_PROXY_LOGIN1;
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen}
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenint pop3_proxy_parse_line(struct client *client, const char *line)
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct pop3_client *pop3_client = (struct pop3_client *)client;
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen struct ostream *output;
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen enum login_proxy_ssl_flags ssl_flags;
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen string_t *str;
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen
d7cd49f01fad7c87c5a0865ebf54a548275e9feeTimo Sirainen i_assert(!client->destroyed);
d7cd49f01fad7c87c5a0865ebf54a548275e9feeTimo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen output = login_proxy_get_ostream(client->login_proxy);
3612ee5c737954d5fb88fd1775aad80f7bf1dc4eTimo Sirainen switch (client->proxy_state) {
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen case POP3_PROXY_BANNER:
f30577ff7cf29858f1878abe963b4f40a436434fTimo Sirainen /* this is a banner */
b8cd2f2f99351605725b7260f5da89cff76d0a3aTimo Sirainen if (strncmp(line, "+OK", 3) != 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_log_err(client, t_strdup_printf(
45155bb1250cf5a120278f349465aded513a100fTimo Sirainen "proxy: Remote returned invalid banner: %s",
45155bb1250cf5a120278f349465aded513a100fTimo Sirainen str_sanitize(line, 160)));
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_proxy_failed(client, TRUE);
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen return -1;
f30577ff7cf29858f1878abe963b4f40a436434fTimo Sirainen }
f30577ff7cf29858f1878abe963b4f40a436434fTimo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ssl_flags = login_proxy_get_ssl_flags(client->login_proxy);
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen if ((ssl_flags & PROXY_SSL_FLAG_STARTTLS) == 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen proxy_send_login(pop3_client, output);
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen } else {
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen (void)o_stream_send_str(output, "STLS\r\n");
3612ee5c737954d5fb88fd1775aad80f7bf1dc4eTimo Sirainen client->proxy_state = POP3_PROXY_STARTTLS;
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen }
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen return 0;
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen case POP3_PROXY_STARTTLS:
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen if (strncmp(line, "+OK", 3) != 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_log_err(client, t_strdup_printf(
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen "proxy: Remote STLS failed: %s",
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen str_sanitize(line, 160)));
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_proxy_failed(client, TRUE);
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen return -1;
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen }
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (login_proxy_starttls(client->login_proxy) < 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_proxy_failed(client, TRUE);
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen return -1;
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen }
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen /* i/ostreams changed. */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen output = login_proxy_get_ostream(client->login_proxy);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen proxy_send_login(pop3_client, output);
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen return 1;
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen case POP3_PROXY_LOGIN1:
ab1236617440e654d5c5a043b677512714b788ddTimo Sirainen str = t_str_new(128);
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen if (client->proxy_master_user == NULL) {
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen if (strncmp(line, "+OK", 3) != 0)
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen break;
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen /* USER successful, send PASS */
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen str_append(str, "PASS ");
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen str_append(str, client->proxy_password);
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen str_append(str, "\r\n");
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen } else {
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen if (*line != '+')
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen break;
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen /* AUTH successful, send the authentication data */
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen get_plain_auth(client, str);
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen str_append(str, "\r\n");
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen }
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen (void)o_stream_send(output, str_data(str), str_len(str));
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen proxy_free_password(client);
3612ee5c737954d5fb88fd1775aad80f7bf1dc4eTimo Sirainen client->proxy_state = POP3_PROXY_LOGIN2;
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen return 0;
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen case POP3_PROXY_LOGIN2:
b8422738d3c891c7c93294b027a5cfe7d520e378Timo Sirainen if (strncmp(line, "+OK", 3) != 0)
b8422738d3c891c7c93294b027a5cfe7d520e378Timo Sirainen break;
b8422738d3c891c7c93294b027a5cfe7d520e378Timo Sirainen
ab1236617440e654d5c5a043b677512714b788ddTimo Sirainen /* Login successful. Send this line to client. */
8e50329e2c5e3a199674ae9f6d3dfcddab02487bTimo Sirainen line = t_strconcat(line, "\r\n", NULL);
ab1236617440e654d5c5a043b677512714b788ddTimo Sirainen (void)o_stream_send_str(client->output, line);
ab1236617440e654d5c5a043b677512714b788ddTimo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_proxy_finish_destroy_client(client);
f8a78c816b4dbfda42f13d8ee152e0cdb28c6a4aTimo Sirainen return 1;
ab1236617440e654d5c5a043b677512714b788ddTimo Sirainen }
ab1236617440e654d5c5a043b677512714b788ddTimo Sirainen
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen /* Login failed. Pass through the error message to client.
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen If the backend server isn't Dovecot, the error message may
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen be different from Dovecot's "user doesn't exist" error. This
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen would allow an attacker to find out what users exist in the
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen system.
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen The optimal way to handle this would be to replace the
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen backend's "password failed" error message with Dovecot's
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen AUTH_FAILED_MSG, but this would require a new setting and
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen the sysadmin to actually bother setting it properly.
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen So for now we'll just forward the error message. This
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen shouldn't be a real problem since of course everyone will
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen be using only Dovecot as their backend :) */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (strncmp(line, "-ERR ", 5) != 0) {
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen client_send_reply(client, POP3_CMD_REPLY_ERROR,
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen AUTH_FAILED_MSG);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen } else {
00fa8dcbc66f56daa737487c9dec7166c37de79eTimo Sirainen client_send_raw(client, t_strconcat(line, "\r\n", NULL));
00fa8dcbc66f56daa737487c9dec7166c37de79eTimo Sirainen }
ab1236617440e654d5c5a043b677512714b788ddTimo Sirainen
ac45ba9c603b67cc43fa7bceffdef0a19100720bTimo Sirainen if (client->set->auth_verbose) {
6e8ad595d0603295f57bef576da8a3a00b55c5e2Timo Sirainen if (strncmp(line, "-ERR ", 5) == 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen line += 5;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_proxy_log_failure(client, line);
6e8ad595d0603295f57bef576da8a3a00b55c5e2Timo Sirainen }
80980955bb1bbcc1bd73623fe0912f334194ddd2Timo Sirainen client->proxy_auth_failed = TRUE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_proxy_failed(client, FALSE);
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen return -1;
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen}
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenvoid pop3_proxy_reset(struct client *client)
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen{
3612ee5c737954d5fb88fd1775aad80f7bf1dc4eTimo Sirainen client->proxy_state = POP3_PROXY_BANNER;
ba90e657bc68a72ab3b3021e2f4a874fac9965baTimo Sirainen}
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainenvoid pop3_proxy_error(struct client *client, const char *text)
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen{
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen client_send_reply(client, POP3_CMD_REPLY_ERROR, text);
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen}