From 2f3c95e53da0eb7a03be3ef7df252ff5740fe625 Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan@rename-it.nl>
Date: Tue, 12 Aug 2008 19:51:56 +0200
Subject: [PATCH] Limited number of accepted match values

---
 TODO                                      |  4 +-
 src/lib-sieve/mcht-matches.c              | 86 ++++++++++++++---------
 src/lib-sieve/plugins/include/Makefile.am |  1 +
 src/lib-sieve/plugins/regex/mcht-regex.c  | 13 ++--
 src/lib-sieve/sieve-limits.h              |  6 ++
 src/lib-sieve/sieve-match-types.c         |  6 +-
 6 files changed, 77 insertions(+), 39 deletions(-)

diff --git a/TODO b/TODO
index 4c81eb74f..173e90f02 100644
--- a/TODO
+++ b/TODO
@@ -9,8 +9,8 @@ Next (in order of descending priority/precedence):
 	- Imapflags: when keep/fileinto is used multiple times in a script and
 	  duplicate message elimination is performed, the last flag list value
 	  MUST win.
-	- If an address is not syntactically valid, then it will not be matched
-	  by tests specifying ":localpart" or ":domain".
+	- 'If an address is not syntactically valid, then it will not be matched
+	  by tests specifying ":localpart" or ":domain"'.
 * Code cleanup 
 * Full security review. Enforce limits on number of created objects, script 
   size, execution time, etc...
diff --git a/src/lib-sieve/mcht-matches.c b/src/lib-sieve/mcht-matches.c
index aa070174e..fd565ada7 100644
--- a/src/lib-sieve/mcht-matches.c
+++ b/src/lib-sieve/mcht-matches.c
@@ -86,7 +86,8 @@ static int mcht_matches_match
 {
 	const struct sieve_comparator *cmp = mctx->comparator;
 	struct sieve_match_values *mvalues;
-	string_t *mvalue, *mchars, *section, *subsection;
+	string_t *mvalue = NULL, *mchars = NULL;
+	string_t *section, *subsection;
 	const char *vend, *kend, *vp, *kp, *wp, *pvp;
 	bool backtrack = FALSE; /* TRUE: match of '?'-connected sections failed */
 	char wcard = '\0';      /* Current wildcard */
@@ -98,8 +99,6 @@ static int mcht_matches_match
 		val_size = 0;
 	}
 	
-	mvalue = t_str_new(32);     /* Match value (*) */
-	mchars = t_str_new(32);     /* Match characters (.?..?.??) */
 	section = t_str_new(32);    /* Section (after beginning or *) */
 	subsection = t_str_new(32); /* Sub-section (after ?) */
 	
@@ -109,11 +108,15 @@ static int mcht_matches_match
 	kp = key;                   /* Key pointer */
 	wp = key;                   /* Wildcard (key) pointer */
 	pvp = val;                  /* Previous value Pointer */
-	
-	/* Reset match values list */
-	mvalues = sieve_match_values_start(mctx->interp);
-	sieve_match_values_add(mvalues, NULL);
 
+	/* Start new match values list */
+	if ( (mvalues = sieve_match_values_start(mctx->interp)) != NULL ) {
+		sieve_match_values_add(mvalues, NULL);
+
+		mvalue = t_str_new(32);     /* Match value (*) */
+		mchars = t_str_new(32);     /* Match characters (.?..?.??) */
+	}
+	
 	/* Match the pattern: 
 	 *   <pattern> = <section>*<section>*<section>....
 	 *   <section> = [text]?[text]?[text].... 
@@ -153,8 +156,9 @@ static int mcht_matches_match
 			
 			debug_printf("found wildcard '%c' at pos [%d]\n", 
 				next_wcard, (int) (wp-key));
-				
-			str_truncate(mvalue, 0);
+	
+			if ( mvalues != NULL )			
+				str_truncate(mvalue, 0);
 		} else {
 			debug_printf("backtracked");
 			backtrack = FALSE;
@@ -183,16 +187,20 @@ static int mcht_matches_match
 			vp = PTR_OFFSET(vend, -str_len(section));
 			qend = vp;
 			qp = vp - key_offset;
-			str_append_n(mvalue, pvp, qp-pvp);
+		
+			if ( mvalues != NULL )
+				str_append_n(mvalue, pvp, qp-pvp);
 					
 			if ( !cmp->char_match(cmp, &vp, vend, &needle, nend) ) {	
 				debug_printf("  match at end failed\n");				 
 				break;
 			}
 			
-			sieve_match_values_add(mvalues, mvalue);
-			for ( ; qp < qend; qp++ )
-				sieve_match_values_add_char(mvalues, *qp); 
+			if ( mvalues != NULL ) {
+				sieve_match_values_add(mvalues, mvalue);
+				for ( ; qp < qend; qp++ )
+					sieve_match_values_add_char(mvalues, *qp); 
+			}
 
 			kp = kend;
 			vp = vend;
@@ -203,8 +211,9 @@ static int mcht_matches_match
 			const char *prk = NULL;
 			const char *prw = NULL;
 			const char *chars;
-		
-			str_truncate(mchars, 0);
+
+			if ( mvalues != NULL )		
+				str_truncate(mchars, 0);
 							
 			if ( wcard == '\0' ) {
 				/* Match needs to happen right at the beginning */
