imap-proxy.c revision e3a838c80f54f024115fade93c6c87a0998f1fab
2e37d45867d081db150ab78dad303b9077aea24fTimo Sirainen/* Copyright (c) 2004-2009 Dovecot authors, see the included COPYING file */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
08d6658a4e2ec8104cd1307f6baa75fdb07a24f8Mark Washenberger#include "common.h"
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen#include "ioloop.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "istream.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "ostream.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "base64.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "str.h"
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen#include "str-sanitize.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "safe-memset.h"
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen#include "client.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "client-authenticate.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "imap-resp-code.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "imap-quote.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "imap-proxy.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#define PROXY_FAILURE_MSG \
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen "NO ["IMAP_RESP_CODE_UNAVAILABLE"] "AUTH_TEMP_FAILED_MSG
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
b624773984e35dd894db8dff976c1a2114c70782Timo Sirainenstatic bool imap_banner_has_capability(const char *line, const char *capability)
b624773984e35dd894db8dff976c1a2114c70782Timo Sirainen{
b624773984e35dd894db8dff976c1a2114c70782Timo Sirainen unsigned int capability_len = strlen(capability);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (strncmp(line, "[CAPABILITY ", 12) != 0)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return FALSE;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen line += 12;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen while (strncmp(line, capability, capability_len) != 0 ||
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen (line[capability_len] != ' ' &&
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen line[capability_len] != '\0')) {
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen /* skip over the capability */
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen while (*line != ' ') {
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen if (*line == '\0')
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen return FALSE;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen line++;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen line++;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen }
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen return TRUE;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen}
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainenstatic void proxy_write_id(struct imap_client *client, string_t *str)
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen{
788a0754cfd38dcfec1902844b085e4e84cfe7e6Timo Sirainen str_printfa(str, "I ID ("
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen "\"x-originating-ip\" \"%s\" "
788a0754cfd38dcfec1902844b085e4e84cfe7e6Timo Sirainen "\"x-originating-port\" \"%u\" "
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen "\"x-connected-ip\" \"%s\" "
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen "\"x-connected-port\" \"%u\")\r\n",
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen net_ip2addr(&client->common.ip),
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen client->common.remote_port,
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen net_ip2addr(&client->common.local_ip),
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen client->common.local_port);
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen}
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainenstatic void proxy_free_password(struct imap_client *client)
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen{
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen if (client->proxy_password == NULL)
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen return;
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen safe_memset(client->proxy_password, 0, strlen(client->proxy_password));
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen i_free_and_null(client->proxy_password);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen}
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic void proxy_failed(struct imap_client *client, bool send_tagline)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (send_tagline)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen client_send_tagline(client, PROXY_FAILURE_MSG);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen login_proxy_free(&client->proxy);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen proxy_free_password(client);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen i_free_and_null(client->proxy_user);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen i_free_and_null(client->proxy_master_user);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* call this last - it may destroy the client */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen client_auth_failed(client, TRUE);
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen}
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic void get_plain_auth(struct imap_client *client, string_t *dest)
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen string_t *str;
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen str = t_str_new(128);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen str_append(str, client->proxy_user);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen str_append_c(str, '\0');
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen str_append(str, client->proxy_master_user);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen str_append_c(str, '\0');
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen str_append(str, client->proxy_password);
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen base64_encode(str_data(str), str_len(str), dest);
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen}
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen
7569ab8537418b7fc369265f26595b0ef9e4cb35Timo Sirainenstatic int proxy_input_banner(struct imap_client *client,
7569ab8537418b7fc369265f26595b0ef9e4cb35Timo Sirainen struct ostream *output, const char *line)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen string_t *str;
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (strncmp(line, "* OK ", 5) != 0) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen client_syslog_err(&client->common, t_strdup_printf(
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen "proxy: Remote returned invalid banner: %s",
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen str_sanitize(line, 160)));
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen return -1;
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen }
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen str = t_str_new(128);
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen if (imap_banner_has_capability(line + 5, "ID"))
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen proxy_write_id(client, str);
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (client->proxy_master_user == NULL) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* logging in normally - use LOGIN command */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen str_append(str, "L LOGIN ");
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen imap_quote_append_string(str, client->proxy_user, FALSE);
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen str_append_c(str, ' ');
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen imap_quote_append_string(str, client->proxy_password, FALSE);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
47bb4a7615c85f212f061499f04f121d6d625387Timo Sirainen proxy_free_password(client);
47bb4a7615c85f212f061499f04f121d6d625387Timo Sirainen } else if (imap_banner_has_capability(line + 5, "SASL-IR")) {
47bb4a7615c85f212f061499f04f121d6d625387Timo Sirainen /* master user login with SASL initial response support */
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen str_append(str, "L AUTHENTICATE PLAIN ");
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen get_plain_auth(client, str);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen proxy_free_password(client);
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen } else {
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen /* master user login without SASL initial response */
fc8d5f0ac909cca77840538e8beef98a8d40c21cTimo Sirainen str_append(str, "L AUTHENTICATE PLAIN");
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen }
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen str_append(str, "\r\n");
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen (void)o_stream_send(output, str_data(str), str_len(str));
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen client->proxy_login_sent = TRUE;
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen return 0;
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen}
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainenstatic int proxy_input_line(struct imap_client *client,
fc8d5f0ac909cca77840538e8beef98a8d40c21cTimo Sirainen struct ostream *output, const char *line)
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen{
fc8d5f0ac909cca77840538e8beef98a8d40c21cTimo Sirainen string_t *str;
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen
fc8d5f0ac909cca77840538e8beef98a8d40c21cTimo Sirainen i_assert(!client->destroyed);
33dd58ab84a020c4f061d2f6031eb6d4c168df1bTimo Sirainen
33dd58ab84a020c4f061d2f6031eb6d4c168df1bTimo Sirainen if (!client->proxy_login_sent) {
33dd58ab84a020c4f061d2f6031eb6d4c168df1bTimo Sirainen /* this is a banner */
33dd58ab84a020c4f061d2f6031eb6d4c168df1bTimo Sirainen if (proxy_input_banner(client, output, line) < 0) {
33dd58ab84a020c4f061d2f6031eb6d4c168df1bTimo Sirainen proxy_failed(client, TRUE);
5d4855d7b4dcffb6975ed8e3c9c376dac74e5c8aTimo Sirainen return -1;
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return 0;
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen } else if (*line == '+') {
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen /* AUTHENTICATE started. finish it. */
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen str = t_str_new(128);
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen get_plain_auth(client, str);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen str_append(str, "\r\n");
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen proxy_free_password(client);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen (void)o_stream_send(output, str_data(str), str_len(str));
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return 0;
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen } else if (strncmp(line, "L OK ", 5) == 0) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* Login successful. Send this line to client. */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen str = t_str_new(128);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen str_append(str, client->cmd_tag);
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen str_append(str, line + 1);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen str_append(str, "\r\n");
8eb94c5190ba09bb6f6f068eec7bf96750f08d1dTimo Sirainen (void)o_stream_send(client->output,
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen str_data(str), str_len(str));
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen str_truncate(str, 0);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen str_printfa(str, "proxy(%s): started proxying to %s:%u",
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen client->common.virtual_user,
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen login_proxy_get_host(client->proxy),
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen login_proxy_get_port(client->proxy));
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (strcmp(client->common.virtual_user,
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen client->proxy_user) != 0) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* remote username is different, log it */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen str_append_c(str, '/');
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen str_append(str, client->proxy_user);
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen }
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen if (client->proxy_master_user != NULL) {
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen str_printfa(str, " (master %s)",
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen client->proxy_master_user);
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen }
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen (void)client_skip_line(client);
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen login_proxy_detach(client->proxy, client->common.input,
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen client->output);
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen client->proxy = NULL;
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen client->common.input = NULL;
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen client->output = NULL;
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen client->common.fd = -1;
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen client_destroy_success(client, str_c(str));
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen return 1;
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen } else if (strncmp(line, "L ", 2) == 0) {
8eb94c5190ba09bb6f6f068eec7bf96750f08d1dTimo Sirainen line += 2;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen if (login_settings->verbose_auth) {
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen str = t_str_new(128);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen str_printfa(str, "proxy(%s): Login failed to %s:%u",
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen client->common.virtual_user,
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen login_proxy_get_host(client->proxy),
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen login_proxy_get_port(client->proxy));
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen if (strcmp(client->common.virtual_user,
b321df9603081896b70ec44635af96d674a9839aTimo Sirainen client->proxy_user) != 0) {
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen /* remote username is different, log it */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen str_append_c(str, '/');
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen str_append(str, client->proxy_user);
f968e62caa52a8924bd05ebf76ff515b5c18e17bTimo Sirainen }
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen if (client->proxy_master_user != NULL) {
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen str_printfa(str, " (master %s)",
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen client->proxy_master_user);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen str_append(str, ": ");
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen if (strncasecmp(line, "NO ", 3) == 0)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen str_append(str, line + 3);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen else
47bb4a7615c85f212f061499f04f121d6d625387Timo Sirainen str_append(str, line);
47bb4a7615c85f212f061499f04f121d6d625387Timo Sirainen i_info("%s", str_c(str));
47bb4a7615c85f212f061499f04f121d6d625387Timo Sirainen }
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen#define STR_NO_IMAP_RESP_CODE_AUTHFAILED "NO ["IMAP_RESP_CODE_AUTHFAILED"]"
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen if (strncmp(line, STR_NO_IMAP_RESP_CODE_AUTHFAILED,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen strlen(STR_NO_IMAP_RESP_CODE_AUTHFAILED)) == 0) {
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen /* the remote sent a generic "authentication failed"
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen error. replace it with our one, so that in case
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen the remote is sending a different error message
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen an attacker can't find out what users exist in
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen the system. */
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen line = "NO "IMAP_AUTH_FAILED_MSG;
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen } else if (strncmp(line, "NO [", 4) == 0) {
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen /* remote sent some other resp-code. forward it. */
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen } else {
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen /* there was no [resp-code], so remote isn't Dovecot
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen v1.2+. we could either forward the line as-is and
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen leak information about what users exist in this
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen system, or we could hide other errors than password
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen failures. since other errors are pretty rare,
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen it's safer to just hide them. they're still
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen available in logs though. */
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen line = "NO "IMAP_AUTH_FAILED_MSG;
4376643cd2c7110e752c09f838f2c4eee6ed8ac6Timo Sirainen }
938835576b218f6bb9498d829cef9514f8609c6fTimo Sirainen client_send_tagline(client, line);
938835576b218f6bb9498d829cef9514f8609c6fTimo Sirainen
938835576b218f6bb9498d829cef9514f8609c6fTimo Sirainen proxy_failed(client, FALSE);
938835576b218f6bb9498d829cef9514f8609c6fTimo Sirainen return -1;
938835576b218f6bb9498d829cef9514f8609c6fTimo Sirainen } else {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* probably some untagged reply */
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen return 0;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen}
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainenstatic void proxy_input(struct istream *input, struct ostream *output,
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen struct imap_client *client)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const char *line;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen if (input == NULL) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (client->proxy == NULL) {
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen /* we're just freeing the proxy */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
a8e132559a7ebe54c8269d79ce29fa3338c76199Timo Sirainen if (client->destroyed) {
e2a700d0628e395d64cbcef4b5b4510816bf51c4Timo Sirainen /* we came here from client_destroy() */
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen return;
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen }
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen /* failed for some reason, probably server disconnected */
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen proxy_failed(client, TRUE);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen return;
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen i_assert(!client->destroyed);
a8e132559a7ebe54c8269d79ce29fa3338c76199Timo Sirainen
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen switch (i_stream_read(input)) {
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen case -2:
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen client_syslog_err(&client->common,
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen "proxy: Remote input buffer full");
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen proxy_failed(client, TRUE);
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen return;
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen case -1:
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen client_syslog_err(&client->common,
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen "proxy: Remote disconnected");
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen proxy_failed(client, TRUE);
e2a700d0628e395d64cbcef4b5b4510816bf51c4Timo Sirainen return;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen }
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen while ((line = i_stream_next_line(input)) != NULL) {
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen if (proxy_input_line(client, output, line) != 0)
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen break;
43358fffb1d9f3091fd94895e0ac4643c50e2388Timo Sirainen }
43358fffb1d9f3091fd94895e0ac4643c50e2388Timo Sirainen}
43358fffb1d9f3091fd94895e0ac4643c50e2388Timo Sirainen
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainenint imap_proxy_new(struct imap_client *client, const char *host,
43358fffb1d9f3091fd94895e0ac4643c50e2388Timo Sirainen unsigned int port, const char *user, const char *master_user,
43358fffb1d9f3091fd94895e0ac4643c50e2388Timo Sirainen const char *password)
430c0b0c370bebeeceba2e206be76bc134742f41Timo Sirainen{
25ee72451d16374ed27fdbf829f4ec756c778352Timo Sirainen i_assert(user != NULL);
a3dd97fb6d92a89c3de0597fed2d4b044c7aeb84Timo Sirainen i_assert(!client->destroyed);
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (password == NULL) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen client_syslog_err(&client->common, "proxy: password not given");
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen client_send_tagline(client, PROXY_FAILURE_MSG);
484e12acec34f16e5a8adc001e23ae48f1dda8c7Timo Sirainen return -1;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen }
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen i_assert(client->refcount > 1);
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen connection_queue_add(1);
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen if (client->destroyed) {
484e12acec34f16e5a8adc001e23ae48f1dda8c7Timo Sirainen /* connection_queue_add() decided that we were the oldest
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen connection and killed us. */
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen return -1;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen }
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen if (login_proxy_is_ourself(&client->common, host, port, user)) {
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen client_syslog_err(&client->common, "Proxying loops to itself");
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen client_send_tagline(client, PROXY_FAILURE_MSG);
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen return -1;
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen }
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen client->proxy = login_proxy_new(&client->common, host, port,
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen proxy_input, client);
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen if (client->proxy == NULL) {
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen client_send_tagline(client, PROXY_FAILURE_MSG);
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen return -1;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen }
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen client->proxy_login_sent = FALSE;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen client->proxy_user = i_strdup(user);
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen client->proxy_master_user = i_strdup(master_user);
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen client->proxy_password = i_strdup(password);
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen /* disable input until authentication is finished */
31597236d79ac38a5cea7ab65a9d0a3df64ed201Timo Sirainen if (client->io != NULL)
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen io_remove(&client->io);
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen return 0;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen}
ce6b6093957885a74fd6e85c18801dbb727d61ecTimo Sirainen