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