imap-proxy.c revision 0af9ef2e9bb71a426bba236e74ceec30be699fb7
89a126810703c666309310d0f3189e9834d70b5bTimo Sirainen/* Copyright (c) 2004-2016 Dovecot authors, see the included COPYING file */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainenstatic void proxy_write_id(struct imap_client *client, string_t *str)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen "\"x-session-id\" \"%s\" "
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen "\"x-originating-ip\" \"%s\" "
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen "\"x-originating-port\" \"%u\" "
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen "\"x-connected-ip\" \"%s\" "
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen "\"x-connected-port\" \"%u\" "
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen "\"x-proxy-ttl\" \"%u\")\r\n",
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainenstatic void proxy_free_password(struct client *client)
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen safe_memset(client->proxy_password, 0, strlen(client->proxy_password));
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainenstatic int proxy_write_login(struct imap_client *client, string_t *str)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen const unsigned char *output;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen unsigned int len;
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen /* Send CAPABILITY command if we don't know the capabilities yet.
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen Also as kind of a Dovecot-backend workaround if the client insisted
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen on sending CAPABILITY command (even though our banner already sent
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen it), send the (unnecessary) CAPABILITY command to backend as well
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen to avoid sending the CAPABILITY reply twice (untagged and OK resp
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen client->client_ignores_capability_resp_code)) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* authenticate only after receiving C OK reply. */
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen /* logging in normally - use LOGIN command */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen imap_append_string(str, client->common.proxy_user);
73b50eecfc31750a312e2f940023f522eb07178cTimo Sirainen imap_append_string(str, client->common.proxy_password);
4d2211dac61c615c5bdfd501ea54d46c89d41b0fTimo Sirainen i_assert(client->common.proxy_sasl_client == NULL);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen sasl_set.authid = client->common.proxy_master_user != NULL ?
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen client->common.proxy_master_user : client->common.proxy_user;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen sasl_set.password = client->common.proxy_password;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen dsasl_client_new(client->common.proxy_mech, &sasl_set);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen mech_name = dsasl_client_mech_get_name(client->common.proxy_mech);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (dsasl_client_output(client->common.proxy_sasl_client,
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen client_log_err(&client->common, t_strdup_printf(
4d2211dac61c615c5bdfd501ea54d46c89d41b0fTimo Sirainen "proxy: SASL mechanism %s init failed: %s",
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainenstatic int proxy_input_banner(struct imap_client *client,
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen client_log_err(&client->common, t_strdup_printf(
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen "proxy: Remote returned invalid banner: %s",
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if (strncmp(line + 5, "[CAPABILITY ", 12) == 0) {
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen capabilities = t_strsplit(t_strcut(line + 5 + 12, ']'), " ");
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (str_array_icase_find(capabilities, "SASL-IR"))
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen ssl_flags = login_proxy_get_ssl_flags(client->common.login_proxy);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if ((ssl_flags & PROXY_SSL_FLAG_STARTTLS) != 0) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen !str_array_icase_find(capabilities, "STARTTLS")) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen "proxy: Remote doesn't support STARTTLS");
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen o_stream_nsend(output, str_data(str), str_len(str));
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainenclient_send_login_reply(struct imap_client *client, string_t *str,
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen capability = client->proxy_backend_capability;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen tagged_capability = strncasecmp(line, "[CAPABILITY ", 12) == 0;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen if (client->client_ignores_capability_resp_code && capability != NULL) {
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen /* client has used CAPABILITY command, so it didn't understand
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen the capabilities in the banner. send the backend's untagged
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen CAPABILITY reply and hope that the client understands it */
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen str_printfa(str, "* CAPABILITY %s\r\n", capability);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen if (!client->client_ignores_capability_resp_code &&
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen str_printfa(str, "[CAPABILITY %s] ", capability);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* we need to send the capability.
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen skip over this resp-code */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainenint imap_proxy_parse_line(struct client *client, const char *line)
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen struct imap_client *imap_client = (struct imap_client *)client;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen const unsigned char *data;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen output = login_proxy_get_ostream(client->login_proxy);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* this is a banner */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen client->proxy_state = IMAP_PROXY_STATE_BANNER;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen if (proxy_input_banner(imap_client, output, line) < 0) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* AUTHENTICATE started. finish it. */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* used literals with LOGIN command, just ignore. */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen client->proxy_state = IMAP_PROXY_STATE_AUTH_CONTINUE;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen base64_decode(line+2, strlen(line+2), NULL, str) < 0) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen "proxy: Server sent invalid base64 data in AUTHENTICATE response");
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen ret = dsasl_client_input(client->proxy_sasl_client,
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen ret = dsasl_client_output(client->proxy_sasl_client,
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen "proxy: Server sent invalid authentication data: %s",
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen o_stream_nsend(output, str_data(str), str_len(str));
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen /* STARTTLS failed */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen "proxy: Remote STARTTLS failed: %s",
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen /* STARTTLS successful, begin TLS negotiation. */
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen client->proxy_state = IMAP_PROXY_STATE_STARTTLS;
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (login_proxy_starttls(client->login_proxy) < 0) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* i/ostreams changed. */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen output = login_proxy_get_ostream(client->login_proxy);
00d58fcfe8191d6ce7efa801d289a5c0fe88d1aeTimo Sirainen if (proxy_write_login(imap_client, str) < 0) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen o_stream_nsend(output, str_data(str), str_len(str));
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* Login successful. Send this line to client. */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen client_send_login_reply(imap_client, str, line + 5);
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen o_stream_nsend(client->output, str_data(str), str_len(str));
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen#define STR_NO_IMAP_RESP_CODE_AUTHFAILED "NO ["IMAP_RESP_CODE_AUTHFAILED"]"
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen if (strncmp(line, STR_NO_IMAP_RESP_CODE_AUTHFAILED,
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen strlen(STR_NO_IMAP_RESP_CODE_AUTHFAILED)) == 0) {
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* the remote sent a generic "authentication failed"
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen error. replace it with our one, so that in case
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen the remote is sending a different error message
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen an attacker can't find out what users exist in
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen the system. */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen client_send_reply_code(client, IMAP_CMD_REPLY_NO,
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* remote sent some other resp-code. forward it. */
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen imap_client->cmd_tag, " ", line, "\r\n", NULL));
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen /* there was no [resp-code], so remote isn't Dovecot
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen v1.2+. we could either forward the line as-is and
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen leak information about what users exist in this
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen system, or we could hide other errors than password
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen failures. since other errors are pretty rare,
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen it's safer to just hide them. they're still
cf7164ece50797a67fc4bfb5889022ac93a36a8aTimo Sirainen available in logs though. */