From 3de551b54b8ded0b5f7a2cb6f8ed8fb61bfef3a8 Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan@rename-it.nl>
Date: Tue, 5 Jul 2011 20:32:28 +0200
Subject: [PATCH] lib-sieve: include extension: forgot to check variable
 identifier syntax.

---
 src/lib-sieve/plugins/include/cmd-global.c    |  4 +-
 .../plugins/include/ext-include-variables.c   |  9 ++++
 .../variables/ext-variables-arguments.c       | 10 ++--
 .../plugins/variables/ext-variables-name.c    | 50 ++++++++++++++-----
 .../plugins/variables/sieve-ext-variables.h   |  2 +
 .../extensions/include/rfc-ex2-default.sieve  |  2 +-
 6 files changed, 57 insertions(+), 20 deletions(-)

diff --git a/src/lib-sieve/plugins/include/cmd-global.c b/src/lib-sieve/plugins/include/cmd-global.c
index 6bef5cf6b..93f4a8f61 100644
--- a/src/lib-sieve/plugins/include/cmd-global.c
+++ b/src/lib-sieve/plugins/include/cmd-global.c
@@ -174,13 +174,13 @@ static bool cmd_global_validate
 			sieve_ast_argument_name(arg));
 		return FALSE;
 	}
-	
+
 	/* Join global commands with predecessors if possible */
 	if ( sieve_commands_equal(prev, cmd) ) {
 		/* Join this command's string list with the previous one */
 		prev->first_positional = sieve_ast_stringlist_join
 			(prev->first_positional, cmd->first_positional);
-		
+
 		if ( prev->first_positional == NULL ) {
 			/* Not going to happen unless MAXINT stringlist items are specified */
 			sieve_command_validate_error(valdtr, cmd, 
diff --git a/src/lib-sieve/plugins/include/ext-include-variables.c b/src/lib-sieve/plugins/include/ext-include-variables.c
index 436723190..bebf5dcc8 100644
--- a/src/lib-sieve/plugins/include/ext-include-variables.c
+++ b/src/lib-sieve/plugins/include/ext-include-variables.c
@@ -1,6 +1,9 @@
 /* Copyright (c) 2002-2011 Pigeonhole authors, see the included COPYING file
  */
 
+#include "lib.h"
+#include "str-sanitize.h"
+
 #include "sieve-common.h"
 #include "sieve-error.h"
 #include "sieve-script.h"
@@ -38,6 +41,12 @@ struct sieve_variable *ext_include_variable_import_global
 	/* Sanity safeguard */	
 	i_assert ( ctx->global_vars != NULL );
 
+	if ( !sieve_variable_identifier_is_valid(variable) ) {
+		sieve_command_validate_error(valdtr, cmd,
+			"invalid variable identifier '%s'", str_sanitize(variable,80));
+		return NULL;
+	}
+
 	/* Get/Declare the variable in the global scope */
 	global_var = sieve_variable_scope_get_variable(global_scope, variable, TRUE);
 
diff --git a/src/lib-sieve/plugins/variables/ext-variables-arguments.c b/src/lib-sieve/plugins/variables/ext-variables-arguments.c
index e2402a5fb..026bb13eb 100644
--- a/src/lib-sieve/plugins/variables/ext-variables-arguments.c
+++ b/src/lib-sieve/plugins/variables/ext-variables-arguments.c
@@ -343,19 +343,19 @@ static bool _sieve_variable_argument_activate
 	bool result = FALSE;
 	string_t *variable;
 	const char *varstr, *varend;
-	ARRAY_TYPE(sieve_variable_name) vname;	
+	ARRAY_TYPE(sieve_variable_name) vname;
 	int nelements = 0;
 
 	T_BEGIN {
-		t_array_init(&vname, 2);			
-	
+		t_array_init(&vname, 2);
+
 		variable = sieve_ast_argument_str(arg);
 		varstr = str_c(variable);
 		varend = PTR_OFFSET(varstr, str_len(variable));
 		nelements = ext_variable_name_parse(&vname, &varstr, varend);
 
-		/* Check whether name parsing succeeded */	
-		if ( nelements < 0 || varstr != varend ) {
+		/* Check whether name parsing succeeded */
+		if ( nelements <= 0 || varstr != varend ) {
 			/* Parse failed */
 			sieve_argument_validate_error(valdtr, arg, 
 				"invalid variable name '%s'", str_sanitize(str_c(variable),80));
diff --git a/src/lib-sieve/plugins/variables/ext-variables-name.c b/src/lib-sieve/plugins/variables/ext-variables-name.c
index b0e72dec7..28817a12f 100644
--- a/src/lib-sieve/plugins/variables/ext-variables-name.c
+++ b/src/lib-sieve/plugins/variables/ext-variables-name.c
@@ -13,14 +13,36 @@
 
 #include <ctype.h>
 
+bool sieve_variable_identifier_is_valid(const char *identifier)
+{
+	const char *p = identifier;
+	size_t plen = strlen(identifier);
+	const char *pend;
+
+	if ( plen == 0 || plen >= EXT_VARIABLES_MAX_VARIABLE_NAME_LEN )
+		return FALSE;
+
+	pend = PTR_OFFSET(identifier, plen);
+
+	if ( *p == '_' || i_isalpha(*p) ) {
+		p++;
+
+		while ( p < pend && (*p == '_' || i_isalnum(*p)) ) {
+			p++;
+		}
+	}
+
+	return ( p == pend );
+}
+
 int ext_variable_name_parse
 (ARRAY_TYPE(sieve_variable_name) *vname, const char **str, const char *strend)
 {
 	const char *p = *str;
-				
+
 	array_clear(vname);
 
-	for (;;) { 
+	while ( p < strend ) {
 		struct sieve_variable_name *cur_element;
 		string_t *cur_ident;
 
@@ -40,23 +62,23 @@ int ext_variable_name_parse
 			str_truncate(cur_ident, 0);
 			str_append_c(cur_ident, *p);
 			p++;
-		
+
 			while ( p < strend && (*p == '_' || i_isalnum(*p)) ) {
 				if ( str_len(cur_ident) >= EXT_VARIABLES_MAX_VARIABLE_NAME_LEN )
 					return -1;
 				str_append_c(cur_ident, *p);
 				p++;
 			}
-		
+
 		/* Num-variable */
 		} else if ( i_isdigit(*p) ) {
 			cur_element->num_variable = *p - '0';
 			p++;
-			
+
 			while ( p < strend && i_isdigit(*p) ) {
 				cur_element->num_variable = cur_element->num_variable*10 + (*p - '0');
 				p++;
-			} 
+			}
 
 			/* If a num-variable is first, no more elements can follow because no
 			 * namespace is specified.
@@ -69,16 +91,20 @@ int ext_variable_name_parse
 			*str = p;
 			return -1;
 		}
-		
+
 		/* Check whether next name element is present */
-		if ( p < strend && *p == '.' ) 
+		if ( p < strend && *p == '.' ) {
 			p++;
-		else
+
+			/* It may not be empty */
+			if ( p >= strend )
+				return -1;
+		} else
 			break;
 	}
-	
+
 	*str = p;
 	return array_count(vname);
-} 
- 
+}
+
 
diff --git a/src/lib-sieve/plugins/variables/sieve-ext-variables.h b/src/lib-sieve/plugins/variables/sieve-ext-variables.h
index 9eba962e1..5258e04ad 100644
--- a/src/lib-sieve/plugins/variables/sieve-ext-variables.h
+++ b/src/lib-sieve/plugins/variables/sieve-ext-variables.h
@@ -46,6 +46,8 @@ struct sieve_variable_name {
 
 ARRAY_DEFINE_TYPE(sieve_variable_name, struct sieve_variable_name);
 
+bool sieve_variable_identifier_is_valid(const char *identifier);
+
 /*
  * Variable scope
  */
diff --git a/tests/extensions/include/rfc-ex2-default.sieve b/tests/extensions/include/rfc-ex2-default.sieve
index 7124e03af..8b1bf4de6 100644
--- a/tests/extensions/include/rfc-ex2-default.sieve
+++ b/tests/extensions/include/rfc-ex2-default.sieve
@@ -1,6 +1,6 @@
 require ["variables", "include", "relational", "fileinto"];
 global "test";
-global "test-mailbox";
+global "test_mailbox";
 
 # The included script may contain repetitive code that is
 # effectively a subroutine that can be factored out.
-- 
GitLab