@@ -234,9 +243,12 @@ static int mcht_matches_match
 				
 				qend = vp - str_len(section);
 				qp = qend - key_offset;
-				str_append_n(mvalue, pvp, qp-pvp);
-				for ( ; qp < qend; qp++ )
-					str_append_c(mchars, *qp);
+
+				if ( mvalues != NULL ) {
+					str_append_n(mvalue, pvp, qp-pvp);
+					for ( ; qp < qend; qp++ )
+						str_append_c(mchars, *qp);
+				}
 			}
 			
 			if ( wp < kend ) wp++;
@@ -246,7 +258,8 @@ static int mcht_matches_match
 				debug_printf("next_wcard = '?'; need to match arbitrary character\n");
 				
 				/* Add match value */ 
-				str_append_c(mchars, *vp);
+				if ( mvalues != NULL )
+					str_append_c(mchars, *vp);
 				vp++;
 				
 				next_wcard = _scan_key_section(subsection, &wp, kend);
@@ -268,7 +281,8 @@ static int mcht_matches_match
 						kp = prk;
 						wp = prw;
 				
-						str_append_c(mvalue, *vp);
+						if ( mvalues != NULL )
+							str_append_c(mvalue, *vp);
 						vp++;
 				
 						wcard = '*';
@@ -292,11 +306,13 @@ static int mcht_matches_match
 					break;
 				}
 				
