changeset 21723:de665befcc92

imap-login: Log proxy state as human-readable string. Separate sent/received state and log them as strings.
author Timo Sirainen <timo.sirainen@dovecot.fi>
date Thu, 09 Mar 2017 10:41:52 -0500
parents 5571a8162b42
children dce69a67f3b2
files src/imap-login/imap-login-client.c src/imap-login/imap-login-client.h src/imap-login/imap-proxy.c src/imap-login/imap-proxy.h
diffstat 4 files changed, 76 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/src/imap-login/imap-login-client.c	Thu Mar 09 10:31:39 2017 -0500
+++ b/src/imap-login/imap-login-client.c	Thu Mar 09 10:41:52 2017 -0500
@@ -697,7 +697,8 @@
 	imap_client_auth_result,
 	imap_proxy_reset,
 	imap_proxy_parse_line,
-	imap_proxy_error
+	imap_proxy_error,
+	imap_proxy_get_state,
 };
 
 static const struct login_binary imap_login_binary = {
--- a/src/imap-login/imap-login-client.h	Thu Mar 09 10:31:39 2017 -0500
+++ b/src/imap-login/imap-login-client.h	Thu Mar 09 10:41:52 2017 -0500
@@ -14,6 +14,30 @@
 	IMAP_CLIENT_ID_STATE_VALUE
 };
 
+/* Multiple commands can be sent pipelined, so the sent_state is a bitmask */
+enum imap_proxy_sent_state {
+	IMAP_PROXY_SENT_STATE_ID		= 0x01,
+	IMAP_PROXY_SENT_STATE_STARTTLS		= 0x02,
+	IMAP_PROXY_SENT_STATE_CAPABILITY	= 0x04,
+	IMAP_PROXY_SENT_STATE_AUTHENTICATE	= 0x08,
+	IMAP_PROXY_SENT_STATE_AUTH_CONTINUE	= 0x10,
+	IMAP_PROXY_SENT_STATE_LOGIN		= 0x20,
+
+	IMAP_PROXY_SENT_STATE_COUNT = 6
+};
+
+enum imap_proxy_rcvd_state {
+	IMAP_PROXY_RCVD_STATE_NONE,
+	IMAP_PROXY_RCVD_STATE_BANNER,
+	IMAP_PROXY_RCVD_STATE_ID,
+	IMAP_PROXY_RCVD_STATE_STARTTLS,
+	IMAP_PROXY_RCVD_STATE_CAPABILITY,
+	IMAP_PROXY_RCVD_STATE_AUTH_CONTINUE,
+	IMAP_PROXY_RCVD_STATE_LOGIN,
+
+	IMAP_PROXY_RCVD_STATE_COUNT
+};
+
 struct imap_client_cmd_id {
 	struct imap_parser *parser;
 
@@ -34,6 +58,9 @@
 	const char *cmd_tag, *cmd_name;
 	struct imap_client_cmd_id *cmd_id;
 
+	enum imap_proxy_sent_state proxy_sent_state;
+	enum imap_proxy_rcvd_state proxy_rcvd_state;
+
 	unsigned int cmd_finished:1;
 	unsigned int proxy_sasl_ir:1;
 	unsigned int proxy_logindisabled:1;
--- a/src/imap-login/imap-proxy.c	Thu Mar 09 10:31:39 2017 -0500
+++ b/src/imap-login/imap-proxy.c	Thu Mar 09 10:41:52 2017 -0500
@@ -16,15 +16,13 @@
 #include "imap-quote.h"
 #include "imap-proxy.h"
 
-
-enum imap_proxy_state {
-	IMAP_PROXY_STATE_NONE,
-	IMAP_PROXY_STATE_BANNER,
-	IMAP_PROXY_STATE_ID,
-	IMAP_PROXY_STATE_STARTTLS,
-	IMAP_PROXY_STATE_CAPABILITY,
-	IMAP_PROXY_STATE_AUTH_CONTINUE,
-	IMAP_PROXY_STATE_LOGIN
+static const char *imap_proxy_sent_state_names[IMAP_PROXY_SENT_STATE_COUNT] = {
+	"id", "starttls", "capability",
+	"authenticate", "auth-continue", "login"
+};
+static const char *imap_proxy_rcvd_state_names[IMAP_PROXY_RCVD_STATE_COUNT] = {
+	"none", "banner", "id", "starttls", "capability",
+	"auth-continue", "login"
 };
 
 static void proxy_write_id(struct imap_client *client, string_t *str)
@@ -66,6 +64,7 @@
 			return -1;
 		}
 		str_append(str, "S STARTTLS\r\n");
+		client->proxy_sent_state |= IMAP_PROXY_SENT_STATE_STARTTLS;
 		return 1;
 	}
 	return 0;
