From f9b37da139ceadcb352a2056e014731bdb35a530 Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan.bosch@dovecot.fi>
Date: Tue, 10 Jan 2017 23:22:28 +0100
Subject: [PATCH] lib-sieve: Fixed handling of
 mail_get_headers()/mail_get_headers_utf8() result.

The situation where no headers are found was not always handled correctly.
---
 .../plugins/enotify/mailto/ntfy-mailto.c      |  34 +++---
 src/lib-sieve/plugins/notify/cmd-notify.c     |  33 ++---
 src/lib-sieve/plugins/vacation/cmd-vacation.c | 115 ++++++++++--------
 .../plugins/vnd.dovecot/report/cmd-report.c   |   6 +-
 src/lib-sieve/sieve-message.c                 |   2 +-
 5 files changed, 103 insertions(+), 87 deletions(-)

diff --git a/src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c b/src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
index 9b2b5d629..8bf564b73 100644
--- a/src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
+++ b/src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c
@@ -516,7 +516,7 @@ static int ntfy_mailto_send
 
 		/* Fetch subject from original message */
 		if ( mail_get_headers_utf8
-			(msgdata->mail, "subject", &hsubject) >= 0 )
+			(msgdata->mail, "subject", &hsubject) > 0 )
 			subject = str_sanitize(t_strdup_printf("Notification: %s", hsubject[0]),
 				NTFY_MAILTO_MAX_SUBJECT);
 		else
@@ -672,7 +672,7 @@ static int ntfy_mailto_action_execute
 	i_assert( owner_email != NULL );
 
 	/* Is the message an automatic reply ? */
