From 12a317ad6f62f60192c26175828c50f2a37544f6 Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan@rename-it.nl>
Date: Sun, 20 Dec 2009 10:25:08 +0100
Subject: [PATCH] Implemented script name checking using the requirements
 specified in the ManageSieve draft.

---
 TODO                                        |  1 -
 src/lib-sieve/plugins/include/cmd-include.c |  4 +-
 src/lib-sieve/sieve-script.c                | 48 +++++++++++++++++++++
 src/lib-sieve/sieve-script.h                |  7 +++
 4 files changed, 57 insertions(+), 3 deletions(-)

diff --git a/TODO b/TODO
index 6f2d23202..3917fd269 100644
--- a/TODO
+++ b/TODO
@@ -15,7 +15,6 @@ Next (in order of descending priority/precedence):
 * Implement namespace support for variables extension (to complete include 
   extension)
 * Update include extension to latest draft:
-	- Perform script name check
 	- Implement global namespace
 	- Allow placing the global command anywhere in the script
 	- Implement required ManageSieve behavior
diff --git a/src/lib-sieve/plugins/include/cmd-include.c b/src/lib-sieve/plugins/include/cmd-include.c
index 473c9e6c0..4cfc4b96c 100644
--- a/src/lib-sieve/plugins/include/cmd-include.c
+++ b/src/lib-sieve/plugins/include/cmd-include.c
@@ -226,9 +226,9 @@ static bool cmd_include_validate
 
 	script_name = sieve_ast_argument_strc(arg);
 
-	if ( strchr(script_name, '/') != NULL ) {
+	if ( !sieve_script_name_is_valid(script_name) ) {
  		sieve_argument_validate_error(valdtr, arg,
-			"include: '/' not allowed in script name (%s)",
+			"include: invalid script name '%s'",
 			str_sanitize(script_name, 80));
 		return FALSE;
 	}
diff --git a/src/lib-sieve/sieve-script.c b/src/lib-sieve/sieve-script.c
index 3d41d8f79..bda41a77b 100644
--- a/src/lib-sieve/sieve-script.c
+++ b/src/lib-sieve/sieve-script.c
@@ -3,6 +3,8 @@
 
 #include "lib.h"
 #include "compat.h"
+#include "unichar.h"
+#include "array.h"
 #include "istream.h"
 #include "eacces-error.h"
 
@@ -21,6 +23,52 @@
  
 #define SIEVE_READ_BLOCK_SIZE (1024*8)
 
+/*
+ * Script name
+ */
+
+bool sieve_script_name_is_valid(const char *scriptname)
+{
+	ARRAY_TYPE(unichars) uni_name;
+	unsigned int count, i;
+	const unichar_t *name_chars;
+
+	/* Intialize array for unicode characters */
+	t_array_init(&uni_name, strlen(scriptname)* 4);
+
+	/* Convert UTF-8 to UCS4/UTF-32 */
+	if ( uni_utf8_to_ucs4(scriptname, &uni_name) < 0 )
+		return FALSE;
+
+	/* Scan name for invalid characters */
+	name_chars = array_get(&uni_name, &count);
+	for ( i = 0; i < count; i++ ) {
+
+		/* 0000-001F; [CONTROL CHARACTERS] */
+		if ( name_chars[i] <= 0x001f )
+			return FALSE;
+		
+		/* 002F; SLASH */
+		if ( name_chars[i] == 0x002f )
+			return FALSE;
+
+		/* 007F; DELETE */
+		if ( name_chars[i] == 0x007f )
+			return FALSE;
+
+		/* 0080-009F; [CONTROL CHARACTERS] */
+		if ( name_chars[i] >= 0x0080 && name_chars[i] <= 0x009f )
+			return FALSE;
+
+		/* 2028; LINE SEPARATOR */
+		/* 2029; PARAGRAPH SEPARATOR */
+		if ( name_chars[i] == 0x2028 || name_chars[i] == 0x2029 )
+			return FALSE;
+	}
+
+	return TRUE;
+}
+
 /*
  * Filename to name/name to filename
  */
diff --git a/src/lib-sieve/sieve-script.h b/src/lib-sieve/sieve-script.h
index 2970e5fa4..ebd8bc0e4 100644
--- a/src/lib-sieve/sieve-script.h
+++ b/src/lib-sieve/sieve-script.h
@@ -8,6 +8,13 @@
 
 #include <sys/types.h>
 
+
+/*
+ * Sieve script name
+ */
+
+bool sieve_script_name_is_valid(const char *scriptname);
+
 /*
  * Sieve script object
  */
-- 
GitLab