imap-proxy.c revision 00b2227d6ff65629707670b7b8dfd236fced8293
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (C) 2004 Timo Sirainen */
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen#include "common.h"
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen#include "ioloop.h"
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen#include "istream.h"
5601c23c0d59376dfda22c7eb807c9e1a0870426Timo Sirainen#include "ostream.h"
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen#include "str.h"
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen#include "safe-memset.h"
e62f6437a4ff01d692a5a61369fe4168d69191edTimo Sirainen#include "client.h"
c4b376dd6e0c423006d7ac83a39253bcaf8e7c47Timo Sirainen#include "imap-quote.h"
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen#include "imap-proxy.h"
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainenstatic int proxy_input_line(struct imap_client *client,
4ae81f8f7aad06aad2f570535cad6e40aaec2b28Timo Sirainen struct ostream *output, const char *line)
4ae81f8f7aad06aad2f570535cad6e40aaec2b28Timo Sirainen{
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen string_t *str;
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen if (client->proxy_user != NULL) {
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen /* this is a banner */
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (strncmp(line, "* OK ", 5) != 0) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen i_error("imap-proxy(%s): "
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen "Remote returned invalid banner: %s",
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen client->common.virtual_user, line);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen client_destroy_internal_failure(client);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return -1;
e62f6437a4ff01d692a5a61369fe4168d69191edTimo Sirainen }
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen /* send LOGIN command */
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen str = t_str_new(128);
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen str_append(str, "P LOGIN ");
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen imap_quote_append_string(str, client->proxy_user, FALSE);
12055678401e913f4be130fa41b22fbeb626cc7eTimo Sirainen str_append_c(str, ' ');
12055678401e913f4be130fa41b22fbeb626cc7eTimo Sirainen imap_quote_append_string(str, client->proxy_password, FALSE);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen str_append(str, "\r\n");
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen (void)o_stream_send(output, str_data(str), str_len(str));
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen safe_memset(client->proxy_password, 0,
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen strlen(client->proxy_password));
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen i_free(client->proxy_user);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen i_free(client->proxy_password);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen client->proxy_user = NULL;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen client->proxy_password = NULL;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return 0;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen } else if (strncmp(line, "P OK ", 5) == 0) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen /* Login successful. Send this line to client. */
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen (void)o_stream_send_str(client->output, client->cmd_tag);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen (void)o_stream_send_str(client->output, line + 1);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen (void)o_stream_send(client->output, "\r\n", 2);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
4ae81f8f7aad06aad2f570535cad6e40aaec2b28Timo Sirainen (void)client_skip_line(client);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen login_proxy_detach(client->proxy, client->input,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen client->output);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen client->proxy = NULL;
4ae81f8f7aad06aad2f570535cad6e40aaec2b28Timo Sirainen client->input = NULL;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen client->output = NULL;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen client->common.fd = -1;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen client_destroy(client, t_strdup_printf("proxy(%s): started",
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen client->common.virtual_user));
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return -1;
4ae81f8f7aad06aad2f570535cad6e40aaec2b28Timo Sirainen } else if (strncmp(line, "P ", 2) == 0) {
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen /* Login failed. Send our own failure reply so client can't
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen figure out if user exists or not just by looking at the
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen reply string. */
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen client_send_tagline(client, "NO "AUTH_FAILED_MSG);
4ae81f8f7aad06aad2f570535cad6e40aaec2b28Timo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen /* allow client input again */
4ae81f8f7aad06aad2f570535cad6e40aaec2b28Timo Sirainen i_assert(client->io == NULL);
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen client->io = io_add(client->common.fd, IO_READ,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen client_input, client);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen login_proxy_free(client->proxy);
4ae81f8f7aad06aad2f570535cad6e40aaec2b28Timo Sirainen client->proxy = NULL;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return -1;
4ae81f8f7aad06aad2f570535cad6e40aaec2b28Timo Sirainen } else {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen /* probably some untagged reply */
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return 0;
4ae81f8f7aad06aad2f570535cad6e40aaec2b28Timo Sirainen }
4ae81f8f7aad06aad2f570535cad6e40aaec2b28Timo Sirainen}
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
4ae81f8f7aad06aad2f570535cad6e40aaec2b28Timo Sirainenstatic void proxy_input(struct istream *input, struct ostream *output,
4ae81f8f7aad06aad2f570535cad6e40aaec2b28Timo Sirainen void *context)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen{
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen struct imap_client *client = context;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen const char *line;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (input == NULL) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (client->io != NULL) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen /* remote authentication failed, we're just
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen freeing the proxy */
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen }
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen /* failed for some reason */
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen client_destroy_internal_failure(client);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen return;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen }
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen switch (i_stream_read(input)) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen case -2:
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen /* buffer full */
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen i_error("imap-proxy(%s): Remote input buffer full",
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen client->common.virtual_user);
37cd04fc1d01c4a7140ffcb514e15cee1e97986aTimo Sirainen client_destroy_internal_failure(client);
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen return;
ebfbf5d78dcf95e8b176429f4b5b0694eb4e17d5Timo Sirainen case -1:
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen /* disconnected */
ac383c437b1ccb9420cae6b4c4b03af3c8019e02Timo Sirainen client_destroy(client, "Proxy: Remote disconnected");
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen return;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen }
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen while ((line = i_stream_next_line(input)) != NULL) {
37cd04fc1d01c4a7140ffcb514e15cee1e97986aTimo Sirainen if (proxy_input_line(client, output, line) < 0)
37cd04fc1d01c4a7140ffcb514e15cee1e97986aTimo Sirainen break;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen }
37cd04fc1d01c4a7140ffcb514e15cee1e97986aTimo Sirainen}
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenint imap_proxy_new(struct imap_client *client, const char *host,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen unsigned int port, const char *user, const char *password)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen{
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen i_assert(user != NULL);
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen
0df9428baed48afaff90b4d4f03792d2fd756a43Timo Sirainen if (password == NULL) {
ac383c437b1ccb9420cae6b4c4b03af3c8019e02Timo Sirainen i_error("proxy(%s): password not given",
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen client->common.virtual_user);
ac383c437b1ccb9420cae6b4c4b03af3c8019e02Timo Sirainen return -1;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
ac383c437b1ccb9420cae6b4c4b03af3c8019e02Timo Sirainen
ebfbf5d78dcf95e8b176429f4b5b0694eb4e17d5Timo Sirainen client->proxy = login_proxy_new(&client->common, host, port,
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen proxy_input, client);
1b0cfbf3cc77a670b92fff5c30f7b1eb17a63ab1Timo Sirainen if (client->proxy == NULL)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen return -1;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen client->proxy_user = i_strdup(user);
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen client->proxy_password = i_strdup(password);
4ae81f8f7aad06aad2f570535cad6e40aaec2b28Timo Sirainen
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen /* disable input until authentication is finished */
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (client->io != NULL) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen io_remove(client->io);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen client->io = NULL;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen }
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen
74ab5ea66c0c4b388f1c774ae6a47ab94f1b4f18Timo Sirainen return 0;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen}
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen