dovecot-1.2: imap/pop3 proxy: Support SSL/TLS connections to rem...
dovecot at dovecot.org
dovecot at dovecot.org
Wed Apr 29 05:31:46 EEST 2009
details: http://hg.dovecot.org/dovecot-1.2/rev/f43bebab3dac
changeset: 8985:f43bebab3dac
user: Timo Sirainen <tss at iki.fi>
date: Tue Apr 28 22:31:40 2009 -0400
description:
imap/pop3 proxy: Support SSL/TLS connections to remote servers.
passdb can return ssl=yes, ssl=any-cert and starttls options.
diffstat:
15 files changed, 538 insertions(+), 232 deletions(-)
src/imap-login/client-authenticate.c | 60 +++++----
src/imap-login/client.c | 7 -
src/imap-login/client.h | 3
src/imap-login/imap-proxy.c | 119 ++++++++++++------
src/imap-login/imap-proxy.h | 2
src/login-common/login-proxy.c | 139 +++++++++++++++++----
src/login-common/login-proxy.h | 32 +++-
src/login-common/ssl-proxy-openssl.c | 222 ++++++++++++++++++++++------------
src/login-common/ssl-proxy.c | 9 +
src/login-common/ssl-proxy.h | 10 +
src/pop3-login/client-authenticate.c | 58 +++++---
src/pop3-login/client.c | 7 -
src/pop3-login/client.h | 9 +
src/pop3-login/pop3-proxy.c | 91 +++++++++----
src/pop3-login/pop3-proxy.h | 2
diffs (truncated from 1287 to 300 lines):
diff -r e7bfb3c134f9 -r f43bebab3dac src/imap-login/client-authenticate.c
--- a/src/imap-login/client-authenticate.c Tue Apr 28 19:57:10 2009 -0400
+++ b/src/imap-login/client-authenticate.c Tue Apr 28 22:31:40 2009 -0400
@@ -124,6 +124,8 @@ static bool client_handle_args(struct im
{
const char *reason = NULL, *host = NULL, *destuser = NULL, *pass = NULL;
const char *master_user = NULL;
+ const char *key, *value, *p;
+ enum login_proxy_ssl_flags ssl_flags = 0;
string_t *reply;
unsigned int port = 143;
bool proxy = FALSE, temp = FALSE, nologin = !success;
@@ -131,33 +133,49 @@ static bool client_handle_args(struct im
*nodelay_r = FALSE;
for (; *args != NULL; args++) {
- if (strcmp(*args, "nologin") == 0)
+ p = strchr(*args, '=');
+ if (p == NULL) {
+ key = *args;
+ value = "";
+ } else {
+ key = t_strdup_until(*args, p);
+ value = p + 1;
+ }
+ if (strcmp(key, "nologin") == 0)
nologin = TRUE;
- else if (strcmp(*args, "nodelay") == 0)
+ else if (strcmp(key, "nodelay") == 0)
*nodelay_r = TRUE;
- else if (strcmp(*args, "proxy") == 0)
+ else if (strcmp(key, "proxy") == 0)
proxy = TRUE;
- else if (strcmp(*args, "temp") == 0)
+ else if (strcmp(key, "temp") == 0)
temp = TRUE;
- else if (strcmp(*args, "authz") == 0)
+ else if (strcmp(key, "authz") == 0)
authz_failure = TRUE;
- else if (strncmp(*args, "reason=", 7) == 0)
- reason = *args + 7;
- else if (strncmp(*args, "host=", 5) == 0)
- host = *args + 5;
- else if (strncmp(*args, "port=", 5) == 0)
- port = atoi(*args + 5);
- else if (strncmp(*args, "destuser=", 9) == 0)
- destuser = *args + 9;
- else if (strncmp(*args, "pass=", 5) == 0)
- pass = *args + 5;
- else if (strncmp(*args, "master=", 7) == 0)
- master_user = *args + 7;
- else if (strncmp(*args, "user=", 5) == 0) {
+ else if (strcmp(key, "reason") == 0)
+ reason = value + 7;
+ else if (strcmp(key, "host") == 0)
+ host = value;
+ else if (strcmp(key, "port") == 0)
+ port = atoi(value);
+ else if (strcmp(key, "destuser") == 0)
+ destuser = value;
+ else if (strcmp(key, "pass") == 0)
+ pass = value;
+ else if (strcmp(key, "master") == 0)
+ master_user = value;
+ else if (strcmp(key, "ssl") == 0) {
+ if (strcmp(value, "yes") == 0)
+ ssl_flags |= PROXY_SSL_FLAG_YES;
+ else if (strcmp(value, "any-cert") == 0) {
+ ssl_flags |= PROXY_SSL_FLAG_YES |
+ PROXY_SSL_FLAG_ANY_CERT;
+ }
+ } else if (strcmp(key, "starttls") == 0) {
+ ssl_flags |= PROXY_SSL_FLAG_STARTTLS;
+ } else if (strcmp(key, "user") == 0) {
/* already handled in login-common */
} else if (auth_debug) {
- i_info("Ignoring unknown passdb extra field: %s",
- *args);
+ i_info("Ignoring unknown passdb extra field: %s", key);
}
}
@@ -173,7 +191,7 @@ static bool client_handle_args(struct im
if (!success)
return FALSE;
if (imap_proxy_new(client, host, port, destuser, master_user,
- pass) < 0)
+ pass, ssl_flags) < 0)
client_auth_failed(client, TRUE);
return TRUE;
}
diff -r e7bfb3c134f9 -r f43bebab3dac src/imap-login/client.c
--- a/src/imap-login/client.c Tue Apr 28 19:57:10 2009 -0400
+++ b/src/imap-login/client.c Tue Apr 28 22:31:40 2009 -0400
@@ -556,10 +556,11 @@ void client_destroy(struct imap_client *
if (client->output != NULL)
o_stream_close(client->output);
- if (client->common.master_tag != 0)
+ if (client->common.master_tag != 0) {
+ i_assert(client->common.auth_request == NULL);
+ i_assert(client->common.authenticating);
master_request_abort(&client->common);
-
- if (client->common.auth_request != NULL) {
+ } else if (client->common.auth_request != NULL) {
i_assert(client->common.authenticating);
sasl_server_auth_client_error(&client->common, NULL);
} else {
diff -r e7bfb3c134f9 -r f43bebab3dac src/imap-login/client.h
--- a/src/imap-login/client.h Tue Apr 28 19:57:10 2009 -0400
+++ b/src/imap-login/client.h Tue Apr 28 22:31:40 2009 -0400
@@ -30,7 +30,8 @@ struct imap_client {
unsigned int login_success:1;
unsigned int cmd_finished:1;
- unsigned int proxy_login_sent:1;
+ unsigned int proxy_sasl_ir:1;
+ unsigned int proxy_seen_banner:1;
unsigned int skip_line:1;
unsigned int input_blocked:1;
unsigned int destroyed:1;
diff -r e7bfb3c134f9 -r f43bebab3dac src/imap-login/imap-proxy.c
--- a/src/imap-login/imap-proxy.c Tue Apr 28 19:57:10 2009 -0400
+++ b/src/imap-login/imap-proxy.c Tue Apr 28 22:31:40 2009 -0400
@@ -136,25 +136,8 @@ client_send_capability_if_needed(struct
str_printfa(str, "* CAPABILITY %s\r\n", capability);
}
-static int proxy_input_banner(struct imap_client *client,
- struct ostream *output, const char *line)
-{
- const char *const *capabilities = NULL;
- string_t *str;
-
- if (strncmp(line, "* OK ", 5) != 0) {
- client_syslog_err(&client->common, t_strdup_printf(
- "proxy: Remote returned invalid banner: %s",
- str_sanitize(line, 160)));
- return -1;
- }
-
- str = t_str_new(128);
- if (strncmp(line + 5, "[CAPABILITY ", 12) == 0) {
- capabilities = t_strsplit(t_strcut(line + 5 + 12, ']'), " ");
- if (str_array_icase_find(capabilities, "ID"))
- proxy_write_id(client, str);
- }
+static void proxy_write_login(struct imap_client *client, string_t *str)
+{
if (client->capability_command_used)
str_append(str, "C CAPABILITY\r\n");
@@ -166,8 +149,7 @@ static int proxy_input_banner(struct ima
imap_quote_append_string(str, client->proxy_password, FALSE);
proxy_free_password(client);
- } else if (capabilities != NULL &&
- str_array_icase_find(capabilities, "SASL-IR")) {
+ } else if (client->proxy_sasl_ir) {
/* master user login with SASL initial response support */
str_append(str, "L AUTHENTICATE PLAIN ");
get_plain_auth(client, str);
@@ -177,21 +159,60 @@ static int proxy_input_banner(struct ima
str_append(str, "L AUTHENTICATE PLAIN");
}
str_append(str, "\r\n");
+}
+
+static int proxy_input_banner(struct imap_client *client,
+ struct ostream *output, const char *line)
+{
+ enum login_proxy_ssl_flags ssl_flags;
+ const char *const *capabilities = NULL;
+ string_t *str;
+
+ if (strncmp(line, "* OK ", 5) != 0) {
+ client_syslog_err(&client->common, t_strdup_printf(
+ "proxy: Remote returned invalid banner: %s",
+ str_sanitize(line, 160)));
+ return -1;
+ }
+
+ str = t_str_new(128);
+ if (strncmp(line + 5, "[CAPABILITY ", 12) == 0) {
+ capabilities = t_strsplit(t_strcut(line + 5 + 12, ']'), " ");
+ if (str_array_icase_find(capabilities, "ID"))
+ proxy_write_id(client, str);
+ if (str_array_icase_find(capabilities, "SASL-IR"))
+ client->proxy_sasl_ir = TRUE;
+ }
+
+ ssl_flags = login_proxy_get_ssl_flags(client->proxy);
+ if ((ssl_flags & PROXY_SSL_FLAG_STARTTLS) != 0) {
+ if (capabilities != NULL &&
+ !str_array_icase_find(capabilities, "STARTTLS")) {
+ client_syslog_err(&client->common,
+ "proxy: Remote doesn't support STARTTLS");
+ return -1;
+ }
+ str_append(str, "S STARTTLS\r\n");
+ } else {
+ proxy_write_login(client, str);
+ }
+
(void)o_stream_send(output, str_data(str), str_len(str));
- client->proxy_login_sent = TRUE;
return 0;
}
-static int proxy_input_line(struct imap_client *client,
- struct ostream *output, const char *line)
-{
+static int proxy_input_line(struct imap_client *client, const char *line)
+{
+ struct ostream *output;
const char *capability;
string_t *str;
i_assert(!client->destroyed);
- if (!client->proxy_login_sent) {
+ output = login_proxy_get_ostream(client->proxy);
+ if (!client->proxy_seen_banner) {
/* this is a banner */
+ client->proxy_seen_banner = TRUE;
if (proxy_input_banner(client, output, line) < 0) {
proxy_failed(client, TRUE);
return -1;
@@ -206,6 +227,26 @@ static int proxy_input_line(struct imap_
(void)o_stream_send(output, str_data(str), str_len(str));
return 0;
+ } else if (strncmp(line, "S ", 2) == 0) {
+ if (strncmp(line, "S OK ", 5) != 0) {
+ /* STARTTLS failed */
+ client_syslog_err(&client->common, t_strdup_printf(
+ "proxy: Remote STARTTLS failed: %s",
+ str_sanitize(line + 5, 160)));
+ proxy_failed(client, TRUE);
+ return -1;
+ }
+ /* STARTTLS successful, begin TLS negotiation. */
+ if (login_proxy_starttls(client->proxy) < 0) {
+ proxy_failed(client, TRUE);
+ return -1;
+ }
+ /* i/ostreams changed. */
+ output = login_proxy_get_ostream(client->proxy);
+ str = t_str_new(128);
+ proxy_write_login(client, str);
+ (void)o_stream_send(output, str_data(str), str_len(str));
+ return 1;
} else if (strncmp(line, "L OK ", 5) == 0) {
/* Login successful. Send this line to client. */
capability = client->proxy_backend_capability;
@@ -306,17 +347,18 @@ static int proxy_input_line(struct imap_
}
}
-static void proxy_input(struct istream *input, struct ostream *output,
- struct imap_client *client)
-{
+static void proxy_input(struct imap_client *client)
+{
+ struct istream *input;
const char *line;
+ if (client->proxy == NULL) {
+ /* we're just freeing the proxy */
+ return;
+ }
+
+ input = login_proxy_get_istream(client->proxy);
if (input == NULL) {
- if (client->proxy == NULL) {
- /* we're just freeing the proxy */
- return;
- }
-
if (client->destroyed) {
/* we came here from client_destroy() */
return;
@@ -343,14 +385,14 @@ static void proxy_input(struct istream *
}
while ((line = i_stream_next_line(input)) != NULL) {
- if (proxy_input_line(client, output, line) != 0)
+ if (proxy_input_line(client, line) != 0)
break;
}
}
int imap_proxy_new(struct imap_client *client, const char *host,
unsigned int port, const char *user, const char *master_user,
- const char *password)
+ const char *password, enum login_proxy_ssl_flags ssl_flags)
{
i_assert(user != NULL);
i_assert(!client->destroyed);
More information about the dovecot-cvs
mailing list