imap-proxy.c revision ac45ba9c603b67cc43fa7bceffdef0a19100720b
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2004-2011 Dovecot authors, see the included COPYING file */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "login-common.h"
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen#include "array.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "ioloop.h"
d6601a0bc4fd60e58bedbddf2481abd82cba76d7Timo Sirainen#include "istream.h"
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen#include "ostream.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "base64.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "str.h"
abf015c9682f0f723db87a7c97bc284ef814818fTimo Sirainen#include "str-sanitize.h"
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen#include "safe-memset.h"
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen#include "client.h"
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen#include "client-authenticate.h"
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen#include "imap-resp-code.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "imap-quote.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "imap-proxy.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include <stdlib.h>
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenenum imap_proxy_state {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen IMAP_PROXY_STATE_NONE,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen IMAP_PROXY_STATE_BANNER,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen IMAP_PROXY_STATE_ID,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen IMAP_PROXY_STATE_STARTTLS,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen IMAP_PROXY_STATE_CAPABILITY,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen IMAP_PROXY_STATE_AUTH_CONTINUE,
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen IMAP_PROXY_STATE_LOGIN
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen};
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainenstatic void proxy_write_id(struct imap_client *client, string_t *str)
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen{
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen str_printfa(str, "I ID ("
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen "\"x-originating-ip\" \"%s\" "
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen "\"x-originating-port\" \"%u\" "
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen "\"x-connected-ip\" \"%s\" "
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen "\"x-connected-port\" \"%u\")\r\n",
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen net_ip2addr(&client->common.ip),
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen client->common.remote_port,
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen net_ip2addr(&client->common.local_ip),
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen client->common.local_port);
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen}
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainenstatic void proxy_free_password(struct client *client)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen{
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (client->proxy_password == NULL)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen return;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen safe_memset(client->proxy_password, 0, strlen(client->proxy_password));
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen i_free_and_null(client->proxy_password);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen}
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic void get_plain_auth(struct client *client, string_t *dest)
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen{
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen string_t *str;
49621bf0ef1d55aaaa2dc7d76011cbfeabdcfbe1Timo Sirainen
fa2433aebcf3fccfa30ca9eed9b1a9166cf92ee2Timo Sirainen str = t_str_new(128);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen str_append(str, client->proxy_user);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen str_append_c(str, '\0');
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen str_append(str, client->proxy_master_user);
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen str_append_c(str, '\0');
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen str_append(str, client->proxy_password);
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen base64_encode(str_data(str), str_len(str), dest);
3482fee0e3733456512ba110780824e6daa7ff9fTimo Sirainen}
3482fee0e3733456512ba110780824e6daa7ff9fTimo Sirainen
3482fee0e3733456512ba110780824e6daa7ff9fTimo Sirainenstatic void proxy_write_login(struct imap_client *client, string_t *str)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen{
12797080b552a3c1727b73b61cc7427bec0c7472Timo Sirainen str_append(str, "C CAPABILITY\r\n");
49fd8c950e3da2ed32506e617a4b1480a07f874fTimo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (client->common.proxy_master_user == NULL) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* logging in normally - use LOGIN command */
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen str_append(str, "L LOGIN ");
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen imap_quote_append_string(str, client->common.proxy_user, FALSE);
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen str_append_c(str, ' ');
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen imap_quote_append_string(str, client->common.proxy_password,
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen FALSE);
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen proxy_free_password(&client->common);
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen } else if (client->proxy_sasl_ir) {
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen /* master user login with SASL initial response support */
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen str_append(str, "L AUTHENTICATE PLAIN ");
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen get_plain_auth(&client->common, str);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen proxy_free_password(&client->common);
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen } else {
e438c85a6b0f77889e25913bbbba808d6078282dStephan Bosch /* master user login without SASL initial response */
e438c85a6b0f77889e25913bbbba808d6078282dStephan Bosch str_append(str, "L AUTHENTICATE PLAIN");
5a9912dcadfd467c5ea54bdc3331eef359f0b1c5Timo Sirainen client->proxy_wait_auth_continue = TRUE;
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen }
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen str_append(str, "\r\n");
38f227941bcf673e0e523c1ac7267bca9cbcd2c4Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
265cb53cf8d5cb35edd4c4ff086ca6165605b708Timo Sirainenstatic int proxy_input_banner(struct imap_client *client,
265cb53cf8d5cb35edd4c4ff086ca6165605b708Timo Sirainen struct ostream *output, const char *line)
265cb53cf8d5cb35edd4c4ff086ca6165605b708Timo Sirainen{
265cb53cf8d5cb35edd4c4ff086ca6165605b708Timo Sirainen enum login_proxy_ssl_flags ssl_flags;
265cb53cf8d5cb35edd4c4ff086ca6165605b708Timo Sirainen const char *const *capabilities = NULL;
265cb53cf8d5cb35edd4c4ff086ca6165605b708Timo Sirainen string_t *str;
265cb53cf8d5cb35edd4c4ff086ca6165605b708Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen if (strncmp(line, "* OK ", 5) != 0) {
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen client_log_err(&client->common, t_strdup_printf(
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen "proxy: Remote returned invalid banner: %s",
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen str_sanitize(line, 160)));
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen return -1;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen }
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen str = t_str_new(128);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen if (strncmp(line + 5, "[CAPABILITY ", 12) == 0) {
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen capabilities = t_strsplit(t_strcut(line + 5 + 12, ']'), " ");
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen if (str_array_icase_find(capabilities, "ID"))
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen proxy_write_id(client, str);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen if (str_array_icase_find(capabilities, "SASL-IR"))
2eb2cf8eeb763bd5ca9b6848dce32f0303e88ec1Timo Sirainen client->proxy_sasl_ir = TRUE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ssl_flags = login_proxy_get_ssl_flags(client->common.login_proxy);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if ((ssl_flags & PROXY_SSL_FLAG_STARTTLS) != 0) {
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen if (capabilities != NULL &&
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen !str_array_icase_find(capabilities, "STARTTLS")) {
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen client_log_err(&client->common,
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen "proxy: Remote doesn't support STARTTLS");
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen return -1;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen }
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen str_append(str, "S STARTTLS\r\n");
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen } else {
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen proxy_write_login(client, str);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen (void)o_stream_send(output, str_data(str), str_len(str));
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return 0;
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic void
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenclient_send_login_reply(struct imap_client *client, string_t *str,
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen const char *line)
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen{
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen const char *capability;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen bool tagged_capability;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen capability = client->proxy_backend_capability;
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen tagged_capability = strncasecmp(line, "[CAPABILITY ", 12) == 0;
7af5f78e9fee296e42430d94ef252ff0333d8024Timo Sirainen if (tagged_capability)
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen capability = t_strcut(line + 12, ']');
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen if (client->client_ignores_capability_resp_code && capability != NULL) {
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen /* client has used CAPABILITY command, so it didn't understand
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen the capabilities in the banner. send the backend's untagged
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen CAPABILITY reply and hope that the client understands it */
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen str_printfa(str, "* CAPABILITY %s\r\n", capability);
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen }
7af5f78e9fee296e42430d94ef252ff0333d8024Timo Sirainen str_append(str, client->cmd_tag);
7af5f78e9fee296e42430d94ef252ff0333d8024Timo Sirainen str_append(str, " OK ");
7af5f78e9fee296e42430d94ef252ff0333d8024Timo Sirainen if (!client->client_ignores_capability_resp_code &&
7af5f78e9fee296e42430d94ef252ff0333d8024Timo Sirainen !tagged_capability && capability != NULL) {
7af5f78e9fee296e42430d94ef252ff0333d8024Timo Sirainen str_printfa(str, "[CAPABILITY %s] ", capability);
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen if (*line == '[') {
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen /* we need to send the capability.
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen skip over this resp-code */
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen while (*line != ']' && *line != '\0')
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen line++;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen if (*line == ' ') line++;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen }
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen }
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen str_append(str, line);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen str_append(str, "\r\n");
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen}
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainenint imap_proxy_parse_line(struct client *client, const char *line)
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen{
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen struct imap_client *imap_client = (struct imap_client *)client;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen struct ostream *output;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen string_t *str;
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen i_assert(!client->destroyed);
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen output = login_proxy_get_ostream(client->login_proxy);
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen if (!imap_client->proxy_seen_banner) {
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen /* this is a banner */
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen client->proxy_state = IMAP_PROXY_STATE_BANNER;
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen imap_client->proxy_seen_banner = TRUE;
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen if (proxy_input_banner(imap_client, output, line) < 0) {
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen client_proxy_failed(client, TRUE);
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen return -1;
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen }
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen return 0;
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen } else if (*line == '+') {
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen /* AUTHENTICATE started. finish it. */
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen if (!imap_client->proxy_wait_auth_continue) {
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen /* used literals with LOGIN command, just ignore. */
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen return 0;
417642ddac19708bea6dd2c2bbeaf6a9578d521bTimo Sirainen }
417642ddac19708bea6dd2c2bbeaf6a9578d521bTimo Sirainen client->proxy_state = IMAP_PROXY_STATE_AUTH_CONTINUE;
417642ddac19708bea6dd2c2bbeaf6a9578d521bTimo Sirainen imap_client->proxy_wait_auth_continue = FALSE;
417642ddac19708bea6dd2c2bbeaf6a9578d521bTimo Sirainen
417642ddac19708bea6dd2c2bbeaf6a9578d521bTimo Sirainen str = t_str_new(128);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen get_plain_auth(client, str);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen str_append(str, "\r\n");
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen proxy_free_password(client);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen (void)o_stream_send(output, str_data(str), str_len(str));
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen return 0;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen } else if (strncmp(line, "S ", 2) == 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (strncmp(line, "S OK ", 5) != 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* STARTTLS failed */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen client_log_err(client, t_strdup_printf(
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "proxy: Remote STARTTLS failed: %s",
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen str_sanitize(line + 5, 160)));
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen client_proxy_failed(client, TRUE);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* STARTTLS successful, begin TLS negotiation. */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen client->proxy_state = IMAP_PROXY_STATE_STARTTLS;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (login_proxy_starttls(client->login_proxy) < 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen client_proxy_failed(client, TRUE);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* i/ostreams changed. */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen output = login_proxy_get_ostream(client->login_proxy);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen str = t_str_new(128);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen proxy_write_login(imap_client, str);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen (void)o_stream_send(output, str_data(str), str_len(str));
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return 1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen } else if (strncmp(line, "L OK ", 5) == 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* Login successful. Send this line to client. */
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen client->proxy_state = IMAP_PROXY_STATE_LOGIN;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen str = t_str_new(128);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen client_send_login_reply(imap_client, str, line + 5);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen (void)o_stream_send(client->output,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen str_data(str), str_len(str));
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen (void)client_skip_line(imap_client);
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen client_proxy_finish_destroy_client(client);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return 1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen } else if (strncmp(line, "L ", 2) == 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen line += 2;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (client->set->auth_verbose) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *log_line = line;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (strncasecmp(log_line, "NO ", 3) == 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen log_line += 3;
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen client_proxy_log_failure(client, log_line);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#define STR_NO_IMAP_RESP_CODE_AUTHFAILED "NO ["IMAP_RESP_CODE_AUTHFAILED"]"
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen if (strncmp(line, STR_NO_IMAP_RESP_CODE_AUTHFAILED,
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen strlen(STR_NO_IMAP_RESP_CODE_AUTHFAILED)) == 0) {
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen /* the remote sent a generic "authentication failed"
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen error. replace it with our one, so that in case
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen the remote is sending a different error message
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen an attacker can't find out what users exist in
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen the system. */
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen client_send_line(client, CLIENT_CMD_REPLY_AUTH_FAILED,
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen AUTH_FAILED_MSG);
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen } else if (strncmp(line, "NO [", 4) == 0) {
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen /* remote sent some other resp-code. forward it. */
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen client_send_raw(client, t_strconcat(
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen imap_client->cmd_tag, " ", line, "\r\n", NULL));
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen } else {
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen /* there was no [resp-code], so remote isn't Dovecot
e30b9e07f9657c35ca09ac36d57d60cbe2ebbc66Timo Sirainen v1.2+. we could either forward the line as-is and
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen leak information about what users exist in this
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen system, or we could hide other errors than password
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen failures. since other errors are pretty rare,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen it's safer to just hide them. they're still
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen available in logs though. */
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen client_send_line(client, CLIENT_CMD_REPLY_AUTH_FAILED,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen AUTH_FAILED_MSG);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen client_proxy_failed(client, FALSE);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -1;
e438c85a6b0f77889e25913bbbba808d6078282dStephan Bosch } else if (strncasecmp(line, "* CAPABILITY ", 13) == 0) {
e438c85a6b0f77889e25913bbbba808d6078282dStephan Bosch i_free(imap_client->proxy_backend_capability);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen imap_client->proxy_backend_capability = i_strdup(line + 13);
4c261fb48e6e36570a0841aa51ca483024d6a0a6Timo Sirainen return 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen } else if (strncmp(line, "C ", 2) == 0) {
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen /* Reply to CAPABILITY command we sent, ignore it */
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen client->proxy_state = IMAP_PROXY_STATE_CAPABILITY;
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen return 0;
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen } else if (strncasecmp(line, "I ", 2) == 0 ||
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen strncasecmp(line, "* ID ", 5) == 0) {
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch /* Reply to ID command we sent, ignore it */
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch client->proxy_state = IMAP_PROXY_STATE_ID;
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch return 0;
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch } else if (strncmp(line, "* ", 2) == 0) {
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch /* untagged reply. just foward it. */
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen client_send_raw(client, t_strconcat(line, "\r\n", NULL));
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen return 0;
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen } else {
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen /* tagged reply, shouldn't happen. */
ab90f702ceedb7ba445a9a592be0b213b27cbafaStephan Bosch client_log_err(client, t_strdup_printf(
ab90f702ceedb7ba445a9a592be0b213b27cbafaStephan Bosch "proxy: Unexpected input, ignoring: %s",
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen str_sanitize(line, 160)));
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen return 0;
5a9912dcadfd467c5ea54bdc3331eef359f0b1c5Timo Sirainen }
5a9912dcadfd467c5ea54bdc3331eef359f0b1c5Timo Sirainen}
5a9912dcadfd467c5ea54bdc3331eef359f0b1c5Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenvoid imap_proxy_reset(struct client *client)
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen{
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen struct imap_client *imap_client = (struct imap_client *)client;
4c261fb48e6e36570a0841aa51ca483024d6a0a6Timo Sirainen
4c261fb48e6e36570a0841aa51ca483024d6a0a6Timo Sirainen imap_client->proxy_sasl_ir = FALSE;
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen imap_client->proxy_seen_banner = FALSE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen imap_client->proxy_wait_auth_continue = FALSE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen client->proxy_state = IMAP_PROXY_STATE_NONE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen