pop3-proxy.c revision d7cd49f01fad7c87c5a0865ebf54a548275e9fee
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (C) 2004 Timo Sirainen */
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen#include "common.h"
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen#include "ioloop.h"
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen#include "istream.h"
7a7d2aa11e46195e2d92d6c337d7e78052a5ce67Timo Sirainen#include "ostream.h"
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen#include "base64.h"
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen#include "safe-memset.h"
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen#include "str.h"
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen#include "client.h"
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen#include "pop3-proxy.h"
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainenstatic void proxy_input(struct istream *input, struct ostream *output,
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen struct pop3_client *client)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen{
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen string_t *str;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen const char *line, *msg;
f7539a17ea306191b53b8f5e752e228937df9ec3Timo Sirainen
f7539a17ea306191b53b8f5e752e228937df9ec3Timo Sirainen if (input == NULL) {
f7539a17ea306191b53b8f5e752e228937df9ec3Timo Sirainen if (client->io != NULL) {
f7539a17ea306191b53b8f5e752e228937df9ec3Timo Sirainen /* remote authentication failed, we're just
f7539a17ea306191b53b8f5e752e228937df9ec3Timo Sirainen freeing the proxy */
f7539a17ea306191b53b8f5e752e228937df9ec3Timo Sirainen return;
f7539a17ea306191b53b8f5e752e228937df9ec3Timo Sirainen }
f7539a17ea306191b53b8f5e752e228937df9ec3Timo Sirainen
f7539a17ea306191b53b8f5e752e228937df9ec3Timo Sirainen if (client->destroyed) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* we came here from client_destroy() */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen return;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen }
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* failed for some reason, probably server disconnected */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen client_send_line(client,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen "-ERR [IN-USE] Temporary login failure.");
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen client_destroy(client, NULL);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen return;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen }
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen i_assert(!client->destroyed);
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen switch (i_stream_read(input)) {
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen case -2:
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen /* buffer full */
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen i_error("pop-proxy(%s): Remote input buffer full",
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen client->common.virtual_user);
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen client_destroy_internal_failure(client);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen return;
3b32bc12710240f86465a00fbb2bd1ef030e6c40Timo Sirainen case -1:
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen /* disconnected */
d22301419109ed4a38351715e6760011421dadecTimo Sirainen client_destroy(client, "Proxy: Remote disconnected");
d22301419109ed4a38351715e6760011421dadecTimo Sirainen return;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen }
d22301419109ed4a38351715e6760011421dadecTimo Sirainen
d22301419109ed4a38351715e6760011421dadecTimo Sirainen line = i_stream_next_line(input);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen if (line == NULL)
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen return;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen switch (client->proxy_state) {
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen case 0:
d22301419109ed4a38351715e6760011421dadecTimo Sirainen /* this is a banner */
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen if (strncmp(line, "+OK", 3) != 0) {
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen i_error("pop3-proxy(%s): "
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen "Remote returned invalid banner: %s",
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen client->common.virtual_user, line);
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen client_destroy_internal_failure(client);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen return;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen }
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen /* send USER command */
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen str = t_str_new(128);
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen str_append(str, "USER ");
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen str_append(str, client->proxy_user);
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen str_append(str, "\r\n");
b42697a5749b85659a24316d97f1c208d469e4e8Timo Sirainen (void)o_stream_send(output, str_data(str), str_len(str));
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen client->proxy_state++;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen return;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen case 1:
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen if (strncmp(line, "+OK", 3) != 0)
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen break;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen /* USER successful, send PASS */
df00412606a00714a6e85383fa87fbdc7cc1fb5bTimo Sirainen str = t_str_new(128);
df00412606a00714a6e85383fa87fbdc7cc1fb5bTimo Sirainen str_append(str, "PASS ");
df00412606a00714a6e85383fa87fbdc7cc1fb5bTimo Sirainen str_append(str, client->proxy_password);
df00412606a00714a6e85383fa87fbdc7cc1fb5bTimo Sirainen str_append(str, "\r\n");
724b7fcf28c2547eb9c837d0e99241c0501dccf3Timo Sirainen (void)o_stream_send(output, str_data(str),
724b7fcf28c2547eb9c837d0e99241c0501dccf3Timo Sirainen str_len(str));
df00412606a00714a6e85383fa87fbdc7cc1fb5bTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen safe_memset(client->proxy_password, 0,
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen strlen(client->proxy_password));
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen i_free(client->proxy_password);
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen client->proxy_password = NULL;
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen client->proxy_state++;
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen return;
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen case 2:
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen if (strncmp(line, "+OK", 3) != 0)
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen break;
3c493c276f599d9b9cd10764876d648003046954Timo Sirainen
9ffdc9d18870acef2e4dde99715d8528ff4b080dTimo Sirainen /* Login successful. Send this line to client. */
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen (void)o_stream_send_str(client->output, line);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen (void)o_stream_send(client->output, "\r\n", 2);
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen msg = t_strdup_printf("proxy(%s): started proxying to %s:%u",
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen client->common.virtual_user,
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen login_proxy_get_host(client->proxy),
f81f4bc282cd1944cec187bae89c0701a416ed2aTimo Sirainen login_proxy_get_port(client->proxy));
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen login_proxy_detach(client->proxy, client->input,
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen client->output);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen client->proxy = NULL;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen client->input = NULL;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen client->output = NULL;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen client->common.fd = -1;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen client_destroy(client, msg);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen return;
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen }
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen
dca6d617a23e3f93af3b8df59acb46478179fe55Timo Sirainen /* Login failed. Send our own failure reply so client can't
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen figure out if user exists or not just by looking at the
1108376e39a19912e8394e64e19b1bc6f6691cf6Timo Sirainen reply string. */
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen client_send_line(client, "-ERR "AUTH_FAILED_MSG);
3e564425db51f3921ce4de11859777135fdedd15Timo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen /* allow client input again */
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen i_assert(client->io == NULL);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen client->io = io_add(client->common.fd, IO_READ,
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen client_input, client);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen login_proxy_free(client->proxy);
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen client->proxy = NULL;
306cfd77100131c08b243de10f6d40500f4c27c6Timo Sirainen
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen if (client->proxy_password != NULL) {
09c08fad8e7cc694a6c8d1711e67839acd3a2f04Timo Sirainen safe_memset(client->proxy_password, 0,
438f12d7a776da695019114884b48188d94613efTimo Sirainen strlen(client->proxy_password));
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen i_free(client->proxy_password);
9ffdc9d18870acef2e4dde99715d8528ff4b080dTimo Sirainen client->proxy_password = NULL;
61b0637759146621cbb7edcbd0b03a71cfd66dfeTimo Sirainen }
2649b237dd4690575e75a30b2bf3b39ebd37b835Timo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen i_free(client->proxy_user);
d3442384ca53d4b18a493db7dd0b000f470419cfTimo Sirainen client->proxy_user = NULL;
6469cf211a57433335641725dc236ebb2b9fdd3bTimo Sirainen}
c0d069950af1dbc6a4e5c3de3bf2e437796e3ae0Timo Sirainen
c0d069950af1dbc6a4e5c3de3bf2e437796e3ae0Timo Sirainenint pop3_proxy_new(struct pop3_client *client, const char *host,
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen unsigned int port, const char *user, const char *password)
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen{
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen i_assert(user != NULL);
5137d2d80255938a0f5fb8f3c1a21b34cf11ada3Timo Sirainen i_assert(!client->destroyed);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen if (password == NULL) {
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen i_error("proxy(%s): password not given",
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen client->common.virtual_user);
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen return -1;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen }
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen i_assert(client->refcount > 1);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen connection_queue_add(1);
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen if (client->destroyed) {
e3aeeb634245e80d4f643f8d2eea11d6b72336d8Timo Sirainen /* connection_queue_add() decided that we were the oldest
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen connection and killed us. */
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen return -1;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen }
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
1460ef7a18c53216ddb4a94bb62fba96076aae8eTimo Sirainen client->proxy = login_proxy_new(&client->common, host, port,
1460ef7a18c53216ddb4a94bb62fba96076aae8eTimo Sirainen proxy_input, client);
1460ef7a18c53216ddb4a94bb62fba96076aae8eTimo Sirainen if (client->proxy == NULL)
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen return -1;
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen
c6a57378d3c54988f525f81e19c0c5d132a0770dTimo Sirainen client->proxy_state = 0;
client->proxy_user = i_strdup(user);
client->proxy_password = i_strdup(password);
/* disable input until authentication is finished */
if (client->io != NULL)
io_remove(&client->io);
return 0;
}