imap-proxy.c revision 686ad6d723004b807fd558f3ef9d1f88afa7e127
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2004-2012 Dovecot authors, see the included COPYING file */
89795c6bbbc52bb382e88bc8617d22092223e9a5Timo Sirainenstatic void proxy_write_id(struct imap_client *client, string_t *str)
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",
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic void proxy_free_password(struct client *client)
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen safe_memset(client->proxy_password, 0, strlen(client->proxy_password));
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenstatic void get_plain_auth(struct client *client, string_t *dest)
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen base64_encode(str_data(str), str_len(str), dest);
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainenstatic void proxy_write_login(struct imap_client *client, string_t *str)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (client->common.proxy_master_user == NULL) {
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen /* logging in normally - use LOGIN command */
686ad6d723004b807fd558f3ef9d1f88afa7e127Timo Sirainen imap_append_string(str, client->common.proxy_user);
686ad6d723004b807fd558f3ef9d1f88afa7e127Timo Sirainen imap_append_string(str, client->common.proxy_password);
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen /* master user login with SASL initial response support */
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen /* master user login without SASL initial response */
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainenstatic int proxy_input_banner(struct imap_client *client,
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen client_log_err(&client->common, t_strdup_printf(
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen "proxy: Remote returned invalid banner: %s",
53d564c421ca7292d7b1bd945f86894a34b75370Timo Sirainen if (strncmp(line + 5, "[CAPABILITY ", 12) == 0) {
3cb26db7f4756b71ba06c6e4950fa4f8ce7fad66Timo Sirainen capabilities = t_strsplit(t_strcut(line + 5 + 12, ']'), " ");
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen if (str_array_icase_find(capabilities, "SASL-IR"))
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 !str_array_icase_find(capabilities, "STARTTLS")) {
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen "proxy: Remote doesn't support STARTTLS");
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsend(output, str_data(str), str_len(str));
be71a9de88d1266597eb8c5e0b6f519d90e14397Timo Sirainenclient_send_login_reply(struct imap_client *client, string_t *str,
be71a9de88d1266597eb8c5e0b6f519d90e14397Timo Sirainen capability = client->proxy_backend_capability;
be71a9de88d1266597eb8c5e0b6f519d90e14397Timo Sirainen tagged_capability = strncasecmp(line, "[CAPABILITY ", 12) == 0;
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 if (!client->client_ignores_capability_resp_code &&
be71a9de88d1266597eb8c5e0b6f519d90e14397Timo Sirainen str_printfa(str, "[CAPABILITY %s] ", capability);
be71a9de88d1266597eb8c5e0b6f519d90e14397Timo Sirainen /* we need to send the capability.
be71a9de88d1266597eb8c5e0b6f519d90e14397Timo Sirainen skip over this resp-code */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainenint imap_proxy_parse_line(struct client *client, const char *line)
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct imap_client *imap_client = (struct imap_client *)client;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen output = login_proxy_get_ostream(client->login_proxy);
f30577ff7cf29858f1878abe963b4f40a436434fTimo Sirainen /* this is a banner */
3612ee5c737954d5fb88fd1775aad80f7bf1dc4eTimo Sirainen client->proxy_state = IMAP_PROXY_STATE_BANNER;
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen if (proxy_input_banner(imap_client, output, line) < 0) {
ccef83820a01bb37ad48653a05a9c5aa6560826aTimo Sirainen /* AUTHENTICATE started. finish it. */
27d50b3aa143964143e4bef66c0bfe3c72aea233Timo Sirainen /* used literals with LOGIN command, just ignore. */
3612ee5c737954d5fb88fd1775aad80f7bf1dc4eTimo Sirainen client->proxy_state = IMAP_PROXY_STATE_AUTH_CONTINUE;
9c47edf0d1aa8afa6d05dde93e7aa5169059c94aTimo Sirainen imap_client->proxy_wait_auth_continue = FALSE;
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsend(output, str_data(str), str_len(str));
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen /* STARTTLS failed */
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen "proxy: Remote STARTTLS failed: %s",
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) {
e95dba8921087afebb8a92c592af3b8ca22ae796Timo Sirainen /* i/ostreams changed. */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen output = login_proxy_get_ostream(client->login_proxy);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsend(output, str_data(str), str_len(str));
f30577ff7cf29858f1878abe963b4f40a436434fTimo Sirainen /* Login successful. Send this line to client. */
be71a9de88d1266597eb8c5e0b6f519d90e14397Timo Sirainen client_send_login_reply(imap_client, str, line + 5);
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsend(client->output, str_data(str), str_len(str));
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,
e3a838c80f54f024115fade93c6c87a0998f1fabTimo Sirainen /* remote sent some other resp-code. forward it. */
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen imap_client->cmd_tag, " ", line, "\r\n", NULL));
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,
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);
31750e7fddc514c68c4eaf85b4f8c00000c281e0Timo Sirainen /* Reply to CAPABILITY command we sent, ignore it */
3612ee5c737954d5fb88fd1775aad80f7bf1dc4eTimo Sirainen client->proxy_state = IMAP_PROXY_STATE_CAPABILITY;
087eb3d719a5667631cc7ce9de6c372ddea19f4dTimo Sirainen /* Reply to ID command we sent, ignore it */
087eb3d719a5667631cc7ce9de6c372ddea19f4dTimo Sirainen /* untagged reply. just foward it. */
00fa8dcbc66f56daa737487c9dec7166c37de79eTimo Sirainen client_send_raw(client, t_strconcat(line, "\r\n", NULL));
087eb3d719a5667631cc7ce9de6c372ddea19f4dTimo Sirainen /* tagged reply, shouldn't happen. */
9c47edf0d1aa8afa6d05dde93e7aa5169059c94aTimo Sirainen "proxy: Unexpected input, ignoring: %s",
e248fe370c4047cee921a91b48edc37944ab0526Timo Sirainen struct imap_client *imap_client = (struct imap_client *)client;
9c47edf0d1aa8afa6d05dde93e7aa5169059c94aTimo Sirainen imap_client->proxy_wait_auth_continue = FALSE;
9f627b360ed38fdc54cb02ec5e67246c3f0d5b0fTimo Sirainenvoid imap_proxy_error(struct client *client, const char *text)