imap-proxy.c revision 9c47edf0d1aa8afa6d05dde93e7aa5169059c94a
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2004-2009 Dovecot authors, see the included COPYING file */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "common.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "array.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "ioloop.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "istream.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "ostream.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "base64.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "str.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "str-sanitize.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "safe-memset.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "client.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "client-authenticate.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "imap-resp-code.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "imap-quote.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include "imap-proxy.h"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#include <stdlib.h>
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic void proxy_write_id(struct imap_client *client, string_t *str)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi str_printfa(str, "I ID ("
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "\"x-originating-ip\" \"%s\" "
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "\"x-originating-port\" \"%u\" "
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "\"x-connected-ip\" \"%s\" "
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "\"x-connected-port\" \"%u\")\r\n",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi net_ip2addr(&client->common.ip),
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi client->common.remote_port,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi net_ip2addr(&client->common.local_ip),
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi client->common.local_port);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic void proxy_free_password(struct client *client)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (client->proxy_password == NULL)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi safe_memset(client->proxy_password, 0, strlen(client->proxy_password));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_free_and_null(client->proxy_password);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic void get_plain_auth(struct client *client, string_t *dest)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi string_t *str;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi str = t_str_new(128);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi str_append(str, client->proxy_user);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi str_append_c(str, '\0');
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi str_append(str, client->proxy_master_user);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi str_append_c(str, '\0');
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi str_append(str, client->proxy_password);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi base64_encode(str_data(str), str_len(str), dest);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic void
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomiclient_send_capability_if_needed(struct imap_client *client, string_t *str,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *capability)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (!client->client_ignores_capability_resp_code || capability == NULL)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* reset this so that we don't re-send the CAPABILITY in case server
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi sends it multiple times */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi client->client_ignores_capability_resp_code = FALSE;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* client has used CAPABILITY command, so it didn't understand the
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi capabilities in the banner. send the backend's untagged CAPABILITY
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi reply and hope that the client understands it */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi str_printfa(str, "* CAPABILITY %s\r\n", capability);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic void proxy_write_login(struct imap_client *client, string_t *str)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (client->client_ignores_capability_resp_code)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi str_append(str, "C CAPABILITY\r\n");
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (client->common.proxy_master_user == NULL) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* logging in normally - use LOGIN command */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi str_append(str, "L LOGIN ");
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi imap_quote_append_string(str, client->common.proxy_user, FALSE);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi str_append_c(str, ' ');
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi imap_quote_append_string(str, client->common.proxy_password,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi FALSE);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi proxy_free_password(&client->common);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else if (client->proxy_sasl_ir) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* master user login with SASL initial response support */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi str_append(str, "L AUTHENTICATE PLAIN ");
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi get_plain_auth(&client->common, str);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi proxy_free_password(&client->common);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* master user login without SASL initial response */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi str_append(str, "L AUTHENTICATE PLAIN");
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi client->proxy_wait_auth_continue = TRUE;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi str_append(str, "\r\n");
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomistatic int proxy_input_banner(struct imap_client *client,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct ostream *output, const char *line)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi enum login_proxy_ssl_flags ssl_flags;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *const *capabilities = NULL;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi string_t *str;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (strncmp(line, "* OK ", 5) != 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi client_log_err(&client->common, t_strdup_printf(
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "proxy: Remote returned invalid banner: %s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi str_sanitize(line, 160)));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi str = t_str_new(128);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (strncmp(line + 5, "[CAPABILITY ", 12) == 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi capabilities = t_strsplit(t_strcut(line + 5 + 12, ']'), " ");
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (str_array_icase_find(capabilities, "ID"))
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi proxy_write_id(client, str);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (str_array_icase_find(capabilities, "SASL-IR"))
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi client->proxy_sasl_ir = TRUE;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi ssl_flags = login_proxy_get_ssl_flags(client->common.login_proxy);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if ((ssl_flags & PROXY_SSL_FLAG_STARTTLS) != 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (capabilities != NULL &&
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi !str_array_icase_find(capabilities, "STARTTLS")) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi client_log_err(&client->common,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "proxy: Remote doesn't support STARTTLS");
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi str_append(str, "S STARTTLS\r\n");
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi proxy_write_login(client, str);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi (void)o_stream_send(output, str_data(str), str_len(str));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return 0;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomiint imap_proxy_parse_line(struct client *client, const char *line)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct imap_client *imap_client = (struct imap_client *)client;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct ostream *output;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *capability;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi string_t *str;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_assert(!client->destroyed);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi output = login_proxy_get_ostream(client->login_proxy);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (!imap_client->proxy_seen_banner) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* this is a banner */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi imap_client->proxy_seen_banner = TRUE;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (proxy_input_banner(imap_client, output, line) < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi client_proxy_failed(client, TRUE);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return 0;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else if (*line == '+') {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* AUTHENTICATE started. finish it. */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (!imap_client->proxy_wait_auth_continue) {
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch client_log_err(client, t_strdup_printf(
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "proxy: Unexpected input: %s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi str_sanitize(line, 160)));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi client_proxy_failed(client, TRUE);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi imap_client->proxy_wait_auth_continue = FALSE;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi str = t_str_new(128);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi get_plain_auth(client, str);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi str_append(str, "\r\n");
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi proxy_free_password(client);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi (void)o_stream_send(output, str_data(str), str_len(str));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return 0;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else if (strncmp(line, "S ", 2) == 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (strncmp(line, "S OK ", 5) != 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* STARTTLS failed */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi client_log_err(client, t_strdup_printf(
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "proxy: Remote STARTTLS failed: %s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi str_sanitize(line + 5, 160)));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi client_proxy_failed(client, TRUE);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* STARTTLS successful, begin TLS negotiation. */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (login_proxy_starttls(client->login_proxy) < 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi client_proxy_failed(client, TRUE);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* i/ostreams changed. */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi output = login_proxy_get_ostream(client->login_proxy);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi str = t_str_new(128);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi proxy_write_login(imap_client, str);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi (void)o_stream_send(output, str_data(str), str_len(str));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return 1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else if (strncmp(line, "L OK ", 5) == 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* Login successful. Send this line to client. */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi capability = imap_client->proxy_backend_capability;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (strncmp(line + 5, "[CAPABILITY ", 12) == 0)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi capability = t_strcut(line + 5 + 12, ']');
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi str = t_str_new(128);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi client_send_capability_if_needed(imap_client, str, capability);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi str_append(str, imap_client->cmd_tag);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi str_append(str, line + 1);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi str_append(str, "\r\n");
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi (void)o_stream_send(client->output,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi str_data(str), str_len(str));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi (void)client_skip_line(imap_client);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi client_proxy_finish_destroy_client(client);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return 1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else if (strncmp(line, "L ", 2) == 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi line += 2;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (client->set->verbose_auth) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi const char *log_line = line;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (strncasecmp(log_line, "NO ", 3) == 0)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi log_line += 3;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi client_proxy_log_failure(client, log_line);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi#define STR_NO_IMAP_RESP_CODE_AUTHFAILED "NO ["IMAP_RESP_CODE_AUTHFAILED"]"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi if (strncmp(line, STR_NO_IMAP_RESP_CODE_AUTHFAILED,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi strlen(STR_NO_IMAP_RESP_CODE_AUTHFAILED)) == 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* the remote sent a generic "authentication failed"
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi error. replace it with our one, so that in case
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi the remote is sending a different error message
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi an attacker can't find out what users exist in
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi the system. */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi client_send_line(client, CLIENT_CMD_REPLY_AUTH_FAILED,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi AUTH_FAILED_MSG);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else if (strncmp(line, "NO [", 4) == 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* remote sent some other resp-code. forward it. */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi client_send_raw(client, t_strconcat(
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi imap_client->cmd_tag, " ", line, "\r\n", NULL));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* there was no [resp-code], so remote isn't Dovecot
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi v1.2+. we could either forward the line as-is and
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi leak information about what users exist in this
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi system, or we could hide other errors than password
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi failures. since other errors are pretty rare,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi it's safer to just hide them. they're still
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi available in logs though. */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi client_send_line(client, CLIENT_CMD_REPLY_AUTH_FAILED,
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi AUTH_FAILED_MSG);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi client_proxy_failed(client, FALSE);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return -1;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else if (strncasecmp(line, "* CAPABILITY ", 13) == 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi i_free(imap_client->proxy_backend_capability);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi imap_client->proxy_backend_capability = i_strdup(line + 13);
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return 0;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else if (strncasecmp(line, "I ", 2) == 0 ||
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi strncasecmp(line, "* ID ", 5) == 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* Reply to ID command we sent, ignore it */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return 0;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else if (strncmp(line, "* ", 2) == 0) {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* untagged reply. just foward it. */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi client_send_raw(client, t_strconcat(line, "\r\n", NULL));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return 0;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi } else {
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi /* tagged reply, shouldn't happen. */
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi client_log_err(client, t_strdup_printf(
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi "proxy: Unexpected input, ignoring: %s",
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi str_sanitize(line, 160)));
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi return 0;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi }
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomivoid imap_proxy_reset(struct client *client)
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi{
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi struct imap_client *imap_client = (struct imap_client *)client;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi imap_client->proxy_sasl_ir = FALSE;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi imap_client->proxy_seen_banner = FALSE;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi imap_client->proxy_wait_auth_continue = FALSE;
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi}
4c78d9e646c4a1158d7167806937c02d86cdfc25Aki Tuomi