pop3-proxy.c revision 9362c5623da599e4bb6ba8e9780c12b01ba6ce2d
a8c5a86d183db25a57bf193c06b41e092ec2e151Timo Sirainen/* Copyright (C) 2004 Timo Sirainen */
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen#include "common.h"
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen#include "ioloop.h"
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen#include "istream.h"
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen#include "ostream.h"
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen#include "base64.h"
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen#include "safe-memset.h"
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen#include "str.h"
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen#include "client.h"
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen#include "pop3-proxy.h"
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenstatic void proxy_input(struct istream *input, struct ostream *output,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen void *context)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen struct pop3_client *client = context;
0db42260be85e797aa9909a29b20296996f52e75Timo Sirainen string_t *str;
0db42260be85e797aa9909a29b20296996f52e75Timo Sirainen const char *line;
0db42260be85e797aa9909a29b20296996f52e75Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen i_assert(!client->destroyed);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (input == NULL) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (client->io != NULL) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen /* remote authentication failed, we're just
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen freeing the proxy */
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen /* failed for some reason, probably server disconnected */
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen client_send_line(client,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen "-ERR [IN-USE] Temporary login failure.");
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen client_destroy(client, NULL);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen switch (i_stream_read(input)) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen case -2:
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen /* buffer full */
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen i_error("pop-proxy(%s): Remote input buffer full",
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen client->common.virtual_user);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen client_destroy_internal_failure(client);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen case -1:
b49aa341d28c0eec1229e30baa2f89d5bae52ff8Phil Carmody /* disconnected */
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen client_destroy(client, "Proxy: Remote disconnected");
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen line = i_stream_next_line(input);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (line == NULL)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
16cb5d65265dd0b216542803fd80c4b999ae118eTimo Sirainen switch (client->proxy_state) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen case 0:
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen /* this is a banner */
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (strncmp(line, "+OK", 3) != 0) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen i_error("pop3-proxy(%s): "
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen "Remote returned invalid banner: %s",
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen client->common.virtual_user, line);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen client_destroy_internal_failure(client);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
0ca3b9cb0f2a322a25ce7f229dc3d3a0b46be17bTimo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen /* send USER command */
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen str = t_str_new(128);
16cb5d65265dd0b216542803fd80c4b999ae118eTimo Sirainen str_append(str, "USER ");
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen str_append(str, client->proxy_user);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen str_append(str, "\r\n");
16cb5d65265dd0b216542803fd80c4b999ae118eTimo Sirainen (void)o_stream_send(output, str_data(str), str_len(str));
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen client->proxy_state++;
16cb5d65265dd0b216542803fd80c4b999ae118eTimo Sirainen return;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen case 1:
16cb5d65265dd0b216542803fd80c4b999ae118eTimo Sirainen if (strncmp(line, "+OK", 3) != 0)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen break;
16cb5d65265dd0b216542803fd80c4b999ae118eTimo Sirainen
56d1345c43bbd28c36b7faa85e4163bd9e874290Timo Sirainen /* USER successful, send PASS */
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen str = t_str_new(128);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen str_append(str, "PASS ");
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen str_append(str, client->proxy_password);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen str_append(str, "\r\n");
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen (void)o_stream_send(output, str_data(str),
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen str_len(str));
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
16cb5d65265dd0b216542803fd80c4b999ae118eTimo Sirainen safe_memset(client->proxy_password, 0,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen strlen(client->proxy_password));
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen i_free(client->proxy_password);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen client->proxy_password = NULL;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen client->proxy_state++;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen case 2:
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (strncmp(line, "+OK", 3) != 0)
56aa97d74071f3a2987140c2ff1cfd5a59cb35aaTimo Sirainen break;
56aa97d74071f3a2987140c2ff1cfd5a59cb35aaTimo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen /* Login successful. Send this line to client. */
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen (void)o_stream_send_str(client->output, line);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen (void)o_stream_send(client->output, "\r\n", 2);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen login_proxy_detach(client->proxy, client->input,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen client->output);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen client->proxy = NULL;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen client->input = NULL;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen client->output = NULL;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen client->common.fd = -1;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen client_destroy(client,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen t_strdup_printf("proxy(%s): started",
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen client->common.virtual_user));
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen /* Login failed. Send our own failure reply so client can't
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen figure out if user exists or not just by looking at the
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen reply string. */
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen client_send_line(client, "-ERR "AUTH_FAILED_MSG);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen /* allow client input again */
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen i_assert(client->io == NULL);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen client->io = io_add(client->common.fd, IO_READ,
8c909e451d14075c05d90382cf8eebc4e354f569Timo Sirainen client_input, client);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen login_proxy_free(client->proxy);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen client->proxy = NULL;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (client->proxy_password != NULL) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen safe_memset(client->proxy_password, 0,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen strlen(client->proxy_password));
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen i_free(client->proxy_password);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen client->proxy_password = NULL;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen i_free(client->proxy_user);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen client->proxy_user = NULL;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainenint pop3_proxy_new(struct pop3_client *client, const char *host,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen unsigned int port, const char *user, const char *password)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen{
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen i_assert(user != NULL);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen i_assert(!client->destroyed);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (password == NULL) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen i_error("proxy(%s): password not given",
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen client->common.virtual_user);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return -1;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen i_assert(client->refcount > 1);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen connection_queue_add(1);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (client->destroyed) {
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen /* connection_queue_add() decided that we were the oldest
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen connection and killed us. */
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return -1;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen }
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen client->proxy = login_proxy_new(&client->common, host, port,
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen proxy_input, client);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen if (client->proxy == NULL)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return -1;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen client->proxy_state = 0;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen client->proxy_user = i_strdup(user);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen client->proxy_password = i_strdup(password);
9a1f68e5ab08eabd352d533315cba1c69006e2c1Timo Sirainen
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen /* disable input until authentication is finished */
bdb026e2dc8a7c77585ed5ba489f0056df8074d4Timo Sirainen if (client->io != NULL)
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen io_remove(&client->io);
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen return 0;
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen}
01435c38e7d671d5a892c4b802cfb204881cd454Timo Sirainen