pop3-proxy.c revision 4b6ddd3770c8484da7308032b75fc93b91aa1b49
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2004-2008 Dovecot authors, see the included COPYING file */
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen#include "common.h"
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen#include "ioloop.h"
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen#include "istream.h"
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen#include "ostream.h"
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen#include "base64.h"
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen#include "safe-memset.h"
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen#include "str.h"
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen#include "str-sanitize.h"
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen#include "client.h"
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen#include "pop3-proxy.h"
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainenstatic void proxy_input(struct istream *input, struct ostream *output,
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen struct pop3_client *client)
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen{
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen string_t *str;
4c9294fcb17fb12326ff5db29e2f882cf4bd7fedTimo Sirainen const char *line, *msg;
4c9294fcb17fb12326ff5db29e2f882cf4bd7fedTimo Sirainen
4c9294fcb17fb12326ff5db29e2f882cf4bd7fedTimo Sirainen if (input == NULL) {
4c9294fcb17fb12326ff5db29e2f882cf4bd7fedTimo Sirainen if (client->io != NULL) {
4c9294fcb17fb12326ff5db29e2f882cf4bd7fedTimo Sirainen /* remote authentication failed, we're just
4c9294fcb17fb12326ff5db29e2f882cf4bd7fedTimo Sirainen freeing the proxy */
4c9294fcb17fb12326ff5db29e2f882cf4bd7fedTimo Sirainen return;
4c9294fcb17fb12326ff5db29e2f882cf4bd7fedTimo Sirainen }
4c9294fcb17fb12326ff5db29e2f882cf4bd7fedTimo Sirainen
4c9294fcb17fb12326ff5db29e2f882cf4bd7fedTimo Sirainen if (client->destroyed) {
4c9294fcb17fb12326ff5db29e2f882cf4bd7fedTimo Sirainen /* we came here from client_destroy() */
4c9294fcb17fb12326ff5db29e2f882cf4bd7fedTimo Sirainen return;
4c9294fcb17fb12326ff5db29e2f882cf4bd7fedTimo Sirainen }
4c9294fcb17fb12326ff5db29e2f882cf4bd7fedTimo Sirainen
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen /* failed for some reason, probably server disconnected */
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen client_send_line(client,
18a2214eedb08d043277cf1d3e75c45762014663Timo Sirainen "-ERR [IN-USE] Temporary login failure.");
18a2214eedb08d043277cf1d3e75c45762014663Timo Sirainen client_destroy(client, NULL);
18a2214eedb08d043277cf1d3e75c45762014663Timo Sirainen return;
18a2214eedb08d043277cf1d3e75c45762014663Timo Sirainen }
18a2214eedb08d043277cf1d3e75c45762014663Timo Sirainen
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen i_assert(!client->destroyed);
5a8ee853d0b62692a6e624b125d08d87a79e001fTimo Sirainen
18a2214eedb08d043277cf1d3e75c45762014663Timo Sirainen switch (i_stream_read(input)) {
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen case -2:
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen /* buffer full */
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen client_syslog(&client->common,
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen "proxy: Remote input buffer full");
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen client_destroy_internal_failure(client);
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen return;
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen case -1:
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen /* disconnected */
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen client_destroy(client, "Proxy: Remote disconnected");
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen return;
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen }
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen line = i_stream_next_line(input);
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen if (line == NULL)
5a8ee853d0b62692a6e624b125d08d87a79e001fTimo Sirainen return;
18a2214eedb08d043277cf1d3e75c45762014663Timo Sirainen
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen switch (client->proxy_state) {
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen case 0:
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen /* this is a banner */
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen if (strncmp(line, "+OK", 3) != 0) {
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen client_syslog(&client->common, t_strdup_printf(
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen "proxy: Remote returned invalid banner: %s",
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen str_sanitize(line, 160)));
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen client_destroy_internal_failure(client);
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen return;
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen }
58a770f1e0ab553a0dba9cad9d6f3a6cdf2dc855Timo Sirainen
58a770f1e0ab553a0dba9cad9d6f3a6cdf2dc855Timo Sirainen /* send USER command */
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen str = t_str_new(128);
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen str_append(str, "USER ");
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen str_append(str, client->proxy_user);
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen str_append(str, "\r\n");
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen (void)o_stream_send(output, str_data(str), str_len(str));
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen client->proxy_state++;
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen return;
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen case 1:
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen if (strncmp(line, "+OK", 3) != 0)
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen break;
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen /* USER successful, send PASS */
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen str = t_str_new(128);
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen str_append(str, "PASS ");
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen str_append(str, client->proxy_password);
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen str_append(str, "\r\n");
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen (void)o_stream_send(output, str_data(str),
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen str_len(str));
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen safe_memset(client->proxy_password, 0,
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen strlen(client->proxy_password));
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen i_free(client->proxy_password);
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen client->proxy_password = NULL;
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen client->proxy_state++;
18a2214eedb08d043277cf1d3e75c45762014663Timo Sirainen return;
18a2214eedb08d043277cf1d3e75c45762014663Timo Sirainen case 2:
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen if (strncmp(line, "+OK", 3) != 0)
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen break;
18a2214eedb08d043277cf1d3e75c45762014663Timo Sirainen
18a2214eedb08d043277cf1d3e75c45762014663Timo Sirainen /* Login successful. Send this line to client. */
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen (void)o_stream_send_str(client->output, line);
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen (void)o_stream_send(client->output, "\r\n", 2);
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen msg = t_strdup_printf("proxy(%s): started proxying to %s:%u",
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen client->common.virtual_user,
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen login_proxy_get_host(client->proxy),
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen login_proxy_get_port(client->proxy));
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen login_proxy_detach(client->proxy, client->input,
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen client->output);
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen client->proxy = NULL;
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen client->input = NULL;
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen client->output = NULL;
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen client->common.fd = -1;
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen client_destroy(client, msg);
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen return;
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen }
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen /* Login failed. Pass through the error message to client
6b8f4863bb2b0938d40f774122baf6528a833ea0Timo Sirainen (see imap-proxy code for potential problems with this) */
f55b07916c82db8b915b28252e44ce6fb2bd3080Timo Sirainen if (strncmp(line, "-ERR ", 5) != 0)
f55b07916c82db8b915b28252e44ce6fb2bd3080Timo Sirainen client_send_line(client, "-ERR "AUTH_FAILED_MSG);
f55b07916c82db8b915b28252e44ce6fb2bd3080Timo Sirainen else
f55b07916c82db8b915b28252e44ce6fb2bd3080Timo Sirainen client_send_line(client, line);
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen /* allow client input again */
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen i_assert(client->io == NULL);
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen client->io = io_add(client->common.fd, IO_READ,
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen client_input, client);
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen login_proxy_free(client->proxy);
4c9294fcb17fb12326ff5db29e2f882cf4bd7fedTimo Sirainen client->proxy = NULL;
a1973d0f171b027f9a7c642bc1c2134293731e1cTimo Sirainen
a1973d0f171b027f9a7c642bc1c2134293731e1cTimo Sirainen if (client->proxy_password != NULL) {
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen safe_memset(client->proxy_password, 0,
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen strlen(client->proxy_password));
a1973d0f171b027f9a7c642bc1c2134293731e1cTimo Sirainen i_free(client->proxy_password);
a1973d0f171b027f9a7c642bc1c2134293731e1cTimo Sirainen client->proxy_password = NULL;
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen }
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen
18a2214eedb08d043277cf1d3e75c45762014663Timo Sirainen i_free(client->proxy_user);
18a2214eedb08d043277cf1d3e75c45762014663Timo Sirainen client->proxy_user = NULL;
18a2214eedb08d043277cf1d3e75c45762014663Timo Sirainen}
4c9294fcb17fb12326ff5db29e2f882cf4bd7fedTimo Sirainen
18a2214eedb08d043277cf1d3e75c45762014663Timo Sirainenint pop3_proxy_new(struct pop3_client *client, const char *host,
18a2214eedb08d043277cf1d3e75c45762014663Timo Sirainen unsigned int port, const char *user, const char *password)
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen{
f55b07916c82db8b915b28252e44ce6fb2bd3080Timo Sirainen i_assert(user != NULL);
a8ebb72c0fba1a6a71104e530bf5903d5f149351Timo Sirainen i_assert(!client->destroyed);
a8ebb72c0fba1a6a71104e530bf5903d5f149351Timo Sirainen
a8ebb72c0fba1a6a71104e530bf5903d5f149351Timo Sirainen if (password == NULL) {
a8ebb72c0fba1a6a71104e530bf5903d5f149351Timo Sirainen client_syslog(&client->common, "proxy: password not given");
a8ebb72c0fba1a6a71104e530bf5903d5f149351Timo Sirainen return -1;
f55b07916c82db8b915b28252e44ce6fb2bd3080Timo Sirainen }
f55b07916c82db8b915b28252e44ce6fb2bd3080Timo Sirainen
f55b07916c82db8b915b28252e44ce6fb2bd3080Timo Sirainen i_assert(client->refcount > 1);
f55b07916c82db8b915b28252e44ce6fb2bd3080Timo Sirainen connection_queue_add(1);
f55b07916c82db8b915b28252e44ce6fb2bd3080Timo Sirainen
f55b07916c82db8b915b28252e44ce6fb2bd3080Timo Sirainen if (client->destroyed) {
f55b07916c82db8b915b28252e44ce6fb2bd3080Timo Sirainen /* connection_queue_add() decided that we were the oldest
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen connection and killed us. */
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen return -1;
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen }
f55b07916c82db8b915b28252e44ce6fb2bd3080Timo Sirainen
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen client->proxy = login_proxy_new(&client->common, host, port,
39025a2dabfcfaeee3790988b9ea00d19887a3d3Timo Sirainen proxy_input, client);
f55b07916c82db8b915b28252e44ce6fb2bd3080Timo Sirainen if (client->proxy == NULL)
f55b07916c82db8b915b28252e44ce6fb2bd3080Timo Sirainen return -1;
f55b07916c82db8b915b28252e44ce6fb2bd3080Timo Sirainen
f55b07916c82db8b915b28252e44ce6fb2bd3080Timo Sirainen client->proxy_state = 0;
f55b07916c82db8b915b28252e44ce6fb2bd3080Timo Sirainen client->proxy_user = i_strdup(user);
f55b07916c82db8b915b28252e44ce6fb2bd3080Timo Sirainen client->proxy_password = i_strdup(password);
f55b07916c82db8b915b28252e44ce6fb2bd3080Timo Sirainen
f55b07916c82db8b915b28252e44ce6fb2bd3080Timo Sirainen /* disable input until authentication is finished */
f55b07916c82db8b915b28252e44ce6fb2bd3080Timo Sirainen if (client->io != NULL)
18a2214eedb08d043277cf1d3e75c45762014663Timo Sirainen io_remove(&client->io);
f55b07916c82db8b915b28252e44ce6fb2bd3080Timo Sirainen return 0;
f55b07916c82db8b915b28252e44ce6fb2bd3080Timo Sirainen}
f55b07916c82db8b915b28252e44ce6fb2bd3080Timo Sirainen