imap-proxy.c revision ac45ba9c603b67cc43fa7bceffdef0a19100720b
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2004-2011 Dovecot authors, see the included COPYING file */
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainenstatic void proxy_write_id(struct imap_client *client, string_t *str)
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",
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainenstatic void proxy_free_password(struct client *client)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen safe_memset(client->proxy_password, 0, strlen(client->proxy_password));
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic void get_plain_auth(struct client *client, string_t *dest)
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen base64_encode(str_data(str), str_len(str), dest);
3482fee0e3733456512ba110780824e6daa7ff9fTimo Sirainenstatic void proxy_write_login(struct imap_client *client, string_t *str)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (client->common.proxy_master_user == NULL) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* logging in normally - use LOGIN command */
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen imap_quote_append_string(str, client->common.proxy_user, FALSE);
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen imap_quote_append_string(str, client->common.proxy_password,
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen /* master user login with SASL initial response support */
e438c85a6b0f77889e25913bbbba808d6078282dStephan Bosch /* master user login without SASL initial response */
265cb53cf8d5cb35edd4c4ff086ca6165605b708Timo Sirainenstatic int proxy_input_banner(struct imap_client *client,
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen client_log_err(&client->common, t_strdup_printf(
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen "proxy: Remote returned invalid banner: %s",
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, "SASL-IR"))
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 !str_array_icase_find(capabilities, "STARTTLS")) {
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen "proxy: Remote doesn't support STARTTLS");
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen (void)o_stream_send(output, str_data(str), str_len(str));
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenclient_send_login_reply(struct imap_client *client, string_t *str,
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen capability = client->proxy_backend_capability;
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen tagged_capability = strncasecmp(line, "[CAPABILITY ", 12) == 0;
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);
7af5f78e9fee296e42430d94ef252ff0333d8024Timo Sirainen if (!client->client_ignores_capability_resp_code &&
7af5f78e9fee296e42430d94ef252ff0333d8024Timo Sirainen str_printfa(str, "[CAPABILITY %s] ", capability);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen /* we need to send the capability.
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen skip over this resp-code */
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainenint imap_proxy_parse_line(struct client *client, const char *line)
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen struct imap_client *imap_client = (struct imap_client *)client;
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen output = login_proxy_get_ostream(client->login_proxy);
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen /* this is a banner */
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen client->proxy_state = IMAP_PROXY_STATE_BANNER;
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen if (proxy_input_banner(imap_client, output, line) < 0) {
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen /* AUTHENTICATE started. finish it. */
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen /* used literals with LOGIN command, just ignore. */
417642ddac19708bea6dd2c2bbeaf6a9578d521bTimo Sirainen client->proxy_state = IMAP_PROXY_STATE_AUTH_CONTINUE;
417642ddac19708bea6dd2c2bbeaf6a9578d521bTimo Sirainen imap_client->proxy_wait_auth_continue = FALSE;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen (void)o_stream_send(output, str_data(str), str_len(str));
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* STARTTLS failed */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "proxy: Remote STARTTLS failed: %s",
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 /* i/ostreams changed. */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen output = login_proxy_get_ostream(client->login_proxy);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen (void)o_stream_send(output, str_data(str), str_len(str));
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* Login successful. Send this line to client. */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen client_send_login_reply(imap_client, str, line + 5);
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 /* remote sent some other resp-code. forward it. */
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen imap_client->cmd_tag, " ", line, "\r\n", NULL));
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,
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);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen /* Reply to CAPABILITY command we sent, ignore it */
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen client->proxy_state = IMAP_PROXY_STATE_CAPABILITY;
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch /* Reply to ID command we sent, ignore it */
c93aca832ee532010ead91b85fa9f614132e1be2Stephan Bosch /* untagged reply. just foward it. */
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen client_send_raw(client, t_strconcat(line, "\r\n", NULL));
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen /* tagged reply, shouldn't happen. */
ab90f702ceedb7ba445a9a592be0b213b27cbafaStephan Bosch "proxy: Unexpected input, ignoring: %s",
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen struct imap_client *imap_client = (struct imap_client *)client;