pop3-proxy.c revision 1eff76c5dbd2ff14bbb7e40a164c290931bdf692
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen/* Copyright (C) 2004 Timo Sirainen */
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen#include "common.h"
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen#include "ioloop.h"
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen#include "istream.h"
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen#include "ostream.h"
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen#include "base64.h"
f3e1593a7d9b02090575fb20db90a235e10145a5Timo Sirainen#include "safe-memset.h"
f3e1593a7d9b02090575fb20db90a235e10145a5Timo Sirainen#include "str.h"
f3e1593a7d9b02090575fb20db90a235e10145a5Timo Sirainen#include "client.h"
f3e1593a7d9b02090575fb20db90a235e10145a5Timo Sirainen#include "pop3-proxy.h"
f3e1593a7d9b02090575fb20db90a235e10145a5Timo Sirainen
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainenstatic void proxy_input(struct istream *input, struct ostream *output,
f3e1593a7d9b02090575fb20db90a235e10145a5Timo Sirainen struct pop3_client *client)
f3e1593a7d9b02090575fb20db90a235e10145a5Timo Sirainen{
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen string_t *str;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen const char *line, *msg;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen i_assert(!client->destroyed);
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen if (input == NULL) {
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen if (client->io != NULL) {
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen /* remote authentication failed, we're just
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen freeing the proxy */
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen return;
acc8c0647873b1c847bfa362ddefd0d219d0aa91Timo Sirainen }
d8eedfaad386a8776e4931086b039b72e1ad38c4Timo Sirainen
acc8c0647873b1c847bfa362ddefd0d219d0aa91Timo Sirainen /* failed for some reason, probably server disconnected */
acc8c0647873b1c847bfa362ddefd0d219d0aa91Timo Sirainen client_send_line(client,
acc8c0647873b1c847bfa362ddefd0d219d0aa91Timo Sirainen "-ERR [IN-USE] Temporary login failure.");
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen client_destroy(client, NULL);
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen return;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen }
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen switch (i_stream_read(input)) {
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen case -2:
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen /* buffer full */
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen i_error("pop-proxy(%s): Remote input buffer full",
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen client->common.virtual_user);
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen client_destroy_internal_failure(client);
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen return;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen case -1:
e6bdf53eb0143af99e3eb977ff0f8a496ecd1a8dTimo Sirainen /* disconnected */
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen client_destroy(client, "Proxy: Remote disconnected");
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen return;
f3e1593a7d9b02090575fb20db90a235e10145a5Timo Sirainen }
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen
f3e1593a7d9b02090575fb20db90a235e10145a5Timo Sirainen line = i_stream_next_line(input);
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen if (line == NULL)
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen return;
f3e1593a7d9b02090575fb20db90a235e10145a5Timo Sirainen
9446c7a5d400cba60d097c528bd08312552438e3Timo Sirainen switch (client->proxy_state) {
9446c7a5d400cba60d097c528bd08312552438e3Timo Sirainen case 0:
9446c7a5d400cba60d097c528bd08312552438e3Timo Sirainen /* this is a banner */
f3e1593a7d9b02090575fb20db90a235e10145a5Timo Sirainen if (strncmp(line, "+OK", 3) != 0) {
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen i_error("pop3-proxy(%s): "
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen "Remote returned invalid banner: %s",
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen client->common.virtual_user, line);
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen client_destroy_internal_failure(client);
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen return;
ad3a1b8f8e2a5596afb1b099a69ae6f688887eecTimo Sirainen }
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen /* send USER command */
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen str = t_str_new(128);
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen str_append(str, "USER ");
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen str_append(str, client->proxy_user);
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen str_append(str, "\r\n");
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen (void)o_stream_send(output, str_data(str), str_len(str));
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen client->proxy_state++;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen return;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen case 1:
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen if (strncmp(line, "+OK", 3) != 0)
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen break;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen
e6bdf53eb0143af99e3eb977ff0f8a496ecd1a8dTimo Sirainen /* USER successful, send PASS */
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen str = t_str_new(128);
9446c7a5d400cba60d097c528bd08312552438e3Timo Sirainen str_append(str, "PASS ");
9446c7a5d400cba60d097c528bd08312552438e3Timo Sirainen str_append(str, client->proxy_password);
9446c7a5d400cba60d097c528bd08312552438e3Timo Sirainen str_append(str, "\r\n");
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen (void)o_stream_send(output, str_data(str),
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen str_len(str));
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen safe_memset(client->proxy_password, 0,
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen strlen(client->proxy_password));
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen i_free(client->proxy_password);
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen client->proxy_password = NULL;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen client->proxy_state++;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen return;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen case 2:
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen if (strncmp(line, "+OK", 3) != 0)
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen break;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen /* Login successful. Send this line to client. */
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen (void)o_stream_send_str(client->output, line);
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen (void)o_stream_send(client->output, "\r\n", 2);
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen msg = t_strdup_printf("proxy(%s): started proxying to %s:%u",
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen client->common.virtual_user,
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen login_proxy_get_host(client->proxy),
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen login_proxy_get_port(client->proxy));
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen login_proxy_detach(client->proxy, client->input,
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen client->output);
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen client->proxy = NULL;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen client->input = NULL;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen client->output = NULL;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen client->common.fd = -1;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen client_destroy(client, msg);
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen return;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen }
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen /* Login failed. Send our own failure reply so client can't
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen figure out if user exists or not just by looking at the
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen reply string. */
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen client_send_line(client, "-ERR "AUTH_FAILED_MSG);
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen /* allow client input again */
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen i_assert(client->io == NULL);
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen client->io = io_add(client->common.fd, IO_READ,
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen client_input, client);
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen login_proxy_free(client->proxy);
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen client->proxy = NULL;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen if (client->proxy_password != NULL) {
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen safe_memset(client->proxy_password, 0,
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen strlen(client->proxy_password));
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen i_free(client->proxy_password);
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen client->proxy_password = NULL;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen }
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen i_free(client->proxy_user);
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen client->proxy_user = NULL;
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen}
b494ffed8ded8d170d9ace3dc607b1d278048241Timo Sirainen
int pop3_proxy_new(struct pop3_client *client, const char *host,
unsigned int port, const char *user, const char *password)
{
i_assert(user != NULL);
i_assert(!client->destroyed);
if (password == NULL) {
i_error("proxy(%s): password not given",
client->common.virtual_user);
return -1;
}
i_assert(client->refcount > 1);
connection_queue_add(1);
if (client->destroyed) {
/* connection_queue_add() decided that we were the oldest
connection and killed us. */
return -1;
}
client->proxy = login_proxy_new(&client->common, host, port,
proxy_input, client);
if (client->proxy == NULL)
return -1;
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;
}