commit 5b66054: [Minor] Protocol: Allow parsing of recipients with commas

Vsevolod Stakhov vsevolod at highsecure.ru
Wed Jun 12 13:49:05 UTC 2019


Author: Vsevolod Stakhov
Date: 2019-06-12 14:45:57 +0100
URL: https://github.com/rspamd/rspamd/commit/5b66054e6fd0a822dd8571669140da590db5593d (HEAD -> master)

[Minor] Protocol: Allow parsing of recipients with commas

---
 src/libserver/protocol.c | 146 ++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 112 insertions(+), 34 deletions(-)

diff --git a/src/libserver/protocol.c b/src/libserver/protocol.c
index 72526ecee..7d3ccb27d 100644
--- a/src/libserver/protocol.c
+++ b/src/libserver/protocol.c
@@ -224,6 +224,117 @@ err:
 	return FALSE;
 }
 
+static void
+rspamd_protocol_process_recipients (struct rspamd_task *task,
+		const rspamd_ftok_t *hdr)
+{
+	enum {
+		skip_spaces,
+		quoted_string,
+		normal_string,
+	} state = skip_spaces;
+	const gchar *p, *end, *start_addr;
+	struct rspamd_email_address *addr;
+
+	p = hdr->begin;
+	end = hdr->begin + hdr->len;
+	start_addr = NULL;
+
+	while (p < end) {
+		switch (state) {
+		case skip_spaces:
+			if (g_ascii_isspace (*p)) {
+				p ++;
+			}
+			else if (*p == '"') {
+				start_addr = p;
+				p ++;
+				state = quoted_string;
+			}
+			else {
+				state = normal_string;
+				start_addr = p;
+			}
+			break;
+		case quoted_string:
+			if (*p == '"') {
+				state = normal_string;
+				p ++;
+			}
+			else if (*p == '\\') {
+				/* Quoted pair */
+				p += 2;
+			}
+			else {
+				p ++;
+			}
+			break;
+		case normal_string:
+			if (*p == '"') {
+				state = quoted_string;
+				p ++;
+			}
+			else if (*p == ',' && start_addr != NULL && p > start_addr) {
+				/* We have finished address, check what we have */
+				addr = rspamd_email_address_from_smtp (start_addr,
+						p - start_addr);
+
+				if (addr) {
+					if (task->rcpt_envelope == NULL) {
+						task->rcpt_envelope = g_ptr_array_sized_new (
+								2);
+					}
+
+					g_ptr_array_add (task->rcpt_envelope, addr);
+				}
+				else {
+					msg_err_protocol ("bad rcpt address: '%*s'",
+							(int)(p - start_addr), start_addr);
+					task->flags |= RSPAMD_TASK_FLAG_BROKEN_HEADERS;
+				}
+				start_addr = NULL;
+				p ++;
+				state = skip_spaces;
+			}
+			else {
+				p ++;
+			}
+			break;
+		}
+	}
+
+	/* Check remainder */
+	if (start_addr && p > start_addr) {
+		switch (state) {
+		case normal_string:
+			addr = rspamd_email_address_from_smtp (start_addr, end - start_addr);
+
+			if (addr) {
+				if (task->rcpt_envelope == NULL) {
+					task->rcpt_envelope = g_ptr_array_sized_new (
+							2);
+				}
+
+				g_ptr_array_add (task->rcpt_envelope, addr);
+			}
+			else {
+				msg_err_protocol ("bad rcpt address: '%*s'",
+						(int)(end - start_addr), start_addr);
+				task->flags |= RSPAMD_TASK_FLAG_BROKEN_HEADERS;
+			}
+			break;
+		case skip_spaces:
+			/* Do nothing */
+			break;
+		case quoted_string:
+		default:
+			msg_err_protocol ("bad state when parsing rcpt address: '%*s'",
+					(int)(end - start_addr), start_addr);
+			task->flags |= RSPAMD_TASK_FLAG_BROKEN_HEADERS;
+		}
+	}
+}
+
 #define IF_HEADER(name) \
 	srch.begin = (name); \
 	srch.len = sizeof (name) - 1; \
@@ -237,7 +348,6 @@ rspamd_protocol_handle_headers (struct rspamd_task *task,
 	rspamd_ftok_t *hn_tok, *hv_tok, srch;
 	gboolean fl, has_ip = FALSE;
 	struct rspamd_http_header *header, *h, *htmp;
-	struct rspamd_email_address *addr;
 
 	HASH_ITER (hh, msg->headers, header, htmp) {
 		DL_FOREACH (header, h) {
@@ -318,39 +428,7 @@ rspamd_protocol_handle_headers (struct rspamd_task *task,
 			case 'r':
 			case 'R':
 				IF_HEADER (RCPT_HEADER) {
-					const gchar *p, *end;
-					gsize cur_len;
-
-					p = hv->str;
-					end = p + hv->len;
-
-					while (p < end) {
-						cur_len = rspamd_memcspn (p, ",", end - p);
-
-						if (cur_len > 0) {
-							addr = rspamd_email_address_from_smtp (p, cur_len);
-
-							if (addr) {
-								if (task->rcpt_envelope == NULL) {
-									task->rcpt_envelope = g_ptr_array_sized_new (
-											2);
-								}
-
-								g_ptr_array_add (task->rcpt_envelope, addr);
-							} else {
-								msg_err_protocol ("bad rcpt header: '%T'",
-										&h->value);
-								task->flags |= RSPAMD_TASK_FLAG_BROKEN_HEADERS;
-							}
-
-							p += cur_len;
-						}
-
-						while (p < end && *p == ',') {
-							p ++;
-						}
-					}
-
+					rspamd_protocol_process_recipients (task, hv_tok);
 					msg_debug_protocol ("read rcpt header, value: %V", hv);
 				}
 				IF_HEADER (RAW_DATA_HEADER) {


More information about the Commits mailing list