-				if ( prv != NULL )
-					sieve_match_values_add(mvalues, mvalue);
-				chars = (const char *) str_data(mchars);
-				for ( i = 0; i < str_len(mchars); i++ ) {
-					sieve_match_values_add_char(mvalues, chars[i]);
+				if ( mvalues != NULL ) {
+					if ( prv != NULL )
+						sieve_match_values_add(mvalues, mvalue);
+					chars = (const char *) str_data(mchars);
+					for ( i = 0; i < str_len(mchars); i++ ) {
+						sieve_match_values_add_char(mvalues, chars[i]);
+					}
 				}
 
 				if ( next_wcard != '*' ) {
@@ -310,11 +326,15 @@ static int mcht_matches_match
 		 * (avoid scanning the rest of the string)
 		 */
 		if ( kp == kend && next_wcard == '*' ) {
-			str_truncate(mvalue, 0);
-			str_append_n(mvalue, vp, vend-vp);
-			sieve_match_values_add(mvalues, mvalue);
+			if ( mvalues != NULL ) {
+				str_truncate(mvalue, 0);
+				str_append_n(mvalue, vp, vend-vp);
+				sieve_match_values_add(mvalues, mvalue);
+			}
+		
 			kp = kend;
 			vp = vend;
+		
 			debug_printf("key ends with '*'\n");
 			break;
 		}			
@@ -325,7 +345,7 @@ static int mcht_matches_match
 	debug_printf("=== Finish ===\n");
 	debug_printf("  result: %s\n", (kp == kend && vp == vend) ? "true" : "false");
 
-	/* Eat away a trailing series of *rs */
+	/* Eat away a trailing series of *s */
 	if ( vp == vend ) {
 		while ( kp < kend && *kp == '*' ) kp++;
 	}
@@ -334,9 +354,11 @@ static int mcht_matches_match
 	 * are exhausted.
 	 */
 	if (kp == kend && vp == vend) {
-		string_t *matched = str_new_const(pool_datastack_create(), val, val_size);
-		sieve_match_values_set(mvalues, 0, matched);
-		sieve_match_values_commit(mctx->interp, &mvalues);
+		if ( mvalues != NULL ) {
+			string_t *matched = str_new_const(pool_datastack_create(), val, val_size);
+			sieve_match_values_set(mvalues, 0, matched);
+			sieve_match_values_commit(mctx->interp, &mvalues);
+		}
 		return TRUE;
 	}
 
diff --git a/src/lib-sieve/plugins/include/Makefile.am b/src/lib-sieve/plugins/include/Makefile.am
index 44236db11..7d8805f50 100644
--- a/src/lib-sieve/plugins/include/Makefile.am
+++ b/src/lib-sieve/plugins/include/Makefile.am
@@ -22,5 +22,6 @@ libsieve_ext_include_la_SOURCES = \
 
 noinst_HEADERS = \
 	ext-include-common.h \
+	ext-include-limits.h \
 	ext-include-binary.h \
 	ext-include-variables.h
diff --git a/src/lib-sieve/plugins/regex/mcht-regex.c b/src/lib-sieve/plugins/regex/mcht-regex.c
index bfd98e4df..fa0501836 100644
--- a/src/lib-sieve/plugins/regex/mcht-regex.c
+++ b/src/lib-sieve/plugins/regex/mcht-regex.c
@@ -8,6 +8,7 @@
 #include "str.h"
 
 #include "sieve-common.h"
+#include "sieve-limits.h"
 #include "sieve-ast.h"
 #include "sieve-commands.h"
 #include "sieve-validator.h"
@@ -25,7 +26,7 @@
  * Configuration
  */
 
-#define MCHT_REGEX_MAX_SUBSTITUTIONS 64
+#define MCHT_REGEX_MAX_SUBSTITUTIONS SIEVE_MAX_MATCH_VALUES
 /* 
  * Forward declarations 
  */
@@ -240,14 +241,17 @@ static int mcht_regex_match
 
 	if ( key_index == 0 ) ctx->value_index++;
 
-	regexp = mcht_regex_get(ctx, mctx->comparator, key, key_index);
-	 
+	if ( (regexp=mcht_regex_get(ctx, mctx->comparator, key, key_index)) == NULL )
+		return FALSE;
+
 	if ( regexec(regexp, val, ctx->nmatch, ctx->pmatch, 0) == 0 ) {
 		size_t i;
 		int skipped = 0;
 		string_t *subst = t_str_new(32);
 		struct sieve_match_values *mvalues = sieve_match_values_start(mctx->interp);
-		
+
+		i_assert( mvalues != NULL );
+
 		for ( i = 0; i < ctx->nmatch; i++ ) {
 			str_truncate(subst, 0);
 			
@@ -261,6 +265,7 @@ static int mcht_regex_match
 			} else 
 				skipped++;
 		}
+
 		sieve_match_values_commit(mctx->interp, &mvalues);
 		return TRUE;
 	}
diff --git a/src/lib-sieve/sieve-limits.h b/src/lib-sieve/sieve-limits.h
index d3426ca4f..18b2437b1 100644
--- a/src/lib-sieve/sieve-limits.h
+++ b/src/lib-sieve/sieve-limits.h
@@ -16,6 +16,12 @@
 #define SIEVE_MAX_BLOCK_NESTING     32
 #define SIEVE_MAX_TEST_NESTING      32
 
+/*
+ * Runtime
+ */
+
+#define SIEVE_MAX_MATCH_VALUES      32
+
 /*
  * Actions
  */
diff --git a/src/lib-sieve/sieve-match-types.c b/src/lib-sieve/sieve-match-types.c
index 731ac411d..287fc6158 100644
--- a/src/lib-sieve/sieve-match-types.c
+++ b/src/lib-sieve/sieve-match-types.c
@@ -6,6 +6,8 @@
 #include "hash.h"
 #include "array.h"
 
+#include "sieve-common.h"
+#include "sieve-limits.h"
 #include "sieve-extensions.h"
 #include "sieve-commands.h"
 #include "sieve-code.h"
@@ -207,6 +209,8 @@ static string_t *sieve_match_values_add_entry
 	string_t *entry;
 	
 	if ( mvalues == NULL ) return NULL;	
+
+	if ( mvalues->count >= SIEVE_MAX_MATCH_VALUES ) return NULL;
 		
 	if ( mvalues->count >= array_count(&mvalues->values) ) {
 		entry = str_new(mvalues->pool, 64);
@@ -225,7 +229,7 @@ static string_t *sieve_match_values_add_entry
 void sieve_match_values_set
 (struct sieve_match_values *mvalues, unsigned int index, string_t *value)
 {
-	if ( mvalues != NULL ) {
+	if ( mvalues != NULL && index < array_count(&mvalues->values) ) {
 		string_t * const *ep = array_idx(&mvalues->values, index);
     	string_t *entry = *ep;
 
-- 
GitLab