@@ -88,6 +87,7 @@
 	    (client->proxy_backend_capability == NULL ||
 	     client->client_ignores_capability_resp_code)) {
 		client->proxy_capability_request_sent = TRUE;
+		client->proxy_sent_state |= IMAP_PROXY_SENT_STATE_CAPABILITY;
 		str_append(str, "C CAPABILITY\r\n");
 		if (client->common.proxy_nopipelining) {
 			/* authenticate only after receiving C OK reply. */
@@ -109,6 +109,7 @@
 		imap_append_string(str, client->common.proxy_password);
 		str_append(str, "\r\n");
 
+		client->proxy_sent_state |= IMAP_PROXY_SENT_STATE_LOGIN;
 		proxy_free_password(&client->common);
 		return 0;
 	}
@@ -141,6 +142,7 @@
 	}
 	str_append(str, "\r\n");
 	proxy_free_password(&client->common);
+	client->proxy_sent_state |= IMAP_PROXY_SENT_STATE_AUTHENTICATE;
 	return 0;
 }
 
@@ -170,6 +172,7 @@
 			i_strdup(t_strcut(line + 5 + 12, ']'));
 		if (str_array_icase_find(capabilities, "ID") &&
 		    !client->common.proxy_not_trusted) {
+			client->proxy_sent_state |= IMAP_PROXY_SENT_STATE_ID;
 			proxy_write_id(client, str);
 			if (client->common.proxy_nopipelining) {
 				/* write login or starttls after I OK */
@@ -240,7 +243,7 @@
 	output = login_proxy_get_ostream(client->login_proxy);
 	if (!imap_client->proxy_seen_banner) {
 		/* this is a banner */
-		client->proxy_state = IMAP_PROXY_STATE_BANNER;
+		imap_client->proxy_rcvd_state = IMAP_PROXY_RCVD_STATE_BANNER;
 		imap_client->proxy_seen_banner = TRUE;
 		if (proxy_input_banner(imap_client, output, line) < 0) {
 			client_proxy_failed(client, TRUE);
@@ -253,7 +256,8 @@
 			/* used literals with LOGIN command, just ignore. */
 			return 0;
 		}
-		client->proxy_state = IMAP_PROXY_STATE_AUTH_CONTINUE;
+		imap_client->proxy_sent_state &= ~IMAP_PROXY_SENT_STATE_AUTHENTICATE;
+		imap_client->proxy_rcvd_state = IMAP_PROXY_RCVD_STATE_AUTH_CONTINUE;
 
 		str = t_str_new(128);
 		if (line[1] != ' ' ||
@@ -282,9 +286,13 @@
 		base64_encode(data, data_len, str);
 		str_append(str, "\r\n");
 
+		imap_client->proxy_sent_state |= IMAP_PROXY_SENT_STATE_AUTH_CONTINUE;
 		o_stream_nsend(output, str_data(str), str_len(str));
 		return 0;
 	} else if (strncmp(line, "S ", 2) == 0) {
+		imap_client->proxy_sent_state &= ~IMAP_PROXY_SENT_STATE_STARTTLS;
+		imap_client->proxy_rcvd_state = IMAP_PROXY_RCVD_STATE_STARTTLS;
+
 		if (strncmp(line, "S OK ", 5) != 0) {
 			/* STARTTLS failed */
 			client_log_err(client, t_strdup_printf(
@@ -294,7 +302,6 @@
 			return -1;
 		}
 		/* STARTTLS successful, begin TLS negotiation. */
-		client->proxy_state = IMAP_PROXY_STATE_STARTTLS;
 		if (login_proxy_starttls(client->login_proxy) < 0) {
 			client_proxy_failed(client, TRUE);
 			return -1;
@@ -310,7 +317,8 @@
 		return 1;
 	} else if (strncmp(line, "L OK ", 5) == 0) {
 		/* Login successful. Send this line to client. */
-		client->proxy_state = IMAP_PROXY_STATE_LOGIN;
+		imap_client->proxy_sent_state &= ~IMAP_PROXY_SENT_STATE_LOGIN;
+		imap_client->proxy_rcvd_state = IMAP_PROXY_RCVD_STATE_LOGIN;
 		str = t_str_new(128);
 		client_send_login_reply(imap_client, str, line + 5);
 		o_stream_nsend(client->output, str_data(str), str_len(str));
@@ -319,6 +327,9 @@
 		client_proxy_finish_destroy_client(client);
 		return 1;
 	} else if (strncmp(line, "L ", 2) == 0) {
+		imap_client->proxy_sent_state &= ~IMAP_PROXY_SENT_STATE_LOGIN;
+		imap_client->proxy_rcvd_state = IMAP_PROXY_RCVD_STATE_LOGIN;
+
 		line += 2;
 		if (client->set->auth_verbose) {
 			const char *log_line = line;
@@ -364,7 +375,8 @@
 		return 0;
 	} else if (strncmp(line, "C ", 2) == 0) {
 		/* Reply to CAPABILITY command we sent */
-		client->proxy_state = IMAP_PROXY_STATE_CAPABILITY;
+		imap_client->proxy_sent_state &= ~IMAP_PROXY_SENT_STATE_CAPABILITY;
+		imap_client->proxy_rcvd_state = IMAP_PROXY_RCVD_STATE_CAPABILITY;
 		if (strncmp(line, "C OK ", 5) == 0 &&
 		    client->proxy_password != NULL) {
 			/* pipelining was disabled, send the login now. */
@@ -379,7 +391,8 @@
 		/* Reply to ID command we sent, ignore it unless
 		   pipelining is disabled, in which case send
 		   either STARTTLS or login */
-		client->proxy_state = IMAP_PROXY_STATE_ID;
+		imap_client->proxy_sent_state &= ~IMAP_PROXY_SENT_STATE_ID;
+		imap_client->proxy_rcvd_state = IMAP_PROXY_RCVD_STATE_ID;
 
 		if (client->proxy_nopipelining) {
 			str = t_str_new(128);
@@ -417,7 +430,8 @@
 	imap_client->proxy_logindisabled = FALSE;
 	imap_client->proxy_seen_banner = FALSE;
 	imap_client->proxy_capability_request_sent = FALSE;
-	client->proxy_state = IMAP_PROXY_STATE_NONE;
+	imap_client->proxy_sent_state = 0;
+	imap_client->proxy_rcvd_state = IMAP_PROXY_RCVD_STATE_NONE;
 }
 
 void imap_proxy_error(struct client *client, const char *text)
@@ -425,3 +439,19 @@
 	client_send_reply_code(client, IMAP_CMD_REPLY_NO,
 			       IMAP_RESP_CODE_UNAVAILABLE, text);
 }
+
+const char *imap_proxy_get_state(struct client *client)
+{
+	struct imap_client *imap_client = (struct imap_client *)client;
+	string_t *str = t_str_new(128);
+
+	for (unsigned int i = 0; i < IMAP_PROXY_SENT_STATE_COUNT; i++) {
+		if (str_len(str) > 0)
+			str_append_c(str, '+');
+		if ((imap_client->proxy_sent_state & (1 << i)) != 0)
+			str_append(str, imap_proxy_sent_state_names[i]);
+	}
+	str_append_c(str, '/');
+	str_append(str, imap_proxy_rcvd_state_names[imap_client->proxy_rcvd_state]);
+	return str_c(str);
+}
--- a/src/imap-login/imap-proxy.h	Thu Mar 09 10:31:39 2017 -0500
+++ b/src/imap-login/imap-proxy.h	Thu Mar 09 10:41:52 2017 -0500
@@ -5,5 +5,6 @@
 int imap_proxy_parse_line(struct client *client, const char *line);
 
 void imap_proxy_error(struct client *client, const char *text);
+const char *imap_proxy_get_state(struct client *client);
 
 #endif