imap-proxy.c revision 02c335c23bf5fa225a467c19f2c063fb0dc7b8c3
a6e79dffa06db28bcfad9c1e5fc819c48172d5deTimo Sirainen/* Copyright (c) 2004-2016 Dovecot authors, see the included COPYING file */
a6e79dffa06db28bcfad9c1e5fc819c48172d5deTimo Sirainenstatic void proxy_write_id(struct imap_client *client, string_t *str)
a6e79dffa06db28bcfad9c1e5fc819c48172d5deTimo Sirainen "\"x-session-id\" \"%s\" "
a6e79dffa06db28bcfad9c1e5fc819c48172d5deTimo Sirainen "\"x-originating-ip\" \"%s\" "
a6e79dffa06db28bcfad9c1e5fc819c48172d5deTimo Sirainen "\"x-originating-port\" \"%u\" "
a6e79dffa06db28bcfad9c1e5fc819c48172d5deTimo Sirainen "\"x-connected-ip\" \"%s\" "
a6e79dffa06db28bcfad9c1e5fc819c48172d5deTimo Sirainen "\"x-connected-port\" \"%u\" "
a6e79dffa06db28bcfad9c1e5fc819c48172d5deTimo Sirainen "\"x-proxy-ttl\" \"%u\")\r\n",
a6e79dffa06db28bcfad9c1e5fc819c48172d5deTimo Sirainenstatic void proxy_free_password(struct client *client)
a6e79dffa06db28bcfad9c1e5fc819c48172d5deTimo Sirainen safe_memset(client->proxy_password, 0, strlen(client->proxy_password));
a6e79dffa06db28bcfad9c1e5fc819c48172d5deTimo Sirainenstatic int proxy_write_login(struct imap_client *client, string_t *str)
a6e79dffa06db28bcfad9c1e5fc819c48172d5deTimo Sirainen const unsigned char *output;
a6e79dffa06db28bcfad9c1e5fc819c48172d5deTimo Sirainen unsigned int len;
a6e79dffa06db28bcfad9c1e5fc819c48172d5deTimo Sirainen /* Send CAPABILITY command if we don't know the capabilities yet.
11352dc3e4b29f3d2763c82f8ea4f99e8daf4fa3Timo Sirainen Also as kind of a Dovecot-backend workaround if the client insisted
a6e79dffa06db28bcfad9c1e5fc819c48172d5deTimo Sirainen on sending CAPABILITY command (even though our banner already sent
a6e79dffa06db28bcfad9c1e5fc819c48172d5deTimo Sirainen it), send the (unnecessary) CAPABILITY command to backend as well
a6e79dffa06db28bcfad9c1e5fc819c48172d5deTimo Sirainen to avoid sending the CAPABILITY reply twice (untagged and OK resp
a6e79dffa06db28bcfad9c1e5fc819c48172d5deTimo Sirainen client->client_ignores_capability_resp_code)) {
a6e79dffa06db28bcfad9c1e5fc819c48172d5deTimo Sirainen /* authenticate only after receiving C OK reply. */
a6e79dffa06db28bcfad9c1e5fc819c48172d5deTimo Sirainen /* logging in normally - use LOGIN command */
a6e79dffa06db28bcfad9c1e5fc819c48172d5deTimo Sirainen imap_append_string(str, client->common.proxy_user);
a6e79dffa06db28bcfad9c1e5fc819c48172d5deTimo Sirainen imap_append_string(str, client->common.proxy_password);
a6e79dffa06db28bcfad9c1e5fc819c48172d5deTimo Sirainen i_assert(client->common.proxy_sasl_client == NULL);
a6e79dffa06db28bcfad9c1e5fc819c48172d5deTimo Sirainen sasl_set.authid = client->common.proxy_master_user != NULL ?
a6e79dffa06db28bcfad9c1e5fc819c48172d5deTimo Sirainen client->common.proxy_master_user : client->common.proxy_user;
a6e79dffa06db28bcfad9c1e5fc819c48172d5deTimo Sirainen sasl_set.password = client->common.proxy_password;
a6e79dffa06db28bcfad9c1e5fc819c48172d5deTimo Sirainen dsasl_client_new(client->common.proxy_mech, &sasl_set);
a6e79dffa06db28bcfad9c1e5fc819c48172d5deTimo Sirainen mech_name = dsasl_client_mech_get_name(client->common.proxy_mech);
a6e79dffa06db28bcfad9c1e5fc819c48172d5deTimo Sirainen if (dsasl_client_output(client->common.proxy_sasl_client,
a6e79dffa06db28bcfad9c1e5fc819c48172d5deTimo Sirainen client_log_err(&client->common, t_strdup_printf(
a6e79dffa06db28bcfad9c1e5fc819c48172d5deTimo Sirainen "proxy: SASL mechanism %s init failed: %s",
9bd607718368ffb39bcfbc82010073364901c5a2Timo Sirainenstatic int proxy_input_banner(struct imap_client *client,
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen client_log_err(&client->common, t_strdup_printf(
9bd607718368ffb39bcfbc82010073364901c5a2Timo Sirainen "proxy: Remote returned invalid banner: %s",
9bd607718368ffb39bcfbc82010073364901c5a2Timo Sirainen if (strncmp(line + 5, "[CAPABILITY ", 12) == 0) {
9bd607718368ffb39bcfbc82010073364901c5a2Timo Sirainen capabilities = t_strsplit(t_strcut(line + 5 + 12, ']'), " ");
a6e79dffa06db28bcfad9c1e5fc819c48172d5deTimo Sirainen if (str_array_icase_find(capabilities, "SASL-IR"))
a6e79dffa06db28bcfad9c1e5fc819c48172d5deTimo Sirainen ssl_flags = login_proxy_get_ssl_flags(client->common.login_proxy);
a6e79dffa06db28bcfad9c1e5fc819c48172d5deTimo Sirainen if ((ssl_flags & PROXY_SSL_FLAG_STARTTLS) != 0) {
9bd607718368ffb39bcfbc82010073364901c5a2Timo Sirainen !str_array_icase_find(capabilities, "STARTTLS")) {
a6e79dffa06db28bcfad9c1e5fc819c48172d5deTimo Sirainen "proxy: Remote doesn't support STARTTLS");
a6e79dffa06db28bcfad9c1e5fc819c48172d5deTimo Sirainen o_stream_nsend(output, str_data(str), str_len(str));
a6e79dffa06db28bcfad9c1e5fc819c48172d5deTimo Sirainenclient_send_login_reply(struct imap_client *client, string_t *str,
9bd607718368ffb39bcfbc82010073364901c5a2Timo Sirainen capability = client->proxy_backend_capability;
9bd607718368ffb39bcfbc82010073364901c5a2Timo Sirainen tagged_capability = strncasecmp(line, "[CAPABILITY ", 12) == 0;
9bd607718368ffb39bcfbc82010073364901c5a2Timo Sirainen if (client->client_ignores_capability_resp_code && capability != NULL) {
9bd607718368ffb39bcfbc82010073364901c5a2Timo Sirainen /* client has used CAPABILITY command, so it didn't understand
9bd607718368ffb39bcfbc82010073364901c5a2Timo Sirainen the capabilities in the banner. send the backend's untagged
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen CAPABILITY reply and hope that the client understands it */
9bd607718368ffb39bcfbc82010073364901c5a2Timo Sirainen str_printfa(str, "* CAPABILITY %s\r\n", capability);
9bd607718368ffb39bcfbc82010073364901c5a2Timo Sirainen if (!client->client_ignores_capability_resp_code &&
9bd607718368ffb39bcfbc82010073364901c5a2Timo Sirainen str_printfa(str, "[CAPABILITY %s] ", capability);
9bd607718368ffb39bcfbc82010073364901c5a2Timo Sirainen /* we need to send the capability.
9bd607718368ffb39bcfbc82010073364901c5a2Timo Sirainen skip over this resp-code */
9bd607718368ffb39bcfbc82010073364901c5a2Timo Sirainenint imap_proxy_parse_line(struct client *client, const char *line)
9bd607718368ffb39bcfbc82010073364901c5a2Timo Sirainen struct imap_client *imap_client = (struct imap_client *)client;
9bd607718368ffb39bcfbc82010073364901c5a2Timo Sirainen const unsigned char *data;
9bd607718368ffb39bcfbc82010073364901c5a2Timo Sirainen output = login_proxy_get_ostream(client->login_proxy);
9bd607718368ffb39bcfbc82010073364901c5a2Timo Sirainen /* this is a banner */
9bd607718368ffb39bcfbc82010073364901c5a2Timo Sirainen client->proxy_state = IMAP_PROXY_STATE_BANNER;
9bd607718368ffb39bcfbc82010073364901c5a2Timo Sirainen if (proxy_input_banner(imap_client, output, line) < 0) {
9bd607718368ffb39bcfbc82010073364901c5a2Timo Sirainen /* AUTHENTICATE started. finish it. */
9bd607718368ffb39bcfbc82010073364901c5a2Timo Sirainen /* used literals with LOGIN command, just ignore. */
9bd607718368ffb39bcfbc82010073364901c5a2Timo Sirainen client->proxy_state = IMAP_PROXY_STATE_AUTH_CONTINUE;
9bd607718368ffb39bcfbc82010073364901c5a2Timo Sirainen base64_decode(line+2, strlen(line+2), NULL, str) < 0) {
9bd607718368ffb39bcfbc82010073364901c5a2Timo Sirainen "proxy: Server sent invalid base64 data in AUTHENTICATE response");
9bd607718368ffb39bcfbc82010073364901c5a2Timo Sirainen ret = dsasl_client_input(client->proxy_sasl_client,
a6e79dffa06db28bcfad9c1e5fc819c48172d5deTimo Sirainen ret = dsasl_client_output(client->proxy_sasl_client,
a6e79dffa06db28bcfad9c1e5fc819c48172d5deTimo Sirainen "proxy: Server sent invalid authentication data: %s",