pop3-proxy.c revision 0c77590df05dc7ce340ea5f0d8d91534cea4f14e
bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (C) 2004 Timo Sirainen */
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi#include "common.h"
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi#include "ioloop.h"
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi#include "istream.h"
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi#include "ostream.h"
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi#include "base64.h"
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi#include "safe-memset.h"
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi#include "str.h"
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi#include "client.h"
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi#include "pop3-proxy.h"
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomistatic void proxy_input(struct istream *input, struct ostream *output,
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi void *context)
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi{
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi struct pop3_client *client = context;
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi string_t *auth, *str;
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi const char *line;
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi if (input == NULL) {
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi if (client->io != NULL) {
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi /* remote authentication failed, we're just
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi freeing the proxy */
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi return;
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi }
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi /* failed for some reason */
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi client_destroy_internal_failure(client);
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi return;
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi }
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi switch (i_stream_read(input)) {
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi case -2:
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi /* buffer full */
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi i_error("pop-proxy(%s): Remote input buffer full",
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi client->common.virtual_user);
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi client_destroy_internal_failure(client);
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi return;
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi case -1:
f6d5c9fbdac9af5c4d3f467f828dc6f056309d5eTimo Sirainen /* disconnected */
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi client_destroy(client, "Proxy: Remote disconnected");
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi return;
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi }
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi line = i_stream_next_line(input);
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi if (line == NULL)
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi return;
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi
df74b8f6ff432d9a26727669dfed9a15d77efb55Aki Tuomi if (client->proxy_user != NULL) {
/* this is a banner */
if (strncmp(line, "+OK ", 4) != 0) {
i_error("pop3-proxy(%s): "
"Remote returned invalid banner: %s",
client->common.virtual_user, line);
client_destroy_internal_failure(client);
return;
}
/* send AUTH command */
auth = t_str_new(128);
str_append_c(auth, '\0');
str_append(auth, client->proxy_user);
str_append_c(auth, '\0');
str_append(auth, client->proxy_password);
str = t_str_new(128);
str_append(str, "AUTH PLAIN ");
base64_encode(str_data(auth), str_len(auth), str);
str_append(str, "\r\n");
(void)o_stream_send(output, str_data(str), str_len(str));
safe_memset(client->proxy_password, 0,
strlen(client->proxy_password));
i_free(client->proxy_user);
i_free(client->proxy_password);
client->proxy_user = NULL;
client->proxy_password = NULL;
} else if (strncmp(line, "+OK ", 4) == 0) {
/* Login successful. Send this line to client. */
(void)o_stream_send_str(client->output, line);
(void)o_stream_send(client->output, "\r\n", 2);
login_proxy_detach(client->proxy, client->input,
client->output);
client->proxy = NULL;
client->input = NULL;
client->output = NULL;
client->common.fd = -1;
client_destroy(client, t_strconcat(
"Proxy: ", client->common.virtual_user, NULL));
} else {
/* Login failed. Send our own failure reply so client can't
figure out if user exists or not just by looking at the
reply string. */
client_send_line(client, "-ERR "AUTH_FAILED_MSG);
/* allow client input again */
i_assert(client->io == NULL);
client->io = io_add(client->common.fd, IO_READ,
client_input, client);
login_proxy_free(client->proxy);
client->proxy = NULL;
}
}
int pop3_proxy_new(struct pop3_client *client, const char *host,
unsigned int port, const char *user, const char *password)
{
i_assert(user != NULL);
if (password == NULL) {
i_error("proxy(%s): password not given",
client->common.virtual_user);
return -1;
}
client->proxy = login_proxy_new(&client->common, host, port,
proxy_input, client);
if (client->proxy == NULL)
return -1;
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);
client->io = NULL;
}
return 0;
}