imap-proxy.c revision 686ad6d723004b807fd558f3ef9d1f88afa7e127
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2004-2012 Dovecot authors, see the included COPYING file */
ba90e657bc68a72ab3b3021e2f4a874fac9965baTimo Sirainen
46552a931924c2d743f045e95b08c3ce6beda91aTimo Sirainen#include "login-common.h"
3cb26db7f4756b71ba06c6e4950fa4f8ce7fad66Timo Sirainen#include "array.h"
ba90e657bc68a72ab3b3021e2f4a874fac9965baTimo Sirainen#include "ioloop.h"
f30577ff7cf29858f1878abe963b4f40a436434fTimo Sirainen#include "istream.h"
f30577ff7cf29858f1878abe963b4f40a436434fTimo Sirainen#include "ostream.h"
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen#include "base64.h"
ba90e657bc68a72ab3b3021e2f4a874fac9965baTimo Sirainen#include "str.h"
45155bb1250cf5a120278f349465aded513a100fTimo Sirainen#include "str-sanitize.h"
f30577ff7cf29858f1878abe963b4f40a436434fTimo Sirainen#include "safe-memset.h"
ba90e657bc68a72ab3b3021e2f4a874fac9965baTimo Sirainen#include "client.h"
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen#include "client-authenticate.h"
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen#include "imap-resp-code.h"
ba90e657bc68a72ab3b3021e2f4a874fac9965baTimo Sirainen#include "imap-quote.h"
ba90e657bc68a72ab3b3021e2f4a874fac9965baTimo Sirainen#include "imap-proxy.h"
ba90e657bc68a72ab3b3021e2f4a874fac9965baTimo Sirainen
3cb26db7f4756b71ba06c6e4950fa4f8ce7fad66Timo Sirainen#include <stdlib.h>
3cb26db7f4756b71ba06c6e4950fa4f8ce7fad66Timo Sirainen
3612ee5c737954d5fb88fd1775aad80f7bf1dc4eTimo Sirainenenum imap_proxy_state {
3612ee5c737954d5fb88fd1775aad80f7bf1dc4eTimo Sirainen IMAP_PROXY_STATE_NONE,
3612ee5c737954d5fb88fd1775aad80f7bf1dc4eTimo Sirainen IMAP_PROXY_STATE_BANNER,
3612ee5c737954d5fb88fd1775aad80f7bf1dc4eTimo Sirainen IMAP_PROXY_STATE_ID,
3612ee5c737954d5fb88fd1775aad80f7bf1dc4eTimo Sirainen IMAP_PROXY_STATE_STARTTLS,
3612ee5c737954d5fb88fd1775aad80f7bf1dc4eTimo Sirainen IMAP_PROXY_STATE_CAPABILITY,
3612ee5c737954d5fb88fd1775aad80f7bf1dc4eTimo Sirainen IMAP_PROXY_STATE_AUTH_CONTINUE,
3612ee5c737954d5fb88fd1775aad80f7bf1dc4eTimo Sirainen IMAP_PROXY_STATE_LOGIN
3612ee5c737954d5fb88fd1775aad80f7bf1dc4eTimo Sirainen};
3612ee5c737954d5fb88fd1775aad80f7bf1dc4eTimo Sirainen
89795c6bbbc52bb382e88bc8617d22092223e9a5Timo Sirainenstatic void proxy_write_id(struct imap_client *client, string_t *str)
89795c6bbbc52bb382e88bc8617d22092223e9a5Timo Sirainen{
ddbdc644a15f56f4b43596f1b8c0fc196c101445Timo Sirainen i_assert(client->common.proxy_ttl > 0);
ddbdc644a15f56f4b43596f1b8c0fc196c101445Timo Sirainen
89795c6bbbc52bb382e88bc8617d22092223e9a5Timo Sirainen str_printfa(str, "I ID ("
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen "\"x-session-id\" \"%s\" "
89795c6bbbc52bb382e88bc8617d22092223e9a5Timo Sirainen "\"x-originating-ip\" \"%s\" "
89795c6bbbc52bb382e88bc8617d22092223e9a5Timo Sirainen "\"x-originating-port\" \"%u\" "
493123e38ca1f27b07ac30dcbc59663c5fcdcba2Timo Sirainen "\"x-connected-ip\" \"%s\" "
ddbdc644a15f56f4b43596f1b8c0fc196c101445Timo Sirainen "\"x-connected-port\" \"%u\" "
ddbdc644a15f56f4b43596f1b8c0fc196c101445Timo Sirainen "\"x-proxy-ttl\" \"%u\")\r\n",
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen client_get_session_id(&client->common),
89795c6bbbc52bb382e88bc8617d22092223e9a5Timo Sirainen net_ip2addr(&client->common.ip),
89795c6bbbc52bb382e88bc8617d22092223e9a5Timo Sirainen client->common.remote_port,
89795c6bbbc52bb382e88bc8617d22092223e9a5Timo Sirainen net_ip2addr(&client->common.local_ip),
ddbdc644a15f56f4b43596f1b8c0fc196c101445Timo Sirainen client->common.local_port,
ddbdc644a15f56f4b43596f1b8c0fc196c101445Timo Sirainen client->common.proxy_ttl - 1);
89795c6bbbc52bb382e88bc8617d22092223e9a5Timo Sirainen}
89795c6bbbc52bb382e88bc8617d22092223e9a5Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic void proxy_free_password(struct client *client)
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen{
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen if (client->proxy_password == NULL)
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen return;
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen safe_memset(client->proxy_password, 0, strlen(client->proxy_password));
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen i_free_and_null(client->proxy_password);
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen}
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo 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_write_login(struct imap_client *client, string_t *str)
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen{
be71a9de88d1266597eb8c5e0b6f519d90e14397Timo Sirainen str_append(str, "C CAPABILITY\r\n");
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (client->common.proxy_master_user == NULL) {
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen /* logging in normally - use LOGIN command */
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen str_append(str, "L LOGIN ");
686ad6d723004b807fd558f3ef9d1f88afa7e127Timo Sirainen imap_append_string(str, client->common.proxy_user);
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen str_append_c(str, ' ');
686ad6d723004b807fd558f3ef9d1f88afa7e127Timo Sirainen imap_append_string(str, client->common.proxy_password);
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen proxy_free_password(&client->common);
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen } else if (client->proxy_sasl_ir) {
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen /* master user login with SASL initial response support */
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen str_append(str, "L AUTHENTICATE PLAIN ");
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen get_plain_auth(&client->common, str);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen proxy_free_password(&client->common);
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen } else {
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen /* master user login without SASL initial response */
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen str_append(str, "L AUTHENTICATE PLAIN");
9c47edf0d1aa8afa6d05dde93e7aa5169059c94aTimo Sirainen client->proxy_wait_auth_continue = TRUE;
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen }
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen str_append(str, "\r\n");
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen}
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainenstatic int proxy_input_banner(struct imap_client *client,
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen struct ostream *output, const char *line)
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen{
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen enum login_proxy_ssl_flags ssl_flags;
3cb26db7f4756b71ba06c6e4950fa4f8ce7fad66Timo Sirainen const char *const *capabilities = NULL;
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen string_t *str;
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen if (strncmp(line, "* OK ", 5) != 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_log_err(&client->common, t_strdup_printf(
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen "proxy: Remote returned invalid banner: %s",
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen str_sanitize(line, 160)));
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen return -1;
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen }
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen str = t_str_new(128);
53d564c421ca7292d7b1bd945f86894a34b75370Timo Sirainen if (strncmp(line + 5, "[CAPABILITY ", 12) == 0) {
3cb26db7f4756b71ba06c6e4950fa4f8ce7fad66Timo Sirainen capabilities = t_strsplit(t_strcut(line + 5 + 12, ']'), " ");
3cb26db7f4756b71ba06c6e4950fa4f8ce7fad66Timo Sirainen if (str_array_icase_find(capabilities, "ID"))
53d564c421ca7292d7b1bd945f86894a34b75370Timo Sirainen proxy_write_id(client, str);
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen if (str_array_icase_find(capabilities, "SASL-IR"))
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen client->proxy_sasl_ir = TRUE;
53d564c421ca7292d7b1bd945f86894a34b75370Timo Sirainen }
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen ssl_flags = login_proxy_get_ssl_flags(client->common.login_proxy);
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen if ((ssl_flags & PROXY_SSL_FLAG_STARTTLS) != 0) {
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen if (capabilities != NULL &&
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen !str_array_icase_find(capabilities, "STARTTLS")) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_log_err(&client->common,
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen "proxy: Remote doesn't support STARTTLS");
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen return -1;
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen }
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen str_append(str, "S STARTTLS\r\n");
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen } else {
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen proxy_write_login(client, str);
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen }
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsend(output, str_data(str), str_len(str));
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen return 0;
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen}
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen
be71a9de88d1266597eb8c5e0b6f519d90e14397Timo Sirainenstatic void
be71a9de88d1266597eb8c5e0b6f519d90e14397Timo Sirainenclient_send_login_reply(struct imap_client *client, string_t *str,
be71a9de88d1266597eb8c5e0b6f519d90e14397Timo Sirainen const char *line)
be71a9de88d1266597eb8c5e0b6f519d90e14397Timo Sirainen{
be71a9de88d1266597eb8c5e0b6f519d90e14397Timo Sirainen const char *capability;
be71a9de88d1266597eb8c5e0b6f519d90e14397Timo Sirainen bool tagged_capability;
be71a9de88d1266597eb8c5e0b6f519d90e14397Timo Sirainen
be71a9de88d1266597eb8c5e0b6f519d90e14397Timo Sirainen capability = client->proxy_backend_capability;
be71a9de88d1266597eb8c5e0b6f519d90e14397Timo Sirainen tagged_capability = strncasecmp(line, "[CAPABILITY ", 12) == 0;
be71a9de88d1266597eb8c5e0b6f519d90e14397Timo Sirainen if (tagged_capability)
be71a9de88d1266597eb8c5e0b6f519d90e14397Timo Sirainen capability = t_strcut(line + 12, ']');
be71a9de88d1266597eb8c5e0b6f519d90e14397Timo Sirainen
be71a9de88d1266597eb8c5e0b6f519d90e14397Timo Sirainen if (client->client_ignores_capability_resp_code && capability != NULL) {
be71a9de88d1266597eb8c5e0b6f519d90e14397Timo Sirainen /* client has used CAPABILITY command, so it didn't understand
be71a9de88d1266597eb8c5e0b6f519d90e14397Timo Sirainen the capabilities in the banner. send the backend's untagged
be71a9de88d1266597eb8c5e0b6f519d90e14397Timo Sirainen CAPABILITY reply and hope that the client understands it */
be71a9de88d1266597eb8c5e0b6f519d90e14397Timo Sirainen str_printfa(str, "* CAPABILITY %s\r\n", capability);
be71a9de88d1266597eb8c5e0b6f519d90e14397Timo Sirainen }
be71a9de88d1266597eb8c5e0b6f519d90e14397Timo Sirainen str_append(str, client->cmd_tag);
be71a9de88d1266597eb8c5e0b6f519d90e14397Timo Sirainen str_append(str, " OK ");
be71a9de88d1266597eb8c5e0b6f519d90e14397Timo Sirainen if (!client->client_ignores_capability_resp_code &&
be71a9de88d1266597eb8c5e0b6f519d90e14397Timo Sirainen !tagged_capability && capability != NULL) {
be71a9de88d1266597eb8c5e0b6f519d90e14397Timo Sirainen str_printfa(str, "[CAPABILITY %s] ", capability);
be71a9de88d1266597eb8c5e0b6f519d90e14397Timo Sirainen if (*line == '[') {
be71a9de88d1266597eb8c5e0b6f519d90e14397Timo Sirainen /* we need to send the capability.
be71a9de88d1266597eb8c5e0b6f519d90e14397Timo Sirainen skip over this resp-code */
be71a9de88d1266597eb8c5e0b6f519d90e14397Timo Sirainen while (*line != ']' && *line != '\0')
be71a9de88d1266597eb8c5e0b6f519d90e14397Timo Sirainen line++;
be71a9de88d1266597eb8c5e0b6f519d90e14397Timo Sirainen if (*line == ' ') line++;
be71a9de88d1266597eb8c5e0b6f519d90e14397Timo Sirainen }
be71a9de88d1266597eb8c5e0b6f519d90e14397Timo Sirainen }
be71a9de88d1266597eb8c5e0b6f519d90e14397Timo Sirainen str_append(str, line);
be71a9de88d1266597eb8c5e0b6f519d90e14397Timo Sirainen str_append(str, "\r\n");
be71a9de88d1266597eb8c5e0b6f519d90e14397Timo Sirainen}
be71a9de88d1266597eb8c5e0b6f519d90e14397Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenint imap_proxy_parse_line(struct client *client, const char *line)
ba90e657bc68a72ab3b3021e2f4a874fac9965baTimo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct imap_client *imap_client = (struct imap_client *)client;
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen struct ostream *output;
ba90e657bc68a72ab3b3021e2f4a874fac9965baTimo Sirainen string_t *str;
ba90e657bc68a72ab3b3021e2f4a874fac9965baTimo Sirainen
feb665db52583259a1f42037c6e8a22852aa8889Timo Sirainen i_assert(!client->destroyed);
9bc0204ec8bda657ce2e96e6ae715e4034f1538bTimo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen output = login_proxy_get_ostream(client->login_proxy);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (!imap_client->proxy_seen_banner) {
f30577ff7cf29858f1878abe963b4f40a436434fTimo Sirainen /* this is a banner */
3612ee5c737954d5fb88fd1775aad80f7bf1dc4eTimo Sirainen client->proxy_state = IMAP_PROXY_STATE_BANNER;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen imap_client->proxy_seen_banner = TRUE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (proxy_input_banner(imap_client, output, line) < 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_proxy_failed(client, TRUE);
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen return -1;
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen }
8372fc7efb6d64dff2e5f55fb4a3822c56869cfeTimo Sirainen return 0;
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen } else if (*line == '+') {
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen /* AUTHENTICATE started. finish it. */
9c47edf0d1aa8afa6d05dde93e7aa5169059c94aTimo Sirainen if (!imap_client->proxy_wait_auth_continue) {
27d50b3aa143964143e4bef66c0bfe3c72aea233Timo Sirainen /* used literals with LOGIN command, just ignore. */
27d50b3aa143964143e4bef66c0bfe3c72aea233Timo Sirainen return 0;
9c47edf0d1aa8afa6d05dde93e7aa5169059c94aTimo Sirainen }
3612ee5c737954d5fb88fd1775aad80f7bf1dc4eTimo Sirainen client->proxy_state = IMAP_PROXY_STATE_AUTH_CONTINUE;
9c47edf0d1aa8afa6d05dde93e7aa5169059c94aTimo Sirainen imap_client->proxy_wait_auth_continue = FALSE;
9c47edf0d1aa8afa6d05dde93e7aa5169059c94aTimo Sirainen
f30577ff7cf29858f1878abe963b4f40a436434fTimo Sirainen str = t_str_new(128);
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen get_plain_auth(client, str);
f30577ff7cf29858f1878abe963b4f40a436434fTimo Sirainen str_append(str, "\r\n");
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen proxy_free_password(client);
f30577ff7cf29858f1878abe963b4f40a436434fTimo Sirainen
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsend(output, str_data(str), str_len(str));
f30577ff7cf29858f1878abe963b4f40a436434fTimo Sirainen return 0;
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen } else if (strncmp(line, "S ", 2) == 0) {
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen if (strncmp(line, "S OK ", 5) != 0) {
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen /* STARTTLS failed */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_log_err(client, t_strdup_printf(
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen "proxy: Remote STARTTLS failed: %s",
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen str_sanitize(line + 5, 160)));
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_proxy_failed(client, TRUE);
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen return -1;
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen }
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen /* STARTTLS successful, begin TLS negotiation. */
3612ee5c737954d5fb88fd1775aad80f7bf1dc4eTimo Sirainen client->proxy_state = IMAP_PROXY_STATE_STARTTLS;
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);
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen str = t_str_new(128);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen proxy_write_login(imap_client, str);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsend(output, str_data(str), str_len(str));
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen return 1;
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen } else if (strncmp(line, "L OK ", 5) == 0) {
f30577ff7cf29858f1878abe963b4f40a436434fTimo Sirainen /* Login successful. Send this line to client. */
3612ee5c737954d5fb88fd1775aad80f7bf1dc4eTimo Sirainen client->proxy_state = IMAP_PROXY_STATE_LOGIN;
8e50329e2c5e3a199674ae9f6d3dfcddab02487bTimo Sirainen str = t_str_new(128);
be71a9de88d1266597eb8c5e0b6f519d90e14397Timo Sirainen client_send_login_reply(imap_client, str, line + 5);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsend(client->output, str_data(str), str_len(str));
f30577ff7cf29858f1878abe963b4f40a436434fTimo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen (void)client_skip_line(imap_client);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_proxy_finish_destroy_client(client);
eb188b2a2d5395b2c6125f875ec053b04a10e5fbTimo Sirainen return 1;
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen } else if (strncmp(line, "L ", 2) == 0) {
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen line += 2;
ac45ba9c603b67cc43fa7bceffdef0a19100720bTimo Sirainen if (client->set->auth_verbose) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen const char *log_line = line;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (strncasecmp(log_line, "NO ", 3) == 0)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen log_line += 3;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_proxy_log_failure(client, log_line);
6e8ad595d0603295f57bef576da8a3a00b55c5e2Timo Sirainen }
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen#define STR_NO_IMAP_RESP_CODE_AUTHFAILED "NO ["IMAP_RESP_CODE_AUTHFAILED"]"
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen if (strncmp(line, STR_NO_IMAP_RESP_CODE_AUTHFAILED,
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen strlen(STR_NO_IMAP_RESP_CODE_AUTHFAILED)) == 0) {
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen /* the remote sent a generic "authentication failed"
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen error. replace it with our one, so that in case
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen the remote is sending a different error message
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen an attacker can't find out what users exist in
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen the system. */
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen client_send_reply_code(client, IMAP_CMD_REPLY_NO,
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen IMAP_RESP_CODE_AUTHFAILED,
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen AUTH_FAILED_MSG);
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen } else if (strncmp(line, "NO [", 4) == 0) {
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen /* remote sent some other resp-code. forward it. */
00fa8dcbc66f56daa737487c9dec7166c37de79eTimo Sirainen client_send_raw(client, t_strconcat(
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen imap_client->cmd_tag, " ", line, "\r\n", NULL));
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen } else {
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen /* there was no [resp-code], so remote isn't Dovecot
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen v1.2+. we could either forward the line as-is and
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen leak information about what users exist in this
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen system, or we could hide other errors than password
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen failures. since other errors are pretty rare,
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen it's safer to just hide them. they're still
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen available in logs though. */
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen client_send_reply_code(client, IMAP_CMD_REPLY_NO,
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen IMAP_RESP_CODE_AUTHFAILED,
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen AUTH_FAILED_MSG);
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen }
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen
80980955bb1bbcc1bd73623fe0912f334194ddd2Timo Sirainen client->proxy_auth_failed = TRUE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_proxy_failed(client, FALSE);
f30577ff7cf29858f1878abe963b4f40a436434fTimo Sirainen return -1;
3cb26db7f4756b71ba06c6e4950fa4f8ce7fad66Timo Sirainen } else if (strncasecmp(line, "* CAPABILITY ", 13) == 0) {
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen i_free(imap_client->proxy_backend_capability);
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen imap_client->proxy_backend_capability = i_strdup(line + 13);
3cb26db7f4756b71ba06c6e4950fa4f8ce7fad66Timo Sirainen return 0;
31750e7fddc514c68c4eaf85b4f8c00000c281e0Timo Sirainen } else if (strncmp(line, "C ", 2) == 0) {
31750e7fddc514c68c4eaf85b4f8c00000c281e0Timo Sirainen /* Reply to CAPABILITY command we sent, ignore it */
3612ee5c737954d5fb88fd1775aad80f7bf1dc4eTimo Sirainen client->proxy_state = IMAP_PROXY_STATE_CAPABILITY;
31750e7fddc514c68c4eaf85b4f8c00000c281e0Timo Sirainen return 0;
087eb3d719a5667631cc7ce9de6c372ddea19f4dTimo Sirainen } else if (strncasecmp(line, "I ", 2) == 0 ||
087eb3d719a5667631cc7ce9de6c372ddea19f4dTimo Sirainen strncasecmp(line, "* ID ", 5) == 0) {
087eb3d719a5667631cc7ce9de6c372ddea19f4dTimo Sirainen /* Reply to ID command we sent, ignore it */
3612ee5c737954d5fb88fd1775aad80f7bf1dc4eTimo Sirainen client->proxy_state = IMAP_PROXY_STATE_ID;
087eb3d719a5667631cc7ce9de6c372ddea19f4dTimo Sirainen return 0;
087eb3d719a5667631cc7ce9de6c372ddea19f4dTimo Sirainen } else if (strncmp(line, "* ", 2) == 0) {
087eb3d719a5667631cc7ce9de6c372ddea19f4dTimo Sirainen /* untagged reply. just foward it. */
00fa8dcbc66f56daa737487c9dec7166c37de79eTimo Sirainen client_send_raw(client, t_strconcat(line, "\r\n", NULL));
087eb3d719a5667631cc7ce9de6c372ddea19f4dTimo Sirainen return 0;
f30577ff7cf29858f1878abe963b4f40a436434fTimo Sirainen } else {
087eb3d719a5667631cc7ce9de6c372ddea19f4dTimo Sirainen /* tagged reply, shouldn't happen. */
9c47edf0d1aa8afa6d05dde93e7aa5169059c94aTimo Sirainen client_log_err(client, t_strdup_printf(
9c47edf0d1aa8afa6d05dde93e7aa5169059c94aTimo Sirainen "proxy: Unexpected input, ignoring: %s",
9c47edf0d1aa8afa6d05dde93e7aa5169059c94aTimo Sirainen str_sanitize(line, 160)));
f30577ff7cf29858f1878abe963b4f40a436434fTimo Sirainen return 0;
f30577ff7cf29858f1878abe963b4f40a436434fTimo Sirainen }
f30577ff7cf29858f1878abe963b4f40a436434fTimo Sirainen}
f30577ff7cf29858f1878abe963b4f40a436434fTimo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenvoid imap_proxy_reset(struct client *client)
f30577ff7cf29858f1878abe963b4f40a436434fTimo Sirainen{
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct imap_client *imap_client = (struct imap_client *)client;
d7cd49f01fad7c87c5a0865ebf54a548275e9feeTimo Sirainen
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen imap_client->proxy_sasl_ir = FALSE;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen imap_client->proxy_seen_banner = FALSE;
9c47edf0d1aa8afa6d05dde93e7aa5169059c94aTimo Sirainen imap_client->proxy_wait_auth_continue = FALSE;
3612ee5c737954d5fb88fd1775aad80f7bf1dc4eTimo Sirainen client->proxy_state = IMAP_PROXY_STATE_NONE;
ba90e657bc68a72ab3b3021e2f4a874fac9965baTimo Sirainen}
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainenvoid imap_proxy_error(struct client *client, const char *text)
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen{
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen client_send_reply_code(client, IMAP_CMD_REPLY_NO,
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen IMAP_RESP_CODE_UNAVAILABLE, text);
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainen}