imap-proxy.c revision a64adf62fa33f2463a86f990217b0c9078531a40
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen/* Copyright (c) 2004-2009 Dovecot authors, see the included COPYING file */
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "common.h"
80c1d98d3638b71e57a39cafa88b9122bf8169c6Timo Sirainen#include "ioloop.h"
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen#include "istream.h"
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen#include "ostream.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "base64.h"
94a8cb0ee1d85569ad1a2acacd92d3ce22f8a1cbTimo Sirainen#include "str.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "str-sanitize.h"
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen#include "safe-memset.h"
795aeec896095aa8f08cc5d3282c88cc0921bff6Timo Sirainen#include "client.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "imap-resp-code.h"
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen#include "imap-quote.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "imap-proxy.h"
e307c8202280c6db60a0615381f18cac33e46a53Timo Sirainen
e307c8202280c6db60a0615381f18cac33e46a53Timo Sirainen#define PROXY_FAILURE_MSG \
e307c8202280c6db60a0615381f18cac33e46a53Timo Sirainen "NO ["IMAP_RESP_CODE_UNAVAILABLE"] "AUTH_TEMP_FAILED_MSG
e307c8202280c6db60a0615381f18cac33e46a53Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic bool imap_banner_has_capability(const char *line, const char *capability)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int capability_len = strlen(capability);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen if (strncmp(line, "[CAPABILITY ", 12) != 0)
8887bf3757d51d73887dd20b1db3334d867d3817Timo Sirainen return FALSE;
8887bf3757d51d73887dd20b1db3334d867d3817Timo Sirainen
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen line += 12;
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen while (strncmp(line, capability, capability_len) != 0 ||
c53e8ee216904ffe6de4f6518d9f9f5107b7610eTimo Sirainen (line[capability_len] != ' ' &&
589a9c6e8ee22071c14171c04bfc6bfe17121871Timo Sirainen line[capability_len] != '\0')) {
589a9c6e8ee22071c14171c04bfc6bfe17121871Timo Sirainen /* skip over the capability */
ef5fb27361cc5e15766e85e28355750ff04b13c9Timo Sirainen while (*line != ' ') {
ef5fb27361cc5e15766e85e28355750ff04b13c9Timo Sirainen if (*line == '\0')
ef5fb27361cc5e15766e85e28355750ff04b13c9Timo Sirainen return FALSE;
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen line++;
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen }
18d92dbbb752c79dc461514e52f7ef11847e636bTimo Sirainen line++;
f883b315ca72073b58020798e6d907340b327228Timo Sirainen }
f883b315ca72073b58020798e6d907340b327228Timo Sirainen return TRUE;
f883b315ca72073b58020798e6d907340b327228Timo Sirainen}
945565e0c9cf979b5feeba6fbd4efce3bf4484adTimo Sirainen
945565e0c9cf979b5feeba6fbd4efce3bf4484adTimo Sirainenstatic void proxy_write_id(struct imap_client *client, string_t *str)
945565e0c9cf979b5feeba6fbd4efce3bf4484adTimo Sirainen{
a53cb86b4d733d9c48ee4d285bed477c80825804Timo Sirainen str_printfa(str, "I ID ("
a53cb86b4d733d9c48ee4d285bed477c80825804Timo Sirainen "\"x-originating-ip\" \"%s\" "
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "\"x-originating-port\" \"%u\" "
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "\"x-connected-ip\" \"%s\" "
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "\"x-connected-port\" \"%u\")\r\n",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen net_ip2addr(&client->common.ip),
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client->common.remote_port,
b7b81543899e306c71e6152516d8698416162bcbTimo Sirainen net_ip2addr(&client->common.local_ip),
fd3d711f219fd6813492acbe051e04327f0ca0f0Timo Sirainen client->common.local_port);
02d6628c1fea2990c67c60b111c8e68867160885Timo Sirainen}
02d6628c1fea2990c67c60b111c8e68867160885Timo Sirainen
02d6628c1fea2990c67c60b111c8e68867160885Timo Sirainenstatic void proxy_free_password(struct imap_client *client)
02d6628c1fea2990c67c60b111c8e68867160885Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (client->proxy_password == NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return;
fd3d711f219fd6813492acbe051e04327f0ca0f0Timo Sirainen
db5164c9a1129af0cfb11fc18d88da361a8011fbTimo Sirainen safe_memset(client->proxy_password, 0, strlen(client->proxy_password));
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen i_free_and_null(client->proxy_password);
945565e0c9cf979b5feeba6fbd4efce3bf4484adTimo Sirainen}
945565e0c9cf979b5feeba6fbd4efce3bf4484adTimo Sirainen
945565e0c9cf979b5feeba6fbd4efce3bf4484adTimo Sirainenstatic void proxy_failed(struct imap_client *client, bool send_tagline)
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen{
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen if (send_tagline)
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen client_send_tagline(client, PROXY_FAILURE_MSG);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen login_proxy_free(&client->proxy);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen proxy_free_password(client);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_free_and_null(client->proxy_user);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_free_and_null(client->proxy_master_user);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* call this last - it may destroy the client */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client_auth_failed(client, TRUE);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void get_plain_auth(struct imap_client *client, string_t *dest)
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen{
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen string_t *str;
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen str = t_str_new(128);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen str_append(str, client->proxy_user);
811f2e26d9782d9cb99fdf82e18ffa0a77564fe2Timo Sirainen str_append_c(str, '\0');
811f2e26d9782d9cb99fdf82e18ffa0a77564fe2Timo Sirainen str_append(str, client->proxy_master_user);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen str_append_c(str, '\0');
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen str_append(str, client->proxy_password);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen base64_encode(str_data(str), str_len(str), dest);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic int proxy_input_banner(struct imap_client *client,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct ostream *output, const char *line)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen string_t *str;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (strncmp(line, "* OK ", 5) != 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client_syslog_err(&client->common, t_strdup_printf(
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen "proxy: Remote returned invalid banner: %s",
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen str_sanitize(line, 160)));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen str = t_str_new(128);
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen if (imap_banner_has_capability(line + 5, "ID"))
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen proxy_write_id(client, str);
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen if (client->proxy_master_user == NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* logging in normally - use LOGIN command */
4394b73cacaf2c31a9b601f66b6e26a1c8f114b4Timo Sirainen str_append(str, "L LOGIN ");
4394b73cacaf2c31a9b601f66b6e26a1c8f114b4Timo Sirainen imap_quote_append_string(str, client->proxy_user, FALSE);
4394b73cacaf2c31a9b601f66b6e26a1c8f114b4Timo Sirainen str_append_c(str, ' ');
4394b73cacaf2c31a9b601f66b6e26a1c8f114b4Timo Sirainen imap_quote_append_string(str, client->proxy_password, FALSE);
4394b73cacaf2c31a9b601f66b6e26a1c8f114b4Timo Sirainen
2ecee6ed2bfd5c9bc5c6cc8a675b9db4cbbcd81fTimo Sirainen proxy_free_password(client);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else if (imap_banner_has_capability(line + 5, "SASL-IR")) {
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen /* master user login with SASL initial response support */
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen str_append(str, "L AUTHENTICATE PLAIN ");
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen get_plain_auth(client, str);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen proxy_free_password(client);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else {
df1b2c3ff9cea4b57a4b9f1688bef54998fda5a4Timo Sirainen /* master user login without SASL initial response */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen str_append(str, "L AUTHENTICATE PLAIN");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen str_append(str, "\r\n");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (void)o_stream_send(output, str_data(str), str_len(str));
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen client->proxy_login_sent = TRUE;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return 0;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen}
84ed9f8f3d0e5ed47607ef417618e49e4f865557Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenstatic int proxy_input_line(struct imap_client *client,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen struct ostream *output, const char *line)
9c93b5764f84126b3362cd96da4bd9b4de078bc7Timo Sirainen{
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen string_t *str;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
db87d16551d1081ada01f787ea21aa3ed1402c31Timo Sirainen i_assert(!client->destroyed);
b9c44feadade0481b957f2978640afb3317bd1dfTimo Sirainen
b9c44feadade0481b957f2978640afb3317bd1dfTimo Sirainen if (!client->proxy_login_sent) {
db87d16551d1081ada01f787ea21aa3ed1402c31Timo Sirainen /* this is a banner */
db87d16551d1081ada01f787ea21aa3ed1402c31Timo Sirainen if (proxy_input_banner(client, output, line) < 0) {
db87d16551d1081ada01f787ea21aa3ed1402c31Timo Sirainen proxy_failed(client, TRUE);
c8adec8db635f5efb13b9879a5f3fb523abdc969Timo Sirainen return -1;
c8adec8db635f5efb13b9879a5f3fb523abdc969Timo Sirainen }
c8adec8db635f5efb13b9879a5f3fb523abdc969Timo Sirainen return 0;
c8adec8db635f5efb13b9879a5f3fb523abdc969Timo Sirainen } else if (*line == '+') {
807b48fe1f6a57b01ed2cc20247d5b5e3facc562Timo Sirainen /* AUTHENTICATE started. finish it. */
807b48fe1f6a57b01ed2cc20247d5b5e3facc562Timo Sirainen str = t_str_new(128);
e169102fb38ce788b76c2a344bee7d77079dea05Timo Sirainen get_plain_auth(client, str);
e169102fb38ce788b76c2a344bee7d77079dea05Timo Sirainen str_append(str, "\r\n");
e169102fb38ce788b76c2a344bee7d77079dea05Timo Sirainen proxy_free_password(client);
e169102fb38ce788b76c2a344bee7d77079dea05Timo Sirainen
db87d16551d1081ada01f787ea21aa3ed1402c31Timo Sirainen (void)o_stream_send(output, str_data(str), str_len(str));
db87d16551d1081ada01f787ea21aa3ed1402c31Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else if (strncmp(line, "L OK ", 5) == 0) {
26ff8f8a4867bf8e9551a27a2de8c12cd138b065Timo Sirainen /* Login successful. Send this line to client. */
26ff8f8a4867bf8e9551a27a2de8c12cd138b065Timo Sirainen str = t_str_new(128);
26ff8f8a4867bf8e9551a27a2de8c12cd138b065Timo Sirainen str_append(str, client->cmd_tag);
250105a1440167ef000323cdb2721cd2a3688e1eTimo Sirainen str_append(str, line + 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen str_append(str, "\r\n");
6bc98d3898c475ba7615ba2b016e5142c8b2c09fTimo Sirainen (void)o_stream_send(client->output,
724b7fcf28c2547eb9c837d0e99241c0501dccf3Timo Sirainen str_data(str), str_len(str));
724b7fcf28c2547eb9c837d0e99241c0501dccf3Timo Sirainen
724b7fcf28c2547eb9c837d0e99241c0501dccf3Timo Sirainen str_truncate(str, 0);
724b7fcf28c2547eb9c837d0e99241c0501dccf3Timo Sirainen str_printfa(str, "proxy(%s): started proxying to %s:%u",
724b7fcf28c2547eb9c837d0e99241c0501dccf3Timo Sirainen client->common.virtual_user,
724b7fcf28c2547eb9c837d0e99241c0501dccf3Timo Sirainen login_proxy_get_host(client->proxy),
724b7fcf28c2547eb9c837d0e99241c0501dccf3Timo Sirainen login_proxy_get_port(client->proxy));
2d39dc1a453546892109b35c0d9770369011a13dTimo Sirainen if (strcmp(client->common.virtual_user,
2d39dc1a453546892109b35c0d9770369011a13dTimo Sirainen client->proxy_user) != 0) {
2d39dc1a453546892109b35c0d9770369011a13dTimo Sirainen /* remote username is different, log it */
2d39dc1a453546892109b35c0d9770369011a13dTimo Sirainen str_append_c(str, '/');
c8adec8db635f5efb13b9879a5f3fb523abdc969Timo Sirainen str_append(str, client->proxy_user);
c8adec8db635f5efb13b9879a5f3fb523abdc969Timo Sirainen }
c8adec8db635f5efb13b9879a5f3fb523abdc969Timo Sirainen if (client->proxy_master_user != NULL) {
d6a1fa1d65c6d1996937802c2482c0f14dd821a7Timo Sirainen str_printfa(str, " (master %s)",
d6a1fa1d65c6d1996937802c2482c0f14dd821a7Timo Sirainen client->proxy_master_user);
807b48fe1f6a57b01ed2cc20247d5b5e3facc562Timo Sirainen }
807b48fe1f6a57b01ed2cc20247d5b5e3facc562Timo Sirainen
3f91e60401495a4046c73992fabaa5e77200a451Timo Sirainen (void)client_skip_line(client);
cfbacf6ea5fb39ae5304e4d95a78d9d4751bdfe1Timo Sirainen login_proxy_detach(client->proxy, client->common.input,
dc912088f84c263db1609435c2f5d7cb29bf1a33Timo Sirainen client->output);
f90cbe597c41d5cc91debd371f8648bd8e6ffbc2Timo Sirainen
f90cbe597c41d5cc91debd371f8648bd8e6ffbc2Timo Sirainen client->proxy = NULL;
f90cbe597c41d5cc91debd371f8648bd8e6ffbc2Timo Sirainen client->common.input = NULL;
f90cbe597c41d5cc91debd371f8648bd8e6ffbc2Timo Sirainen client->output = NULL;
b356019bca27927bed2995e55aa6bfea756cc776Timo Sirainen client->common.fd = -1;
b356019bca27927bed2995e55aa6bfea756cc776Timo Sirainen client_destroy_success(client, str_c(str));
b356019bca27927bed2995e55aa6bfea756cc776Timo Sirainen return -1;
b356019bca27927bed2995e55aa6bfea756cc776Timo Sirainen } else if (strncmp(line, "L ", 2) == 0) {
2d39dc1a453546892109b35c0d9770369011a13dTimo Sirainen /* If the backend server isn't Dovecot, the error message may
2d39dc1a453546892109b35c0d9770369011a13dTimo Sirainen be different from Dovecot's "user doesn't exist" error. This
7761758f43d6150be4b07f4c54457ce662f78c4cTimo Sirainen would allow an attacker to find out what users exist in the
6bc98d3898c475ba7615ba2b016e5142c8b2c09fTimo Sirainen system.
62f4a199b5c9a0862f486cbf18e195cc621bbe25Timo Sirainen
62f4a199b5c9a0862f486cbf18e195cc621bbe25Timo Sirainen The optimal way to handle this would be to replace the
62f4a199b5c9a0862f486cbf18e195cc621bbe25Timo Sirainen backend's "password failed" error message with Dovecot's
62f4a199b5c9a0862f486cbf18e195cc621bbe25Timo Sirainen AUTH_FAILED_MSG, but this would require a new setting and
62f4a199b5c9a0862f486cbf18e195cc621bbe25Timo Sirainen the sysadmin to actually bother setting it properly.
6bc98d3898c475ba7615ba2b016e5142c8b2c09fTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen So for now we'll just forward the error message. This
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen shouldn't be a real problem since of course everyone will
659fe5d24825b160cae512538088020d97a60239Timo Sirainen be using only Dovecot as their backend :) */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client_send_tagline(client, line + 2);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (login_settings->verbose_auth) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen str = t_str_new(128);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen str_printfa(str, "proxy(%s): Login failed to %s:%u",
26ff8f8a4867bf8e9551a27a2de8c12cd138b065Timo Sirainen client->common.virtual_user,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen login_proxy_get_host(client->proxy),
26ff8f8a4867bf8e9551a27a2de8c12cd138b065Timo Sirainen login_proxy_get_port(client->proxy));
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen if (strcmp(client->common.virtual_user,
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen client->proxy_user) != 0) {
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen /* remote username is different, log it */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen str_append_c(str, '/');
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen str_append(str, client->proxy_user);
1f43c8ac132c153c224c4fffe34b2c3075d87ef7Timo Sirainen }
1f43c8ac132c153c224c4fffe34b2c3075d87ef7Timo Sirainen if (client->proxy_master_user != NULL) {
e68fc7dc8c8a75842f1e39deb49d196d1cfdb3b3Timo Sirainen str_printfa(str, " (master %s)",
e68fc7dc8c8a75842f1e39deb49d196d1cfdb3b3Timo Sirainen client->proxy_master_user);
1f43c8ac132c153c224c4fffe34b2c3075d87ef7Timo Sirainen }
1f43c8ac132c153c224c4fffe34b2c3075d87ef7Timo Sirainen str_append(str, ": ");
020a39a395d2adb768e0179631b37bc78ecd9471Timo Sirainen if (strncasecmp(line + 2, "NO ", 3) == 0)
020a39a395d2adb768e0179631b37bc78ecd9471Timo Sirainen str_append(str, line + 2 + 3);
1f43c8ac132c153c224c4fffe34b2c3075d87ef7Timo Sirainen else
b9c44feadade0481b957f2978640afb3317bd1dfTimo Sirainen str_append(str, line + 2);
b9c44feadade0481b957f2978640afb3317bd1dfTimo Sirainen i_info("%s", str_c(str));
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen }
020a39a395d2adb768e0179631b37bc78ecd9471Timo Sirainen proxy_failed(client, FALSE);
020a39a395d2adb768e0179631b37bc78ecd9471Timo Sirainen return -1;
6a0855a04d75bce3c0a2f68517d02f86ae72087fTimo Sirainen } else {
6a0855a04d75bce3c0a2f68517d02f86ae72087fTimo Sirainen /* probably some untagged reply */
6a0855a04d75bce3c0a2f68517d02f86ae72087fTimo Sirainen return 0;
6a0855a04d75bce3c0a2f68517d02f86ae72087fTimo Sirainen }
6a0855a04d75bce3c0a2f68517d02f86ae72087fTimo Sirainen}
6a0855a04d75bce3c0a2f68517d02f86ae72087fTimo Sirainen
6a0855a04d75bce3c0a2f68517d02f86ae72087fTimo Sirainenstatic void proxy_input(struct istream *input, struct ostream *output,
6a0855a04d75bce3c0a2f68517d02f86ae72087fTimo Sirainen struct imap_client *client)
6a0855a04d75bce3c0a2f68517d02f86ae72087fTimo Sirainen{
6a0855a04d75bce3c0a2f68517d02f86ae72087fTimo Sirainen const char *line;
6a0855a04d75bce3c0a2f68517d02f86ae72087fTimo Sirainen
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen if (input == NULL) {
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen if (client->proxy == NULL) {
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen /* we're just freeing the proxy */
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen return;
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen }
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen if (client->destroyed) {
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen /* we came here from client_destroy() */
6a0855a04d75bce3c0a2f68517d02f86ae72087fTimo Sirainen return;
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen }
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen /* failed for some reason, probably server disconnected */
3a78329166819e06f2929ce44e360514c6a80a8eTimo Sirainen proxy_failed(client, TRUE);
3a78329166819e06f2929ce44e360514c6a80a8eTimo Sirainen return;
3a78329166819e06f2929ce44e360514c6a80a8eTimo Sirainen }
3a78329166819e06f2929ce44e360514c6a80a8eTimo Sirainen
3a78329166819e06f2929ce44e360514c6a80a8eTimo Sirainen i_assert(!client->destroyed);
3a78329166819e06f2929ce44e360514c6a80a8eTimo Sirainen
3a78329166819e06f2929ce44e360514c6a80a8eTimo Sirainen switch (i_stream_read(input)) {
7ce557e379d2df8c4c3c5639f251881f0a55f3b5Timo Sirainen case -2:
7ce557e379d2df8c4c3c5639f251881f0a55f3b5Timo Sirainen client_syslog_err(&client->common,
7ce557e379d2df8c4c3c5639f251881f0a55f3b5Timo Sirainen "proxy: Remote input buffer full");
7ce557e379d2df8c4c3c5639f251881f0a55f3b5Timo Sirainen proxy_failed(client, TRUE);
7ce557e379d2df8c4c3c5639f251881f0a55f3b5Timo Sirainen return;
7ce557e379d2df8c4c3c5639f251881f0a55f3b5Timo Sirainen case -1:
7ce557e379d2df8c4c3c5639f251881f0a55f3b5Timo Sirainen client_syslog_err(&client->common,
7ce557e379d2df8c4c3c5639f251881f0a55f3b5Timo Sirainen "proxy: Remote disconnected");
7ce557e379d2df8c4c3c5639f251881f0a55f3b5Timo Sirainen proxy_failed(client, TRUE);
7ce557e379d2df8c4c3c5639f251881f0a55f3b5Timo Sirainen return;
7ce557e379d2df8c4c3c5639f251881f0a55f3b5Timo Sirainen }
7ce557e379d2df8c4c3c5639f251881f0a55f3b5Timo Sirainen
67bbcd664bebce9a507a49c67273be4814d07c97Timo Sirainen while ((line = i_stream_next_line(input)) != NULL) {
67bbcd664bebce9a507a49c67273be4814d07c97Timo Sirainen if (proxy_input_line(client, output, line) < 0)
67bbcd664bebce9a507a49c67273be4814d07c97Timo Sirainen break;
67bbcd664bebce9a507a49c67273be4814d07c97Timo Sirainen }
67bbcd664bebce9a507a49c67273be4814d07c97Timo Sirainen}
67bbcd664bebce9a507a49c67273be4814d07c97Timo Sirainen
67bbcd664bebce9a507a49c67273be4814d07c97Timo Sirainenint imap_proxy_new(struct imap_client *client, const char *host,
67bbcd664bebce9a507a49c67273be4814d07c97Timo Sirainen unsigned int port, const char *user, const char *master_user,
67bbcd664bebce9a507a49c67273be4814d07c97Timo Sirainen const char *password)
67bbcd664bebce9a507a49c67273be4814d07c97Timo Sirainen{
67bbcd664bebce9a507a49c67273be4814d07c97Timo Sirainen i_assert(user != NULL);
67bbcd664bebce9a507a49c67273be4814d07c97Timo Sirainen i_assert(!client->destroyed);
67bbcd664bebce9a507a49c67273be4814d07c97Timo Sirainen
67bbcd664bebce9a507a49c67273be4814d07c97Timo Sirainen if (password == NULL) {
67bbcd664bebce9a507a49c67273be4814d07c97Timo Sirainen client_syslog_err(&client->common, "proxy: password not given");
67bbcd664bebce9a507a49c67273be4814d07c97Timo Sirainen client_send_tagline(client, PROXY_FAILURE_MSG);
67bbcd664bebce9a507a49c67273be4814d07c97Timo Sirainen return -1;
67bbcd664bebce9a507a49c67273be4814d07c97Timo Sirainen }
67bbcd664bebce9a507a49c67273be4814d07c97Timo Sirainen
7ce557e379d2df8c4c3c5639f251881f0a55f3b5Timo Sirainen i_assert(client->refcount > 1);
3a78329166819e06f2929ce44e360514c6a80a8eTimo Sirainen connection_queue_add(1);
7ce557e379d2df8c4c3c5639f251881f0a55f3b5Timo Sirainen
67bbcd664bebce9a507a49c67273be4814d07c97Timo Sirainen if (client->destroyed) {
7ce557e379d2df8c4c3c5639f251881f0a55f3b5Timo Sirainen /* connection_queue_add() decided that we were the oldest
7ce557e379d2df8c4c3c5639f251881f0a55f3b5Timo Sirainen connection and killed us. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (login_proxy_is_ourself(&client->common, host, port, user)) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client_syslog_err(&client->common, "Proxying loops to itself");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client_send_tagline(client, PROXY_FAILURE_MSG);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
82d158d37db5cfb4e26affe4bc2f2a235901d1b9Timo Sirainen
82d158d37db5cfb4e26affe4bc2f2a235901d1b9Timo Sirainen client->proxy = login_proxy_new(&client->common, host, port,
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen proxy_input, client);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (client->proxy == NULL) {
72af6886cb51e0ee02c9b3d6a7572eef8a0e236fTimo Sirainen client_send_tagline(client, PROXY_FAILURE_MSG);
72af6886cb51e0ee02c9b3d6a7572eef8a0e236fTimo Sirainen return -1;
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen }
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen
b780aa272b742a43579cdb523cc79cc8d4521306Timo Sirainen client->proxy_login_sent = FALSE;
724b7fcf28c2547eb9c837d0e99241c0501dccf3Timo Sirainen client->proxy_user = i_strdup(user);
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen client->proxy_master_user = i_strdup(master_user);
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen client->proxy_password = i_strdup(password);
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen /* disable input until authentication is finished */
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen if (client->io != NULL)
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen io_remove(&client->io);
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen return 0;
8ae72ad7d0c69e972cfa65d1e2ce4e3e9a8b765cTimo Sirainen}
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen