imap-proxy.c revision feb665db52583259a1f42037c6e8a22852aa8889
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen/* Copyright (C) 2004 Timo Sirainen */
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen#include "common.h"
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen#include "ioloop.h"
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen#include "istream.h"
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen#include "ostream.h"
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen#include "str.h"
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen#include "safe-memset.h"
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen#include "client.h"
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen#include "imap-quote.h"
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen#include "imap-proxy.h"
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainenstatic int proxy_input_line(struct imap_client *client,
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen struct ostream *output, const char *line)
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen{
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen string_t *str;
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen i_assert(!client->destroyed);
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen if (!client->proxy_login_sent) {
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen /* this is a banner */
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen if (strncmp(line, "* OK ", 5) != 0) {
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen i_error("imap-proxy(%s): "
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen "Remote returned invalid banner: %s",
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen client->common.virtual_user, line);
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen client_destroy_internal_failure(client);
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen return -1;
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen }
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen /* send LOGIN command */
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen str = t_str_new(128);
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen str_append(str, "P LOGIN ");
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen imap_quote_append_string(str, client->proxy_user, FALSE);
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen str_append_c(str, ' ');
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen imap_quote_append_string(str, client->proxy_password, FALSE);
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen str_append(str, "\r\n");
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen (void)o_stream_send(output, str_data(str), str_len(str));
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen safe_memset(client->proxy_password, 0,
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen strlen(client->proxy_password));
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen i_free(client->proxy_password);
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen client->proxy_password = NULL;
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen client->proxy_login_sent = TRUE;
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen return 0;
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen } else if (strncmp(line, "P OK ", 5) == 0) {
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen /* Login successful. Send this line to client. */
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen (void)o_stream_send_str(client->output, client->cmd_tag);
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen (void)o_stream_send_str(client->output, line + 1);
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen (void)o_stream_send(client->output, "\r\n", 2);
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen (void)client_skip_line(client);
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen login_proxy_detach(client->proxy, client->input,
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen client->output);
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen client->proxy = NULL;
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen client->input = NULL;
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen client->output = NULL;
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen client->common.fd = -1;
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen client_destroy(client, t_strdup_printf("proxy(%s): started",
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen client->common.virtual_user));
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen return -1;
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen } else if (strncmp(line, "P ", 2) == 0) {
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen /* Login failed. Send our own failure reply so client can't
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen figure out if user exists or not just by looking at the
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen reply string. */
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen client_send_tagline(client, "NO "AUTH_FAILED_MSG);
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen /* allow client input again */
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen i_assert(client->io == NULL);
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen client->io = io_add(client->common.fd, IO_READ,
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen client_input, client);
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen login_proxy_free(client->proxy);
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen client->proxy = NULL;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen i_free(client->proxy_user);
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen client->proxy_user = NULL;
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen client_unref(client);
25ec868bd8b5375e1c1c4c3331d761667ddfe26cTimo Sirainen return -1;
25ec868bd8b5375e1c1c4c3331d761667ddfe26cTimo Sirainen } else {
25ec868bd8b5375e1c1c4c3331d761667ddfe26cTimo Sirainen /* probably some untagged reply */
25ec868bd8b5375e1c1c4c3331d761667ddfe26cTimo Sirainen return 0;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen }
25ec868bd8b5375e1c1c4c3331d761667ddfe26cTimo Sirainen}
25ec868bd8b5375e1c1c4c3331d761667ddfe26cTimo Sirainen
25ec868bd8b5375e1c1c4c3331d761667ddfe26cTimo Sirainenstatic void proxy_input(struct istream *input, struct ostream *output,
25ec868bd8b5375e1c1c4c3331d761667ddfe26cTimo Sirainen void *context)
25ec868bd8b5375e1c1c4c3331d761667ddfe26cTimo Sirainen{
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen struct imap_client *client = context;
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen const char *line;
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen if (input == NULL) {
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen if (client->io != NULL) {
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen /* remote authentication failed, we're just
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen freeing the proxy */
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen return;
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen }
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen /* failed for some reason, probably server disconnected */
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen client_send_line(client, "* BYE Temporary login failure.");
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen client_destroy(client, NULL);
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen return;
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen }
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen switch (i_stream_read(input)) {
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen case -2:
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen /* buffer full */
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen i_error("imap-proxy(%s): Remote input buffer full",
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen client->common.virtual_user);
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen client_destroy_internal_failure(client);
c076ad69e28e7d41af83ada84e12019793ffcfa2Timo Sirainen return;
2686ef87921233609d1d8ec8dee2883facc2c5ebTimo Sirainen case -1:
/* disconnected */
client_destroy(client, "Proxy: Remote disconnected");
return;
}
while ((line = i_stream_next_line(input)) != NULL) {
if (proxy_input_line(client, output, line) < 0)
break;
}
}
int imap_proxy_new(struct imap_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_ref(client);
client->proxy = login_proxy_new(&client->common, host, port,
proxy_input, client);
if (client->proxy == NULL)
return -1;
client->proxy_login_sent = FALSE;
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;
}