dovecot-2.2-pigeonhole: managesieve-login: Changed proxy to bett...

pigeonhole at rename-it.nl pigeonhole at rename-it.nl
Fri May 22 00:11:55 UTC 2015


details:   http://hg.rename-it.nl/dovecot-2.2-pigeonhole/rev/3df7e50f986d
changeset: 2076:3df7e50f986d
user:      Stephan Bosch <stephan at rename-it.nl>
date:      Fri May 22 02:11:03 2015 +0200
description:
managesieve-login: Changed proxy to better match imap equivalent.
It now uses dsasl-client, so it should now be possible to use SASL mechanisms other than PLAIN.
Cleaned up the code a bit.

diffstat:

 src/managesieve-login/managesieve-proxy.c |  253 ++++++++++++++++++++++-------
 1 files changed, 188 insertions(+), 65 deletions(-)

diffs (truncated from 424 to 300 lines):

diff -r d08c11c6f618 -r 3df7e50f986d src/managesieve-login/managesieve-proxy.c
--- a/src/managesieve-login/managesieve-proxy.c	Fri May 22 02:02:38 2015 +0200
+++ b/src/managesieve-login/managesieve-proxy.c	Fri May 22 02:11:03 2015 +0200
@@ -11,6 +11,7 @@
 #include "safe-memset.h"
 #include "buffer.h"
 #include "base64.h"
+#include "dsasl-client.h"
 
 #include "client.h"
 #include "client-authenticate.h"
@@ -20,11 +21,11 @@
 #include "managesieve-parser.h"
 
 enum {
-	PROXY_STATE_INITIAL,
-	PROXY_STATE_TLS_START,
-	PROXY_STATE_TLS_READY,
-	PROXY_STATE_XCLIENT,
-	PROXY_STATE_AUTHENTICATE,
+	MSIEVE_PROXY_STATE_NONE,
+	MSIEVE_PROXY_STATE_TLS_START,
+	MSIEVE_PROXY_STATE_TLS_READY,
+	MSIEVE_PROXY_STATE_XCLIENT,
+	MSIEVE_PROXY_STATE_AUTH,
 };
 
 typedef enum {
@@ -43,28 +44,6 @@
 	i_free_and_null(client->proxy_password);
 }
 
-static void get_plain_auth(struct client *client, string_t *dest)
-{
-	string_t *str, *base64;
-
-	str = t_str_new(128);
-	if ( client->proxy_master_user == NULL ) {
-		str_append_c(str, '\0');
-		str_append(str, client->proxy_user);
-	} else {
-		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 = t_str_new(128);
-	base64_encode(str_data(str), str_len(str), base64);
-
-	managesieve_quote_append_string(dest, str_c(base64), FALSE);
-}
-
 static void proxy_write_xclient
 (struct managesieve_client *client, string_t *str)
 {
@@ -76,8 +55,14 @@
 		client->common.proxy_ttl - 1);
 }
 
