dovecot-2.2: imap/pop3-login: Use libsasl for authenticating to ...

dovecot at dovecot.org dovecot at dovecot.org
Sun Jun 9 06:03:51 EEST 2013


details:   http://hg.dovecot.org/dovecot-2.2/rev/266101990d63
changeset: 16487:266101990d63
user:      Timo Sirainen <tss at iki.fi>
date:      Sun Jun 09 06:03:34 2013 +0300
description:
imap/pop3-login: Use libsasl for authenticating to remote IMAP/POP3 server.
Also passdb lookup can return "proxy_mech" extra field to specify which SASL
mechanism to use.

diffstat:

 src/imap-login/Makefile.am            |    1 +
 src/imap-login/client.h               |    1 -
 src/imap-login/imap-proxy.c           |  101 +++++++++++++++++-------
 src/login-common/Makefile.am          |    1 +
 src/login-common/client-common-auth.c |   23 +++++
 src/login-common/client-common.c      |    3 +
 src/login-common/client-common.h      |    4 +-
 src/login-common/main.c               |    3 +
 src/pop3-login/Makefile.am            |    1 +
 src/pop3-login/pop3-proxy.c           |  137 ++++++++++++++++++++++++---------
 10 files changed, 205 insertions(+), 70 deletions(-)

diffs (truncated from 560 to 300 lines):

diff -r 1cbff0a8a849 -r 266101990d63 src/imap-login/Makefile.am
--- a/src/imap-login/Makefile.am	Sun Jun 09 06:02:14 2013 +0300
+++ b/src/imap-login/Makefile.am	Sun Jun 09 06:03:34 2013 +0300
@@ -6,6 +6,7 @@
 	-I$(top_srcdir)/src/lib \
 	-I$(top_srcdir)/src/lib-settings \
 	-I$(top_srcdir)/src/lib-auth \
+	-I$(top_srcdir)/src/lib-sasl \
 	-I$(top_srcdir)/src/lib-imap \
 	-I$(top_srcdir)/src/lib-master \
 	-I$(top_srcdir)/src/login-common
diff -r 1cbff0a8a849 -r 266101990d63 src/imap-login/client.h
--- a/src/imap-login/client.h	Sun Jun 09 06:02:14 2013 +0300
+++ b/src/imap-login/client.h	Sun Jun 09 06:03:34 2013 +0300
@@ -19,7 +19,6 @@
 	unsigned int cmd_finished:1;
 	unsigned int proxy_sasl_ir:1;
 	unsigned int proxy_seen_banner:1;
-	unsigned int proxy_wait_auth_continue:1;
 	unsigned int skip_line:1;
 	unsigned int id_logged:1;
 	unsigned int client_ignores_capability_resp_code:1;
diff -r 1cbff0a8a849 -r 266101990d63 src/imap-login/imap-proxy.c
--- a/src/imap-login/imap-proxy.c	Sun Jun 09 06:02:14 2013 +0300
+++ b/src/imap-login/imap-proxy.c	Sun Jun 09 06:03:34 2013 +0300
@@ -9,6 +9,7 @@
 #include "str.h"
 #include "str-sanitize.h"
 #include "safe-memset.h"
+#include "sasl-client.h"
 #include "client.h"
 #include "client-authenticate.h"
 #include "imap-resp-code.h"
@@ -55,42 +56,55 @@
 	i_free_and_null(client->proxy_password);
 }
 
