Mercurial > dovecot > core-2.2
view src/pop3-login/pop3-proxy.c @ 9002:9d0037a997f4 HEAD
Initial commit for config rewrite.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Tue, 27 Jan 2009 18:21:53 -0500 |
parents | b9faf4db2a9f |
children | 21d4363a3cf7 |
line wrap: on
line source
/* Copyright (c) 2004-2009 Dovecot authors, see the included COPYING file */ #include "common.h" #include "ioloop.h" #include "istream.h" #include "ostream.h" #include "base64.h" #include "safe-memset.h" #include "str.h" #include "str-sanitize.h" #include "client.h" #include "pop3-proxy.h" #define PROXY_FAILURE_MSG "-ERR [IN-USE] "AUTH_TEMP_FAILED_MSG static void proxy_free_password(struct pop3_client *client) { if (client->proxy_password == NULL) return; safe_memset(client->proxy_password, 0, strlen(client->proxy_password)); i_free_and_null(client->proxy_password); } static void proxy_failed(struct pop3_client *client, bool send_line) { if (send_line) client_send_line(client, PROXY_FAILURE_MSG); login_proxy_free(&client->proxy); proxy_free_password(client); i_free_and_null(client->proxy_user); i_free_and_null(client->proxy_master_user); /* call this last - it may destroy the client */ client_auth_failed(client, TRUE); } static void get_plain_auth(struct pop3_client *client, string_t *dest) { string_t *str; str = t_str_new(128); str_append(str, client->proxy_user); str_append_c(str, '\0'); str_append(str, client->proxy_master_user); str_append_c(str, '\0'); str_append(str, client->proxy_password); base64_encode(str_data(str), str_len(str), dest); } static int proxy_input_line(struct pop3_client *client, struct ostream *output, const char *line) { string_t *str; i_assert(!client->destroyed); switch (client->proxy_state) { case 0: /* this is a banner */ if (strncmp(line, "+OK", 3) != 0) { client_syslog_err(&client->common, t_strdup_printf( "proxy: Remote returned invalid banner: %s", str_sanitize(line, 160))); proxy_failed(client, TRUE); return -1; } str = t_str_new(128); if (client->proxy_master_user == NULL) { /* send USER command */ str_append(str, "USER "); str_append(str, client->proxy_user); str_append(str, "\r\n"); } else { /* master user login - use AUTH PLAIN. */ str_append(str, "AUTH PLAIN\r\n"); } (void)o_stream_send(output, str_data(str), str_len(str)); client->proxy_state++; return 0; case 1: str = t_str_new(128); if (client->proxy_master_user == NULL) { if (strncmp(line, "+OK", 3) != 0) break; /* USER successful, send PASS */ str_append(str, "PASS "); str_append(str, client->proxy_password); str_append(str, "\r\n"); } else { if (*line != '+') break; /* AUTH successful, send the authentication data */ get_plain_auth(client, str); str_append(str, "\r\n"); } (void)o_stream_send(output, str_data(str), str_len(str)); proxy_free_password(client); client->proxy_state++; return 0; case 2: if (strncmp(line, "+OK", 3) != 0) break; /* Login successful. Send this line to client. */ line = t_strconcat(line, "\r\n", NULL); (void)o_stream_send_str(client->output, line); str = t_str_new(128); str_printfa(str, "proxy(%s): started proxying to %s:%u", client->common.virtual_user, login_proxy_get_host(client->proxy), login_proxy_get_port(client->proxy)); if (strcmp(client->common.virtual_user, client->proxy_user) != 0) { /* remote username is different, log it */ str_append_c(str, '/'); str_append(str, client->proxy_user); } if (client->proxy_master_user != NULL) { str_printfa(str, " (master %s)", client->proxy_master_user); } login_proxy_detach(client->proxy, client->common.input, client->output); client->proxy = NULL; client->common.input = NULL; client->output = NULL; client->common.fd = -1; client_destroy_success(client, str_c(str)); return 0; } /* Login failed. Pass through the error message to client (see imap-proxy code for potential problems with this) */ if (strncmp(line, "-ERR ", 5) != 0) client_send_line(client, "-ERR "AUTH_FAILED_MSG); else client_send_line(client, line); if (login_settings->verbose_auth) { str = t_str_new(128); str_printfa(str, "proxy(%s): Login failed to %s:%u", client->common.virtual_user, login_proxy_get_host(client->proxy), login_proxy_get_port(client->proxy)); if (strcmp(client->common.virtual_user, client->proxy_user) != 0) { /* remote username is different, log it */ str_append_c(str, '/'); str_append(str, client->proxy_user); } if (client->proxy_master_user != NULL) { str_printfa(str, " (master %s)", client->proxy_master_user); } str_append(str, ": "); if (strncmp(line, "-ERR ", 5) == 0) str_append(str, line + 5); else str_append(str, line); i_info("%s", str_c(str)); } proxy_failed(client, FALSE); return -1; } static void proxy_input(struct istream *input, struct ostream *output, struct pop3_client *client) { const char *line; if (input == NULL) { if (client->proxy == NULL) { /* we're just freeing the proxy */ return; } if (client->destroyed) { /* we came here from client_destroy() */ return; } /* failed for some reason, probably server disconnected */ proxy_failed(client, TRUE); return; } i_assert(!client->destroyed); switch (i_stream_read(input)) { case -2: client_syslog_err(&client->common, "proxy: Remote input buffer full"); proxy_failed(client, TRUE); return; case -1: client_syslog_err(&client->common, "proxy: Remote disconnected"); proxy_failed(client, TRUE); return; } while ((line = i_stream_next_line(input)) != NULL) { if (proxy_input_line(client, output, line) < 0) break; } } int pop3_proxy_new(struct pop3_client *client, const char *host, unsigned int port, const char *user, const char *master_user, const char *password) { i_assert(user != NULL); i_assert(!client->destroyed); if (password == NULL) { client_syslog_err(&client->common, "proxy: password not given"); client_send_line(client, PROXY_FAILURE_MSG); 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; } if (login_proxy_is_ourself(&client->common, host, port, user)) { client_syslog_err(&client->common, "Proxying loops to itself"); client_send_line(client, PROXY_FAILURE_MSG); return -1; } client->proxy = login_proxy_new(&client->common, host, port, proxy_input, client); if (client->proxy == NULL) { client_send_line(client, PROXY_FAILURE_MSG); return -1; } client->proxy_state = 0; client->proxy_user = i_strdup(user); client->proxy_master_user = i_strdup(master_user); client->proxy_password = i_strdup(password); /* disable input until authentication is finished */ if (client->io != NULL) io_remove(&client->io); return 0; }