-static int proxy_write_login(struct managesieve_client *client, string_t *str)
+static int proxy_write_auth
+(struct managesieve_client *client, string_t *str)
 {
+	struct dsasl_client_settings sasl_set;
+	const unsigned char *output;
+	unsigned int len;
+	const char *mech_name, *error;
+
 	i_assert(client->common.proxy_ttl > 1);
 
 	if ( !client->proxy_sasl_plain ) {
@@ -86,12 +71,134 @@
 		return -1;
 	}
 
-	/*   Send command */
-	str_append(str, "AUTHENTICATE \"PLAIN\" ");
-	get_plain_auth(&client->common, str);
+	if (client->common.proxy_mech == NULL)
+		client->common.proxy_mech = &dsasl_client_mech_plain;
+
+	i_assert(client->common.proxy_sasl_client == NULL);
+	memset(&sasl_set, 0, sizeof(sasl_set));
+	sasl_set.authid = client->common.proxy_master_user != NULL ?
+		client->common.proxy_master_user : client->common.proxy_user;
+	sasl_set.authzid = client->common.proxy_user;
+	sasl_set.password = client->common.proxy_password;
+	client->common.proxy_sasl_client =
+		dsasl_client_new(client->common.proxy_mech, &sasl_set);
+	mech_name = dsasl_client_mech_get_name(client->common.proxy_mech);
+
+	str_append(str, "AUTHENTICATE ");
+	managesieve_quote_append_string(str, mech_name, FALSE);
+	if (dsasl_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(str, "\"\"");
+	else {
+		string_t *resp = t_str_new(128);
+		base64_encode(output, len, resp);
+		managesieve_quote_append_string(str, str_c(resp), FALSE);
+	}
+	str_append(str, "\r\n");
 	proxy_free_password(&client->common);
+	return 0;
+}
+
+static int proxy_input_auth_challenge
+(struct managesieve_client *client, const char *line,
+	const char **challenge_r)
+{
+	struct istream *input;
+	struct managesieve_parser *parser;
+ 	const struct managesieve_arg *args;
+	const char *challenge;
+	bool fatal = FALSE;
+	int ret;
+
+	i_assert(client->common.proxy_sasl_client != NULL);
+	*challenge_r = NULL;
+
+	/* Build an input stream for the managesieve parser
+	 *  FIXME: Ugly, see proxy_input_capability().
+	 */
+	line = t_strconcat(line, "\r\n", NULL);
+	input = i_stream_create_from_data(line, strlen(line));
+	parser = managesieve_parser_create(input, MAX_MANAGESIEVE_LINE);
+	managesieve_parser_reset(parser);
+
+	(void)i_stream_read(input);
+	ret = managesieve_parser_read_args(parser, 1, 0, &args);
+
+	if ( ret >= 1 ) {
+		if ( managesieve_arg_get_string(&args[0], &challenge) ) {
+			*challenge_r = t_strdup(challenge);
+		} else {
+			client_log_err(&client->common, t_strdup_printf("proxy: "
+				"Server sent invalid SASL challenge line: %s",
+				str_sanitize(line,160)));
+			fatal = TRUE;
+		}
+
+	} else if ( ret == -2 ) {
+		/* Parser needs more data (not possible on mem stream) */
+		i_unreached();
+
+	} else if ( ret < 0 ) {
+		const char *error_str = managesieve_parser_get_error(parser, &fatal);
+		error_str = (error_str != NULL ? error_str : "unknown (bug)" );
+
+		/* Do not accept faulty server */
+		client_log_err(&client->common, t_strdup_printf("proxy: "
+			"Protocol parse error(%d) int SASL challenge line: %s (line=`%s')",
+			ret, error_str, line));
+		fatal = TRUE;
+	}
+
+
+	/* Cleanup parser */
+  managesieve_parser_destroy(&parser);
+	i_stream_destroy(&input);
+
+	/* Time to exit if greeting was not accepted */
+	if ( fatal ) return -1;
+	return 0;
+}
+
+static int proxy_write_auth_response
+(struct managesieve_client *client,
+	const char *challenge, string_t *str)
+{
+	const unsigned char *data;
+	unsigned int data_len;
+	const char *error;
+	int ret;
+
+	str = t_str_new(256);
+	if (base64_decode(challenge, strlen(challenge), NULL, str) < 0) {
+		client_log_err(&client->common,
+			"proxy: Server sent invalid base64 data in AUTHENTICATE response");
+		return -1;
+	}
+	ret = dsasl_client_input(client->common.proxy_sasl_client,
+				 str_data(str), str_len(str), &error);
+	if (ret == 0) {
+		ret = dsasl_client_output(client->common.proxy_sasl_client,
+					  &data, &data_len, &error);
+	}
+	if (ret < 0) {
+		client_log_err(&client->common, t_strdup_printf(
+			"proxy: Server sent invalid authentication data: %s",
+			error));
+		return -1;
+	}
+	i_assert(ret == 0);
+
+	str_truncate(str, 0);
+	base64_encode(data, data_len, str);
 	str_append(str, "\r\n");
-	return 1;
+	return 0;
 }
 
 static managesieve_response_t proxy_read_response
@@ -100,22 +207,19 @@
 	const char *response;
 
 	if ( managesieve_arg_get_atom(&args[0], &response) ) {
-
 		if ( strcasecmp(response, "OK") == 0 ) {
 			/* Received OK response; greeting is finished */
 			return MANAGESIEVE_RESPONSE_OK;
 
-        } else if ( strcasecmp(response, "NO") == 0 ) {
+		} else if ( strcasecmp(response, "NO") == 0 ) {
 			/* Received OK response; greeting is finished */
 			return MANAGESIEVE_RESPONSE_NO;
 
-        } else if ( strcasecmp(response, "BYE") == 0 ) {
+		} else if ( strcasecmp(response, "BYE") == 0 ) {
 			/* Received OK response; greeting is finished */
 			return MANAGESIEVE_RESPONSE_BYE;
-
 		}
 	}
-
 	return MANAGESIEVE_RESPONSE_NONE;
 }
 
