pop3-proxy.c revision ab1236617440e654d5c5a043b677512714b788dd
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (C) 2004 Timo Sirainen */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen#include "common.h"
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen#include "ioloop.h"
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen#include "istream.h"
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen#include "ostream.h"
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen#include "base64.h"
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen#include "safe-memset.h"
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen#include "str.h"
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen#include "client.h"
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen#include "pop3-proxy.h"
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainenstatic void proxy_input(struct istream *input, struct ostream *output,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen void *context)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen{
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen struct pop3_client *client = context;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen string_t *str;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen const char *line;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (input == NULL) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (client->io != NULL) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen /* remote authentication failed, we're just
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen freeing the proxy */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen /* failed for some reason */
b8835b8a21c617ceb82ddc5a176243faf36aa8f7Timo Sirainen client_destroy_internal_failure(client);
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen return;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen switch (i_stream_read(input)) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen case -2:
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen /* buffer full */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen i_error("pop-proxy(%s): Remote input buffer full",
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen client->common.virtual_user);
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen client_destroy_internal_failure(client);
a0c453a8edaec90fb0d945c874de0b1845bc7d7eTimo Sirainen return;
b8835b8a21c617ceb82ddc5a176243faf36aa8f7Timo Sirainen case -1:
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen /* disconnected */
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen client_destroy(client, "Proxy: Remote disconnected");
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return;
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen }
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen line = i_stream_next_line(input);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (line == NULL)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen switch (client->proxy_state) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen case 0:
beae08c3abc23434d15572ab3b059fbdf8efc2dfTimo Sirainen /* this is a banner */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (strncmp(line, "+OK", 3) != 0) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen i_error("pop3-proxy(%s): "
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen "Remote returned invalid banner: %s",
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen client->common.virtual_user, line);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen client_destroy_internal_failure(client);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen /* send USER command */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen str = t_str_new(128);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen str_append(str, "USER ");
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen str_append(str, client->proxy_user);
beae08c3abc23434d15572ab3b059fbdf8efc2dfTimo Sirainen str_append(str, "\r\n");
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen (void)o_stream_send(output, str_data(str), str_len(str));
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen client->proxy_state++;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen case 1:
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (strncmp(line, "+OK", 3) != 0)
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen break;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen /* USER successful, send PASS */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen str = t_str_new(128);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen str_append(str, "PASS ");
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen str_append(str, client->proxy_password);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen str_append(str, "\r\n");
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen (void)o_stream_send(output, str_data(str),
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen str_len(str));
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen safe_memset(client->proxy_password, 0,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen strlen(client->proxy_password));
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen i_free(client->proxy_password);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen client->proxy_password = NULL;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen client->proxy_state++;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen case 2:
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen /* Login successful. Send this line to client. */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen (void)o_stream_send_str(client->output, line);
df1713bd29d29a3e3f3ebfdf05f929525825a7d3Timo Sirainen (void)o_stream_send(client->output, "\r\n", 2);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen login_proxy_detach(client->proxy, client->input,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen client->output);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen client->proxy = NULL;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen client->input = NULL;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen client->output = NULL;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen client->common.fd = -1;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen client_destroy(client,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen t_strdup_printf("proxy(%s): started",
df1713bd29d29a3e3f3ebfdf05f929525825a7d3Timo Sirainen client->common.virtual_user));
df1713bd29d29a3e3f3ebfdf05f929525825a7d3Timo Sirainen return;
df1713bd29d29a3e3f3ebfdf05f929525825a7d3Timo Sirainen }
cd2fc7dd28c3a2e3f82e8480eaf3ba7c4abc3614Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen /* Login failed. Send our own failure reply so client can't
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen figure out if user exists or not just by looking at the
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen reply string. */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen client_send_line(client, "-ERR "AUTH_FAILED_MSG);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen /* allow client input again */
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen i_assert(client->io == NULL);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen client->io = io_add(client->common.fd, IO_READ,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen client_input, client);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen login_proxy_free(client->proxy);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen client->proxy = NULL;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen if (client->proxy_password != NULL) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen safe_memset(client->proxy_password, 0,
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen strlen(client->proxy_password));
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen i_free(client->proxy_password);
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen client->proxy_password = NULL;
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen }
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen i_free(client->proxy_user);
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen client->proxy_user = NULL;
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen}
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen
c649139f889c02154fc9a153728b81619edb5663Timo Sirainenint pop3_proxy_new(struct pop3_client *client, const char *host,
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen unsigned int port, const char *user, const char *password)
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen{
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen i_assert(user != NULL);
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen if (password == NULL) {
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen i_error("proxy(%s): password not given",
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen client->common.virtual_user);
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen return -1;
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen }
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen client->proxy = login_proxy_new(&client->common, host, port,
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen proxy_input, client);
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen if (client->proxy == NULL)
c649139f889c02154fc9a153728b81619edb5663Timo Sirainen return -1;
53ec1ff2231d477db3103c51987fa9cb6033bc16Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen client->proxy_state = 0;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen client->proxy_user = i_strdup(user);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen client->proxy_password = i_strdup(password);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
53ec1ff2231d477db3103c51987fa9cb6033bc16Timo Sirainen /* disable input until authentication is finished */
53ec1ff2231d477db3103c51987fa9cb6033bc16Timo Sirainen if (client->io != NULL) {
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen io_remove(client->io);
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen client->io = NULL;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen }
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen return 0;
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen}
48566ca412a7cf3b42512fd0ec112744778e5da0Timo Sirainen