From 8b9f5e2ed8df09b099c8dda57702a220e7487052 Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan.bosch@dovecot.fi>
Date: Thu, 4 Jan 2018 00:39:38 +0100
Subject: [PATCH] lib-sieve: imap4flags extension: Fix binary corruption
 occurring when setflag/addflag/removeflag flag-list is a variable.

The original implementation checked the first operand for being a variable.
Obviously, when the assigned flag string is just a variable, this doesn't work.
This causes the flag list to be recognized erroneously as a variable flags
string. Fixed the problem by explicitly emitting an omitted operand when there
is no second argument for a setflag/addflag/removeflag.

Because the new byte code format is incompatible, the extension version is
bumped to 1.
---
 src/lib-sieve/plugins/imap4flags/cmd-flag.c   | 40 +++++++++++--------
 .../plugins/imap4flags/ext-imap4flags.c       |  1 +
 2 files changed, 24 insertions(+), 17 deletions(-)

diff --git a/src/lib-sieve/plugins/imap4flags/cmd-flag.c b/src/lib-sieve/plugins/imap4flags/cmd-flag.c
index 6e550d9b1..26456691b 100644
--- a/src/lib-sieve/plugins/imap4flags/cmd-flag.c
+++ b/src/lib-sieve/plugins/imap4flags/cmd-flag.c
@@ -122,6 +122,8 @@ const struct sieve_operation_def removeflag_operation = {
 static bool cmd_flag_generate
 (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd)
 {
+	struct sieve_ast_argument *arg1, *arg2;
+
 	/* Emit operation */
 	if ( sieve_command_is(cmd, cmd_setflag) )
 		sieve_operation_emit(cgenv->sblock, cmd->ext, &setflag_operation);
@@ -130,10 +132,21 @@ static bool cmd_flag_generate
 	else if ( sieve_command_is(cmd, cmd_removeflag) )
 		sieve_operation_emit(cgenv->sblock, cmd->ext, &removeflag_operation);
 
-	/* Generate arguments */
-	if ( !sieve_generate_arguments(cgenv, cmd, NULL) )
-		return FALSE;
+	arg1 = cmd->first_positional;
+	arg2 = sieve_ast_argument_next(arg1);
 
+	if ( arg2 == NULL ) {
+		/* No variable */
+		sieve_opr_omitted_emit(cgenv->sblock);
+		if ( !sieve_generate_argument(cgenv, arg1, cmd) )
+			return FALSE;
+	} else {
+		/* Full command */
+		if ( !sieve_generate_argument(cgenv, arg1, cmd) )
+			return FALSE;
+		if ( !sieve_generate_argument(cgenv, arg2, cmd) )
+			return FALSE;
+	}
 	return TRUE;
 }
 
@@ -155,14 +168,14 @@ bool cmd_flag_operation_dump
 		return FALSE;
 	}
 
-	if ( sieve_operand_is_variable(&oprnd) ) {
+	if ( !sieve_operand_is_omitted(&oprnd) ) {
 		return
 			sieve_opr_string_dump_data(denv, &oprnd, address, "variable name") &&
 			sieve_opr_stringlist_dump(denv, address, "list of flags");
 	}
 
 	return
-		sieve_opr_stringlist_dump_data(denv, &oprnd, address, "list of flags");
+		sieve_opr_stringlist_dump(denv, address, "list of flags");
 }
 
 /*
@@ -190,10 +203,10 @@ static int cmd_flag_operation_execute
 		return ret;
 
 	/* Variable operand (optional) */
-	if ( sieve_operand_is_variable(&oprnd) ) {
+	if ( !sieve_operand_is_omitted(&oprnd) ) {
 		/* Read the variable operand */
 		if ( (ret=sieve_variable_operand_read_data
-				(renv, &oprnd, address, "variable", &storage, &var_index)) <= 0 )
+			(renv, &oprnd, address, "variable", &storage, &var_index)) <= 0 )
 			return ret;
 
 		/* Read flag list */
@@ -202,21 +215,14 @@ static int cmd_flag_operation_execute
 			return ret;
 
 	/* Flag-list operand */
-	} else if ( sieve_operand_is_stringlist(&oprnd) ) {
+	} else {
 		storage = NULL;
 		var_index = 0;
 
 		/* Read flag list */
-		if ( (ret=sieve_opr_stringlist_read_data
-			(renv, &oprnd, address, "flag-list", &flag_list)) <= 0 )
+		if ( (ret=sieve_opr_stringlist_read(renv, address,
+			"flag-list", &flag_list)) <= 0 )
 			return ret;
-
-	/* Invalid */
-	} else {
-		sieve_runtime_trace_operand_error
-			(renv, &oprnd, "expected variable or string-list (flag-list) operand "
-				"but found %s", sieve_operand_name(&oprnd));
-		return SIEVE_EXEC_BIN_CORRUPT;
 	}
 
 	/*
diff --git a/src/lib-sieve/plugins/imap4flags/ext-imap4flags.c b/src/lib-sieve/plugins/imap4flags/ext-imap4flags.c
index 3b908c0d5..23230c110 100644
--- a/src/lib-sieve/plugins/imap4flags/ext-imap4flags.c
+++ b/src/lib-sieve/plugins/imap4flags/ext-imap4flags.c
@@ -50,6 +50,7 @@ static bool ext_imap4flags_interpreter_load
 
 const struct sieve_extension_def imap4flags_extension = {
 	.name = "imap4flags",
+	.version = 1,
 	.validator_load = ext_imap4flags_validator_load,
 	.interpreter_load = ext_imap4flags_interpreter_load,
 	SIEVE_EXT_DEFINE_OPERATIONS(imap4flags_operations),
-- 
GitLab