@@ -200,19 +304,19 @@
 		/* Parser needs more data (not possible on mem stream) */
 		i_unreached();
 
-    } else if ( ret < 0 ) {
+	} else if ( ret < 0 ) {
 		const char *error_str = managesieve_parser_get_error(parser, &fatal);
 		error_str = (error_str != NULL ? error_str : "unknown (bug)" );
 
 		/* Do not accept faulty server */
 		client_log_err(&client->common, t_strdup_printf("proxy: "
-			"Protocol parse error(%d) in capability/greeting line: %s (line='%s')",
+			"Protocol parse error(%d) in capability/greeting line: %s (line=`%s')",
 			ret, error_str, line));
 		fatal = TRUE;
 	}
 
 	/* Cleanup parser */
-    managesieve_parser_destroy(&parser);
+	managesieve_parser_destroy(&parser);
 	i_stream_destroy(&input);
 
 	/* Time to exit if greeting was not accepted */
@@ -238,8 +342,9 @@
 
 	output = login_proxy_get_ostream(client->login_proxy);
 	switch ( msieve_client->proxy_state ) {
-	case PROXY_STATE_INITIAL:
-		if ( (ret=proxy_input_capability(msieve_client, line, &response)) < 0 ) {
+	case MSIEVE_PROXY_STATE_NONE:
+		if ( (ret=proxy_input_capability
+			(msieve_client, line, &response)) < 0 ) {
 			client_proxy_failed(client, TRUE);
 			return -1;
 		}
@@ -263,27 +368,27 @@
 				}
 
 				str_append(command, "STARTTLS\r\n");
-				msieve_client->proxy_state = PROXY_STATE_TLS_START;
+				msieve_client->proxy_state = MSIEVE_PROXY_STATE_TLS_START;
 
 			} else if (msieve_client->proxy_xclient) {
 				proxy_write_xclient(msieve_client, command);
-				msieve_client->proxy_state = PROXY_STATE_XCLIENT;
+				msieve_client->proxy_state = MSIEVE_PROXY_STATE_XCLIENT;
 
 			} else {
-				if ( proxy_write_login(msieve_client, command) < 0 ) {
+				if ( proxy_write_auth(msieve_client, command) < 0 ) {
 					client_proxy_failed(client, TRUE);
 					return -1;
 				}
-				msieve_client->proxy_state = PROXY_STATE_AUTHENTICATE;
+				msieve_client->proxy_state = MSIEVE_PROXY_STATE_AUTH;
 			}
 
 			(void)o_stream_send(output, str_data(command), str_len(command));
 		}
-
 		return 0;
 
-	case PROXY_STATE_TLS_START:


More information about the dovecot-cvs mailing list