-static void get_plain_auth(struct client *client, string_t *dest)
+static int proxy_write_login(struct imap_client *client, string_t *str)
 {
-	string_t *str;
+	struct sasl_client_settings sasl_set;
+	const unsigned char *output;
+	unsigned int len;
+	const char *mech_name, *error;
 
-	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 void proxy_write_login(struct imap_client *client, string_t *str)
-{
 	str_append(str, "C CAPABILITY\r\n");
 
-	if (client->common.proxy_master_user == NULL) {
+	if (client->common.proxy_mech == NULL) {
 		/* logging in normally - use LOGIN command */
 		str_append(str, "L LOGIN ");
 		imap_append_string(str, client->common.proxy_user);
 		str_append_c(str, ' ');
 		imap_append_string(str, client->common.proxy_password);
+		str_append(str, "\r\n");
 
 		proxy_free_password(&client->common);
-	} else if (client->proxy_sasl_ir) {
-		/* master user login with SASL initial response support */
-		str_append(str, "L AUTHENTICATE PLAIN ");
-		get_plain_auth(&client->common, str);
-		proxy_free_password(&client->common);
-	} else {
-		/* master user login without SASL initial response */
-		str_append(str, "L AUTHENTICATE PLAIN");
-		client->proxy_wait_auth_continue = TRUE;
+		return 0;
+	}
+
+	i_assert(client->common.proxy_sasl_client == NULL);
+	memset(&sasl_set, 0, sizeof(sasl_set));
+	sasl_set.authid = client->common.proxy_user;
+	sasl_set.authzid = client->common.proxy_master_user;
+	sasl_set.password = client->common.proxy_password;
+	client->common.proxy_sasl_client =
+		sasl_client_new(client->common.proxy_mech, &sasl_set);
+	mech_name = sasl_client_mech_get_name(client->common.proxy_mech);
+
+	str_append(str, "L AUTHENTICATE ");
+	str_append(str, mech_name);
+	if (client->proxy_sasl_ir) {
+		if (sasl_client_output(client->common.proxy_sasl_client,
+				       &output, &len, &error) < 0) {
+			client_log_err(&client->common, t_strdup_printf(
+				"proxy: SASL mechanism %s init failed: %s",
+				mech_name, error));
+			return -1;
+		}
+		str_append_c(str, ' ');
+		if (len == 0)
+			str_append_c(str, '=');
+		else
+			base64_encode(output, len, str);
 	}
 	str_append(str, "\r\n");
+	proxy_free_password(&client->common);
+	return 0;
 }
 
 static int proxy_input_banner(struct imap_client *client,
@@ -126,7 +140,8 @@
 		}
 		str_append(str, "S STARTTLS\r\n");
 	} else {
-		proxy_write_login(client, str);
+		if (proxy_write_login(client, str) < 0)
+			return -1;
 	}
 
 	o_stream_nsend(output, str_data(str), str_len(str));
@@ -173,6 +188,10 @@
 	struct imap_client *imap_client = (struct imap_client *)client;
 	struct ostream *output;
 	string_t *str;
+	const unsigned char *data;
+	unsigned int data_len;
+	const char *error;
+	int ret;
 
 	i_assert(!client->destroyed);
 
@@ -188,17 +207,37 @@
 		return 0;
 	} else if (*line == '+') {
 		/* AUTHENTICATE started. finish it. */
-		if (!imap_client->proxy_wait_auth_continue) {
+		if (client->proxy_sasl_client == NULL) {
 			/* used literals with LOGIN command, just ignore. */
 			return 0;
 		}
 		client->proxy_state = IMAP_PROXY_STATE_AUTH_CONTINUE;
-		imap_client->proxy_wait_auth_continue = FALSE;
 
 		str = t_str_new(128);
-		get_plain_auth(client, str);
+		if (line[1] != ' ' ||
+		    base64_decode(line+2, strlen(line+2), NULL, str) < 0) {
+			client_log_err(client,
+				"proxy: Server sent invalid base64 data in AUTHENTICATE response");
+			client_proxy_failed(client, TRUE);
+			return -1;
+		}
+		ret = sasl_client_input(client->proxy_sasl_client,
+					str_data(str), str_len(str), &error);
+		if (ret == 0) {
+			ret = sasl_client_output(client->proxy_sasl_client,
+						 &data, &data_len, &error);
+		}
+		if (ret < 0) {
+			client_log_err(client, t_strdup_printf(
+				"proxy: Server sent invalid authentication data: %s",
+				error));
+			client_proxy_failed(client, TRUE);
+			return -1;
+		}
+
+		str_truncate(str, 0);
+		base64_encode(data, data_len, str);
 		str_append(str, "\r\n");
-		proxy_free_password(client);
 
 		o_stream_nsend(output, str_data(str), str_len(str));
 		return 0;
@@ -220,7 +259,10 @@
 		/* i/ostreams changed. */
 		output = login_proxy_get_ostream(client->login_proxy);
 		str = t_str_new(128);
-		proxy_write_login(imap_client, str);
+		if (proxy_write_login(imap_client, str) < 0) {
+			client_proxy_failed(client, TRUE);
+			return -1;
+		}
 		o_stream_nsend(output, str_data(str), str_len(str));
 		return 1;
 	} else if (strncmp(line, "L OK ", 5) == 0) {
@@ -305,7 +347,6 @@
 
 	imap_client->proxy_sasl_ir = FALSE;
 	imap_client->proxy_seen_banner = FALSE;
-	imap_client->proxy_wait_auth_continue = FALSE;
 	client->proxy_state = IMAP_PROXY_STATE_NONE;
 }
 
diff -r 1cbff0a8a849 -r 266101990d63 src/login-common/Makefile.am
--- a/src/login-common/Makefile.am	Sun Jun 09 06:02:14 2013 +0300
+++ b/src/login-common/Makefile.am	Sun Jun 09 06:03:34 2013 +0300
@@ -4,6 +4,7 @@
 	-I$(top_srcdir)/src/lib \
 	-I$(top_srcdir)/src/lib-settings \
 	-I$(top_srcdir)/src/lib-auth \
+	-I$(top_srcdir)/src/lib-sasl \
 	-I$(top_srcdir)/src/lib-master \
 	-I$(top_srcdir)/src/lib-ssl-iostream \
 	-I$(top_srcdir)/src/lib-mail \
diff -r 1cbff0a8a849 -r 266101990d63 src/login-common/client-common-auth.c
--- a/src/login-common/client-common-auth.c	Sun Jun 09 06:02:14 2013 +0300
+++ b/src/login-common/client-common-auth.c	Sun Jun 09 06:03:34 2013 +0300
@@ -9,6 +9,7 @@
 #include "time-util.h"
 #include "login-proxy.h"
 #include "auth-client.h"
+#include "sasl-client.h"
 #include "master-service-ssl-settings.h"
 #include "client-common.h"
 
@@ -104,6 +105,8 @@
 			reply_r->proxy_timeout_msecs = 1000*atoi(value);
 		else if (strcmp(key, "proxy_refresh") == 0)
 			reply_r->proxy_refresh_secs = atoi(value);
+		else if (strcmp(key, "proxy_mech") == 0)
+			reply_r->proxy_mech = value;
 		else if (strcmp(key, "master") == 0)
 			reply_r->master_user = value;
 		else if (strcmp(key, "ssl") == 0) {
@@ -198,6 +201,8 @@
 		client_proxy_error(client, PROXY_FAILURE_MSG);
 	}
 
+	if (client->proxy_sasl_client != NULL)
+		sasl_client_free(&client->proxy_sasl_client);
 	login_proxy_free(&client->login_proxy);
 	proxy_free_password(client);
 	i_free_and_null(client->proxy_user);
@@ -270,10 +275,13 @@
 		       const struct client_auth_reply *reply)
 {
 	struct login_proxy_settings proxy_set;
+	const struct sasl_client_mech *sasl_mech = NULL;
 
 	i_assert(reply->destuser != NULL);
 	i_assert(!client->destroyed);
+	i_assert(client->proxy_sasl_client == NULL);
 
+	client->proxy_mech = NULL;
 	client->v.proxy_reset(client);
 
 	if (reply->password == NULL) {
@@ -287,6 +295,20 @@
 		return -1;
 	}
 
+	if (reply->proxy_mech != NULL) {
+		sasl_mech = sasl_client_mech_find(reply->proxy_mech);
+		if (sasl_mech == NULL) {
+			client_log_err(client, t_strdup_printf(
+				"proxy: Unsupported SASL mechanism %s",
+				reply->proxy_mech));
+			client_proxy_error(client, PROXY_FAILURE_MSG);
+			return -1;
+		}
+	} else if (reply->master_user != NULL) {
+		/* have to use PLAIN authentication with master user logins */
+		sasl_mech = &sasl_client_mech_plain;
+	}
+
 	i_assert(client->refcount > 1);
 
 	if (client->destroyed) {
@@ -318,6 +340,7 @@
 		return -1;
 	}
 
+	client->proxy_mech = sasl_mech;
 	client->proxy_user = i_strdup(reply->destuser);
 	client->proxy_master_user = i_strdup(reply->master_user);
 	client->proxy_password = i_strdup(reply->password);
diff -r 1cbff0a8a849 -r 266101990d63 src/login-common/client-common.c
--- a/src/login-common/client-common.c	Sun Jun 09 06:02:14 2013 +0300
+++ b/src/login-common/client-common.c	Sun Jun 09 06:03:34 2013 +0300
@@ -18,6 +18,7 @@
 #include "master-service-ssl-settings.h"
 #include "master-auth.h"
 #include "auth-client.h"
+#include "sasl-client.h"
 #include "login-proxy.h"
 #include "ssl-proxy.h"
 #include "client-common.h"
@@ -209,6 +210,8 @@
 		i_free_and_null(client->proxy_password);
 	}
 
+	if (client->proxy_sasl_client != NULL)
+		sasl_client_free(&client->proxy_sasl_client);
 	if (client->login_proxy != NULL)
 		login_proxy_free(&client->login_proxy);
 	if (client->v.destroy != NULL)
diff -r 1cbff0a8a849 -r 266101990d63 src/login-common/client-common.h
--- a/src/login-common/client-common.h	Sun Jun 09 06:02:14 2013 +0300


More information about the dovecot-cvs mailing list