-	if ( mail_get_headers(mail, "auto-submitted", &hdsp) < 0 ) {
+	if ( (ret=mail_get_headers(mail, "auto-submitted", &hdsp)) < 0 ) {
 		sieve_enotify_critical(nenv,
 			"mailto notification: "
 				"failed to read `auto-submitted' header field",
@@ -683,21 +683,23 @@ static int ntfy_mailto_action_execute
 	}
 
 	/* Theoretically multiple headers could exist, so lets make sure */
-	while ( *hdsp != NULL ) {
-		if ( strcasecmp(*hdsp, "no") != 0 ) {
-			const char *from = NULL;
-
-			if ( (nenv->flags & SIEVE_EXECUTE_FLAG_NO_ENVELOPE) == 0 )
-				from = sieve_message_get_sender(nenv->msgctx);
-			from = (from == NULL ? "" :
-				t_strdup_printf(" from <%s>", str_sanitize(from, 256)));
-
-			sieve_enotify_global_info(nenv,
-				"not sending notification for auto-submitted message%s",
-				from);
-			return 0;
+	if ( ret > 0 ) {
+		while ( *hdsp != NULL ) {
+			if ( strcasecmp(*hdsp, "no") != 0 ) {
+				const char *from = NULL;
+
+				if ( (nenv->flags & SIEVE_EXECUTE_FLAG_NO_ENVELOPE) == 0 )
+					from = sieve_message_get_sender(nenv->msgctx);
+				from = (from == NULL ? "" :
+					t_strdup_printf(" from <%s>", str_sanitize(from, 256)));
+
+				sieve_enotify_global_info(nenv,
+					"not sending notification "
+					"for auto-submitted message%s", from);
+				return 0;
+			}
+			hdsp++;
 		}
-		hdsp++;
 	}
 
 	T_BEGIN {
diff --git a/src/lib-sieve/plugins/notify/cmd-notify.c b/src/lib-sieve/plugins/notify/cmd-notify.c
index 83671f706..75878abfc 100644
--- a/src/lib-sieve/plugins/notify/cmd-notify.c
+++ b/src/lib-sieve/plugins/notify/cmd-notify.c
@@ -805,30 +805,33 @@ static int act_notify_commit
 		(const struct ext_notify_action *) action->context;
 	const char *const *hdsp;
 	bool result;
+	int ret;
 
 	/* Is the message an automatic reply ? */
-	if ( mail_get_headers(mail, "auto-submitted", &hdsp) < 0 ) {
+	if ( (ret=mail_get_headers(mail, "auto-submitted", &hdsp)) < 0 ) {
 		return sieve_result_mail_error(aenv, mail,
 			"notify action: "
 			"failed to read `auto-submitted' header field");
 	}
 
 	/* Theoretically multiple headers could exist, so lets make sure */
-	while ( *hdsp != NULL ) {
-		if ( strcasecmp(*hdsp, "no") != 0 ) {
-			const char *from = NULL;
-
-			if ( (aenv->flags & SIEVE_EXECUTE_FLAG_NO_ENVELOPE) == 0 )
-				from = sieve_message_get_sender(aenv->msgctx);
-			from = (from == NULL ? "" :
-				t_strdup_printf(" from <%s>", str_sanitize(from, 256)));
-
-			sieve_result_global_log(aenv,
-				"not sending notification for auto-submitted message%s",
-				from);
-			return SIEVE_EXEC_OK;
+	if (ret > 0) {
+		while ( *hdsp != NULL ) {
+			if ( strcasecmp(*hdsp, "no") != 0 ) {
+				const char *from = NULL;
+
+				if ( (aenv->flags & SIEVE_EXECUTE_FLAG_NO_ENVELOPE) == 0 )
+					from = sieve_message_get_sender(aenv->msgctx);
+				from = (from == NULL ? "" :
+					t_strdup_printf(" from <%s>", str_sanitize(from, 256)));
+
+				sieve_result_global_log(aenv,
+					"not sending notification for auto-submitted message%s",
+					from);
+				return SIEVE_EXEC_OK;
+			}
+			hdsp++;
 		}
-		hdsp++;
 	}
 
 	T_BEGIN {
diff --git a/src/lib-sieve/plugins/vacation/cmd-vacation.c b/src/lib-sieve/plugins/vacation/cmd-vacation.c
index 9d38dc942..4c57dedd8 100644
--- a/src/lib-sieve/plugins/vacation/cmd-vacation.c
+++ b/src/lib-sieve/plugins/vacation/cmd-vacation.c
@@ -911,13 +911,13 @@ static int act_vacation_send
 	/* Make sure we have a subject for our reply */
 
 	if ( ctx->subject == NULL || *(ctx->subject) == '\0' ) {
-		if ( mail_get_headers_utf8
-			(msgdata->mail, "subject", &headers) < 0 ) {
+		if ( (ret=mail_get_headers_utf8
+			(msgdata->mail, "subject", &headers)) < 0 ) {
 			return sieve_result_mail_error(aenv, msgdata->mail,
 				"vacation action: "
 				"failed to read header field `subject'");
 		}
-		if ( headers[0] != NULL ) {
+		if ( ret > 0 && headers[0] != NULL ) {
 			subject = t_strconcat("Auto: ", headers[0], NULL);
 		}	else {
 			subject = "Automated reply";
@@ -960,8 +960,8 @@ static int act_vacation_send
 
 	/* Compose proper in-reply-to and references headers */
 
-	if ( mail_get_headers
-		(msgdata->mail, "references", &headers) < 0 ) {
+	if ( (ret=mail_get_headers
+		(msgdata->mail, "references", &headers)) < 0 ) {
 		return sieve_result_mail_error(aenv, msgdata->mail,
 			"vacation action: "
 			"failed to read header field `references'");
@@ -970,12 +970,13 @@ static int act_vacation_send
 	if ( msgdata->id != NULL ) {
 		rfc2822_header_write(msg, "In-Reply-To", msgdata->id);
 
-		if ( headers[0] != NULL )
-			rfc2822_header_write
-				(msg, "References", t_strconcat(headers[0], " ", msgdata->id, NULL));
-		else
+		if ( ret > 0 && headers[0] != NULL ) {
+			rfc2822_header_write(msg, "References",
+				t_strconcat(headers[0], " ", msgdata->id, NULL));
+		} else {
 			rfc2822_header_write(msg, "References", msgdata->id);
-	} else if ( headers[0] != NULL ) {
+		}
+	} else if ( ret > 0 && headers[0] != NULL ) {
 		rfc2822_header_write(msg, "References", headers[0]);
 	}
 
@@ -1106,16 +1107,17 @@ static int act_vacation_commit
 	/* Are we trying to respond to a mailing list ? */
 	hdsp = _list_headers;
 	while ( *hdsp != NULL ) {
-		if ( mail_get_headers(mail, *hdsp, &headers) < 0 ) {
+		if ( (ret=mail_get_headers(mail, *hdsp, &headers)) < 0 ) {
 			return sieve_result_mail_error(aenv, mail,
 				"vacation action: "
 				"failed to read header field `%s'", *hdsp);
 		}
 
-		if ( headers[0] != NULL ) {
+		if ( ret > 0 && headers[0] != NULL ) {
 			/* Yes, bail out */
 			sieve_result_global_log(aenv,
-				"discarding vacation response to mailinglist recipient <%s>",
+				"discarding vacation response "
+				"to mailinglist recipient <%s>",
 				str_sanitize(sender, 128));
 			return SIEVE_EXEC_OK;
 		}
@@ -1123,68 +1125,77 @@ static int act_vacation_commit
 	}
 
 	/* Is the message that we are replying to an automatic reply ? */
-	if ( mail_get_headers
-		(mail, "auto-submitted", &headers) < 0 ) {
+	if ( (ret=mail_get_headers
+		(mail, "auto-submitted", &headers)) < 0 ) {
 		return sieve_result_mail_error(aenv, mail,
 			"vacation action: "
 			"failed to read header field `auto-submitted'");
 	}
 	/* Theoretically multiple headers could exist, so lets make sure */
-	hdsp = headers;
-	while ( *hdsp != NULL ) {
-		if ( strcasecmp(*hdsp, "no") != 0 ) {
-			sieve_result_global_log(aenv,
-				"discarding vacation response to auto-submitted message from <%s>",
-				str_sanitize(sender, 128));
-				return SIEVE_EXEC_OK;
+	if ( ret > 0 ) {
+		hdsp = headers;
+		while ( *hdsp != NULL ) {
+			if ( strcasecmp(*hdsp, "no") != 0 ) {
+				sieve_result_global_log(aenv,
+					"discarding vacation response "
+					"to auto-submitted message from <%s>",
+					str_sanitize(sender, 128));
+					return SIEVE_EXEC_OK;
+			}
+			hdsp++;
 		}
-		hdsp++;
 	}
 
 	/* Check for the (non-standard) precedence header */
-	if ( mail_get_headers
-		(mail, "precedence", &headers) < 0 ) {
+	if ( (ret=mail_get_headers
+		(mail, "precedence", &headers)) < 0 ) {
 		return sieve_result_mail_error(aenv, mail,
 			"vacation action: "
 			"failed to read header field `precedence'");
 	}
 	/* Theoretically multiple headers could exist, so lets make sure */
-	hdsp = headers;
-	while ( *hdsp != NULL ) {
-		if ( strcasecmp(*hdsp, "junk") == 0 || strcasecmp(*hdsp, "bulk") == 0 ||
-			strcasecmp(*hdsp, "list") == 0 ) {
-			sieve_result_global_log(aenv,
-				"discarding vacation response to precedence=%s message from <%s>",
-				*hdsp, str_sanitize(sender, 128));
-				return SIEVE_EXEC_OK;
+	if ( ret > 0 ) {
+		hdsp = headers;
+		while ( *hdsp != NULL ) {
+			if ( strcasecmp(*hdsp, "junk") == 0 ||
+				strcasecmp(*hdsp, "bulk") == 0 ||
+				strcasecmp(*hdsp, "list") == 0 ) {
+				sieve_result_global_log(aenv,
+					"discarding vacation response "
+					"to precedence=%s message from <%s>",
+					*hdsp, str_sanitize(sender, 128));
+					return SIEVE_EXEC_OK;
+			}
+			hdsp++;
 		}
-		hdsp++;
 	}
 
 	/* Check for the (non-standard) Microsoft X-Auto-Response-Suppress header */
-	if ( mail_get_headers
-		(mail, "x-auto-response-suppress", &headers) < 0 ) {
+	if ( (ret=mail_get_headers
+		(mail, "x-auto-response-suppress", &headers)) < 0 ) {
 		return sieve_result_mail_error(aenv, mail,
 			"vacation action: "
 			"failed to read header field `x-auto-response-suppress'");
 	}
 	/* Theoretically multiple headers could exist, so lets make sure */
-	hdsp = headers;
-	while ( *hdsp != NULL ) {
-		const char *const *flags = t_strsplit(*hdsp, ",");
-		while ( *flags != NULL ) {
-			const char *flag = t_str_trim(*flags, " \t");
-			if ( strcasecmp(flag, "All") == 0 ||
-				strcasecmp(flag, "OOF") == 0 ) {
-				sieve_result_global_log(aenv,
-					"discarding vacation response to message from <%s> "
-					"(`%s' flag found in x-auto-response-suppress header)",
-					str_sanitize(sender, 128), flag);
-					return SIEVE_EXEC_OK;
+	if ( ret > 0 ) {
+		hdsp = headers;
+		while ( *hdsp != NULL ) {
+			const char *const *flags = t_strsplit(*hdsp, ",");
+			while ( *flags != NULL ) {
+				const char *flag = t_str_trim(*flags, " \t");
+				if ( strcasecmp(flag, "All") == 0 ||
+					strcasecmp(flag, "OOF") == 0 ) {
+					sieve_result_global_log(aenv,
+						"discarding vacation response to message from <%s> "
+						"(`%s' flag found in x-auto-response-suppress header)",
+						str_sanitize(sender, 128), flag);
+						return SIEVE_EXEC_OK;
+				}
+				flags++;
 			}
-			flags++;
+			hdsp++;
 		}
-		hdsp++;
 	}
 
 	/* Do not reply to system addresses */
@@ -1207,12 +1218,12 @@ static int act_vacation_commit
 	 */
 	hdsp = _my_address_headers;
 	while ( *hdsp != NULL ) {
-		if ( mail_get_headers(mail, *hdsp, &headers) < 0 ) {
+		if ( (ret=mail_get_headers(mail, *hdsp, &headers)) < 0 ) {
 			return sieve_result_mail_error(aenv, mail,
 				"vacation action: "
 				"failed to read header field `%s'", *hdsp);
 		}
-		if ( headers[0] != NULL ) {
+		if ( ret > 0 && headers[0] != NULL ) {
 
 			/* Final recipient directly listed in headers? */
 			if ( _contains_my_address(headers, recipient) ) {
diff --git a/src/lib-sieve/plugins/vnd.dovecot/report/cmd-report.c b/src/lib-sieve/plugins/vnd.dovecot/report/cmd-report.c
index 40d3836ca..18c93cc0c 100644
--- a/src/lib-sieve/plugins/vnd.dovecot/report/cmd-report.c
+++ b/src/lib-sieve/plugins/vnd.dovecot/report/cmd-report.c
@@ -470,13 +470,13 @@ static int act_report_send
 	}
 
 	/* Make sure we have a subject for our report */
-	if ( mail_get_headers_utf8
-		(msgdata->mail, "subject", &headers) < 0 ) {
+	if ( (ret=mail_get_headers_utf8
+		(msgdata->mail, "subject", &headers)) < 0 ) {
 		return sieve_result_mail_error(aenv, msgdata->mail,
 			"report action: "
 			"failed to read header field `subject'");
 	}
-	if ( headers[0] != NULL ) {
+	if ( ret > 0 && headers[0] != NULL ) {
 		subject = t_strconcat("Report: ", headers[0], NULL);
 	}	else {
 		subject = "Report: (message without subject)";
diff --git a/src/lib-sieve/sieve-message.c b/src/lib-sieve/sieve-message.c
index 7cedd8ce4..3c40c41f1 100644
--- a/src/lib-sieve/sieve-message.c
+++ b/src/lib-sieve/sieve-message.c
@@ -627,7 +627,7 @@ static int sieve_message_header_list_next_item
 			return -1;
 		}
 
-		if ( hdrlist->headers == NULL || hdrlist->headers[0] == NULL ) {
+		if ( ret == 0 || hdrlist->headers[0] == NULL ) {
 			/* Try next item when no headers found */
 			hdrlist->headers = NULL;
 		}
-- 
GitLab