imap-proxy.c revision a64adf62fa33f2463a86f990217b0c9078531a40
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen/* Copyright (c) 2004-2009 Dovecot authors, see the included COPYING file */
e307c8202280c6db60a0615381f18cac33e46a53Timo Sirainen "NO ["IMAP_RESP_CODE_UNAVAILABLE"] "AUTH_TEMP_FAILED_MSG
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic bool imap_banner_has_capability(const char *line, const char *capability)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int capability_len = strlen(capability);
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen while (strncmp(line, capability, capability_len) != 0 ||
589a9c6e8ee22071c14171c04bfc6bfe17121871Timo Sirainen /* skip over the capability */
945565e0c9cf979b5feeba6fbd4efce3bf4484adTimo Sirainenstatic void proxy_write_id(struct imap_client *client, string_t *str)
a53cb86b4d733d9c48ee4d285bed477c80825804Timo Sirainen "\"x-originating-ip\" \"%s\" "
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "\"x-originating-port\" \"%u\" "
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "\"x-connected-ip\" \"%s\" "
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "\"x-connected-port\" \"%u\")\r\n",
02d6628c1fea2990c67c60b111c8e68867160885Timo Sirainenstatic void proxy_free_password(struct imap_client *client)
db5164c9a1129af0cfb11fc18d88da361a8011fbTimo Sirainen safe_memset(client->proxy_password, 0, strlen(client->proxy_password));
945565e0c9cf979b5feeba6fbd4efce3bf4484adTimo Sirainenstatic void proxy_failed(struct imap_client *client, bool send_tagline)
5da1aa5197a43d83f0fb3eeb83125c7cd73d1b62Timo Sirainen client_send_tagline(client, PROXY_FAILURE_MSG);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* call this last - it may destroy the client */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void get_plain_auth(struct imap_client *client, string_t *dest)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen base64_encode(str_data(str), str_len(str), dest);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic int proxy_input_banner(struct imap_client *client,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client_syslog_err(&client->common, t_strdup_printf(
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen "proxy: Remote returned invalid banner: %s",
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen if (imap_banner_has_capability(line + 5, "ID"))
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* logging in normally - use LOGIN command */
4394b73cacaf2c31a9b601f66b6e26a1c8f114b4Timo Sirainen imap_quote_append_string(str, client->proxy_user, FALSE);
4394b73cacaf2c31a9b601f66b6e26a1c8f114b4Timo Sirainen imap_quote_append_string(str, client->proxy_password, FALSE);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else if (imap_banner_has_capability(line + 5, "SASL-IR")) {
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen /* master user login with SASL initial response support */
df1b2c3ff9cea4b57a4b9f1688bef54998fda5a4Timo Sirainen /* master user login without SASL initial response */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (void)o_stream_send(output, str_data(str), str_len(str));
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenstatic int proxy_input_line(struct imap_client *client,
db87d16551d1081ada01f787ea21aa3ed1402c31Timo Sirainen /* this is a banner */
db87d16551d1081ada01f787ea21aa3ed1402c31Timo Sirainen if (proxy_input_banner(client, output, line) < 0) {
807b48fe1f6a57b01ed2cc20247d5b5e3facc562Timo Sirainen /* AUTHENTICATE started. finish it. */
db87d16551d1081ada01f787ea21aa3ed1402c31Timo Sirainen (void)o_stream_send(output, str_data(str), str_len(str));
26ff8f8a4867bf8e9551a27a2de8c12cd138b065Timo Sirainen /* Login successful. Send this line to client. */
724b7fcf28c2547eb9c837d0e99241c0501dccf3Timo Sirainen str_printfa(str, "proxy(%s): started proxying to %s:%u",
2d39dc1a453546892109b35c0d9770369011a13dTimo Sirainen /* remote username is different, log it */
cfbacf6ea5fb39ae5304e4d95a78d9d4751bdfe1Timo Sirainen login_proxy_detach(client->proxy, client->common.input,
2d39dc1a453546892109b35c0d9770369011a13dTimo Sirainen /* If the backend server isn't Dovecot, the error message may
2d39dc1a453546892109b35c0d9770369011a13dTimo Sirainen be different from Dovecot's "user doesn't exist" error. This
7761758f43d6150be4b07f4c54457ce662f78c4cTimo Sirainen would allow an attacker to find out what users exist in the
62f4a199b5c9a0862f486cbf18e195cc621bbe25Timo Sirainen The optimal way to handle this would be to replace the
62f4a199b5c9a0862f486cbf18e195cc621bbe25Timo Sirainen backend's "password failed" error message with Dovecot's
62f4a199b5c9a0862f486cbf18e195cc621bbe25Timo Sirainen AUTH_FAILED_MSG, but this would require a new setting and
62f4a199b5c9a0862f486cbf18e195cc621bbe25Timo Sirainen the sysadmin to actually bother setting it properly.
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen So for now we'll just forward the error message. This
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen shouldn't be a real problem since of course everyone will
659fe5d24825b160cae512538088020d97a60239Timo Sirainen be using only Dovecot as their backend :) */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen str_printfa(str, "proxy(%s): Login failed to %s:%u",
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen /* remote username is different, log it */
6a0855a04d75bce3c0a2f68517d02f86ae72087fTimo Sirainen /* probably some untagged reply */
6a0855a04d75bce3c0a2f68517d02f86ae72087fTimo Sirainenstatic void proxy_input(struct istream *input, struct ostream *output,
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen /* we're just freeing the proxy */
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen /* we came here from client_destroy() */
9f19a50d5966643c4d1c5ca06868ac2ad31bc4d5Timo Sirainen /* failed for some reason, probably server disconnected */
7ce557e379d2df8c4c3c5639f251881f0a55f3b5Timo Sirainen "proxy: Remote input buffer full");
7ce557e379d2df8c4c3c5639f251881f0a55f3b5Timo Sirainen "proxy: Remote disconnected");
67bbcd664bebce9a507a49c67273be4814d07c97Timo Sirainen while ((line = i_stream_next_line(input)) != NULL) {
67bbcd664bebce9a507a49c67273be4814d07c97Timo Sirainen if (proxy_input_line(client, output, line) < 0)
67bbcd664bebce9a507a49c67273be4814d07c97Timo Sirainenint imap_proxy_new(struct imap_client *client, const char *host,
67bbcd664bebce9a507a49c67273be4814d07c97Timo Sirainen unsigned int port, const char *user, const char *master_user,
67bbcd664bebce9a507a49c67273be4814d07c97Timo Sirainen client_syslog_err(&client->common, "proxy: password not given");
67bbcd664bebce9a507a49c67273be4814d07c97Timo Sirainen client_send_tagline(client, PROXY_FAILURE_MSG);
7ce557e379d2df8c4c3c5639f251881f0a55f3b5Timo Sirainen /* connection_queue_add() decided that we were the oldest
7ce557e379d2df8c4c3c5639f251881f0a55f3b5Timo Sirainen connection and killed us. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (login_proxy_is_ourself(&client->common, host, port, user)) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client_syslog_err(&client->common, "Proxying loops to itself");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client_send_tagline(client, PROXY_FAILURE_MSG);
82d158d37db5cfb4e26affe4bc2f2a235901d1b9Timo Sirainen client->proxy = login_proxy_new(&client->common, host, port,
72af6886cb51e0ee02c9b3d6a7572eef8a0e236fTimo Sirainen client_send_tagline(client, PROXY_FAILURE_MSG);
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen client->proxy_master_user = i_strdup(master_user);
cded712c19ea8fb43c22726331de26b8a8dd234bTimo Sirainen /* disable input until authentication is finished */