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