From b01bd7c9eb6f06dbe91d2a32d4fcd7b784267e21 Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan@rename-it.nl>
Date: Sat, 8 Dec 2007 13:13:26 +0100
Subject: [PATCH] Properly implemented circular include detection for the
 include extension.

---
 src/lib-sieve/plugins/include/cmd-include.c   | 10 +----
 .../plugins/include/ext-include-common.c      | 21 +++++++---
 .../plugins/include/ext-include-common.h      |  4 +-
 src/lib-sieve/plugins/include/included3.sieve |  5 ++-
 src/lib-sieve/sieve-lexer.c                   |  2 +-
 src/lib-sieve/sieve-script.c                  | 42 ++++++++++++++-----
 src/lib-sieve/sieve-script.h                  |  6 +--
 src/lib-sieve/sieve.c                         |  3 +-
 8 files changed, 61 insertions(+), 32 deletions(-)

diff --git a/src/lib-sieve/plugins/include/cmd-include.c b/src/lib-sieve/plugins/include/cmd-include.c
index cffd608dc..40ae8c8ed 100644
--- a/src/lib-sieve/plugins/include/cmd-include.c
+++ b/src/lib-sieve/plugins/include/cmd-include.c
@@ -162,7 +162,6 @@ static bool cmd_include_validate(struct sieve_validator *validator,
 	struct cmd_include_context_data *ctx_data = 
 		(struct cmd_include_context_data *) cmd->data;
 	const char *script_name, *script_path;
-	struct sieve_script *script;
 	struct sieve_ast *ast;
 
 	if ( !sieve_validate_positional_argument
@@ -185,17 +184,12 @@ static bool cmd_include_validate(struct sieve_validator *validator,
 	else 
 		return FALSE;
 
-	script = sieve_script_create(script_path, script_name);
-
 	/* Validate */
 	if ( !ext_include_validate_include
-		(validator, cmd, script, &ast) ) {
-		sieve_script_unref(&script);
+		(validator, cmd, script_path, script_name, &ast) ) {
  		return FALSE;
  	}
- 	
- 	sieve_script_unref(&script);
- 	
+ 	 	
  	ctx_data->ast = ast;
 	sieve_validator_argument_activate(validator, arg);	
 	
diff --git a/src/lib-sieve/plugins/include/ext-include-common.c b/src/lib-sieve/plugins/include/ext-include-common.c
index 4e6394ffa..f9bfda0b6 100644
--- a/src/lib-sieve/plugins/include/ext-include-common.c
+++ b/src/lib-sieve/plugins/include/ext-include-common.c
@@ -70,9 +70,10 @@ void ext_include_register_validator_context
 
 bool ext_include_validate_include
 (struct sieve_validator *validator, struct sieve_command_context *cmd,
-	struct sieve_script *script, struct sieve_ast **ast_r)
+	const char *script_path, const char *script_name, struct sieve_ast **ast_r)
 {
 	bool result = TRUE;
+	struct sieve_script *script;
 	struct sieve_validator *subvalid; 
 	struct ext_include_validator_context *parent =
 		ext_include_get_validator_context(validator);
@@ -80,6 +81,11 @@ bool ext_include_validate_include
 	struct sieve_error_handler *ehandler = 
 		sieve_validator_get_error_handler(validator);
 	
+	/* Create script object */
+	if ( (script = sieve_script_create(script_path, script_name, ehandler)) 
+		== NULL )
+		return FALSE;
+	
 	*ast_r = NULL;
 	
 	/* Check for circular include */
@@ -89,21 +95,26 @@ bool ext_include_validate_include
 		if ( sieve_script_equals(ctx->script, script) ) {
 			sieve_command_validate_error
 				(validator, cmd, "circular include");
+				
+			sieve_script_unref(&script);
 			return FALSE;
 		}
 		
 		ctx = ctx->parent;
-	}
+	}	
 			
 	/* Parse script */
 	
 	if ( (*ast_r = sieve_parse(script, ehandler)) == NULL ) {
  		sieve_command_validate_error
- 			(validator, cmd, "parse failed for included script '%s'", 
- 				sieve_script_name(script));
+ 			(validator, cmd, "parse failed for included script '%s'", script_name);
+		sieve_script_unref(&script);
 		return FALSE;
 	}
 	
+	/* AST now holds a reference, so we can drop it already */
+	sieve_script_unref(&script);
+	
 	/* Validate script */
 
 	subvalid = sieve_validator_create(*ast_r, ehandler);	
@@ -113,7 +124,7 @@ bool ext_include_validate_include
 	if ( !sieve_validator_run(subvalid) || sieve_get_errors(ehandler) > 0 ) {
 		sieve_command_validate_error
 			(validator, cmd, "validation failed for included script '%s'", 
-				sieve_script_name(script));
+				script_name);
 		sieve_ast_unref(ast_r);
 		result = FALSE;
 	}
diff --git a/src/lib-sieve/plugins/include/ext-include-common.h b/src/lib-sieve/plugins/include/ext-include-common.h
index f7e89a3fa..b4f1d51c2 100644
--- a/src/lib-sieve/plugins/include/ext-include-common.h
+++ b/src/lib-sieve/plugins/include/ext-include-common.h
@@ -29,7 +29,7 @@ void ext_include_register_validator_context
 	(struct sieve_validator *validator, struct sieve_script *script);
 
 bool ext_include_validate_include
-(struct sieve_validator *validator, struct sieve_command_context *cmd,
-	struct sieve_script *script, struct sieve_ast **ast_r);
+	(struct sieve_validator *validator, struct sieve_command_context *cmd,
+		const char *script_path, const char *script_name, struct sieve_ast **ast_r);
 
 #endif /* __EXT_INCLUDE_COMMON_H */
diff --git a/src/lib-sieve/plugins/include/included3.sieve b/src/lib-sieve/plugins/include/included3.sieve
index 08a6621ed..720364ed5 100644
--- a/src/lib-sieve/plugins/include/included3.sieve
+++ b/src/lib-sieve/plugins/include/included3.sieve
@@ -1 +1,4 @@
-discard
+require "include";
+
+include "include";
+discard;
diff --git a/src/lib-sieve/sieve-lexer.c b/src/lib-sieve/sieve-lexer.c
index f6e87ac23..db4285073 100644
--- a/src/lib-sieve/sieve-lexer.c
+++ b/src/lib-sieve/sieve-lexer.c
@@ -80,7 +80,7 @@ struct sieve_lexer *sieve_lexer_create
 	struct sieve_lexer *lexer;
 	struct istream *stream;
 	
-	stream = sieve_script_open(script, ehandler);
+	stream = sieve_script_open(script);
 	if ( stream == NULL )
 		return NULL;
 	
diff --git a/src/lib-sieve/sieve-script.c b/src/lib-sieve/sieve-script.c
index 55ba5fa39..3c472e939 100644
--- a/src/lib-sieve/sieve-script.c
+++ b/src/lib-sieve/sieve-script.c
@@ -13,6 +13,10 @@ struct sieve_script {
 	pool_t pool;
 	unsigned int refcount;
 	
+	struct stat st;
+
+	struct sieve_error_handler *ehandler;
+		
 	/* Parameters */
 	const char *name;
 	const char *path;	
@@ -25,17 +29,32 @@ struct sieve_script {
 /* Script object */
 
 struct sieve_script *sieve_script_create
-	(const char *path, const char *name)
+	(const char *path, const char *name, struct sieve_error_handler *ehandler)
 {
 	pool_t pool;
+	struct stat st;
 	struct sieve_script *script;
 	
+	/* First obtain stat data from the system */
+	
+	if ( stat(path, &st) < 0 ) {
+		if ( errno == ENOENT )
+			sieve_error(ehandler, name, "sieve script does not exist");
+		else 
+			sieve_critical(ehandler, path, "failed to stat sieve script: %m");
+		return NULL;
+	}
+	
+	/* Only create object if it stat()s without problems */
+	
 	pool = pool_alloconly_create("sieve_script", 1024);
 	script = p_new(pool, struct sieve_script, 1);
 	script->pool = pool;
 	script->refcount = 1;
+	script->ehandler = ehandler;
 	
-	script->path = p_strdup(pool, path);
+	memcpy((void *) &script->st, (void *) &st, sizeof(st));
+	script->path = p_strdup(pool, path);	
 		
 	if ( name == NULL || *name == '\0' ) {
 		const char *filename, *ext;
@@ -84,17 +103,18 @@ void sieve_script_unref(struct sieve_script **script)
 
 /* Stream manageement */
 
-struct istream *sieve_script_open(struct sieve_script *script, 
-	struct sieve_error_handler *ehandler)
+struct istream *sieve_script_open(struct sieve_script *script)
 {
 	int fd;
 
 	if ( (fd=open(script->path, O_RDONLY)) < 0 ) {
-		if ( errno == ENOENT )
-			sieve_error(ehandler, script->path, "sieve script '%s' does not exist",
-				script->name);
-		else 
-			sieve_critical(ehandler, script->path, "failed to open sieve script: %m");
+		if ( errno == ENOENT ) 
+			/* Not supposed to occur, create() does stat already */
+			sieve_error(script->ehandler, script->name, 
+				"sieve script '%s' does not exist", script->name);
+		else
+			sieve_critical(script->ehandler, script->path, 
+				"failed to open sieve script: %m");
 		return NULL;
 	}	
 
@@ -112,8 +132,8 @@ void sieve_script_close(struct sieve_script *script)
 
 bool sieve_script_equals
 (struct sieve_script *script1, struct sieve_script *script2)
-{
-	return ( strcmp(script1->path, script2->path) == 0 );
+{	
+	return ( script1->st.st_ino == script2->st.st_ino );
 }
 
 /* Inline accessors */
diff --git a/src/lib-sieve/sieve-script.h b/src/lib-sieve/sieve-script.h
index 1266d1757..44ffb8ca4 100644
--- a/src/lib-sieve/sieve-script.h
+++ b/src/lib-sieve/sieve-script.h
@@ -7,15 +7,15 @@
 
 struct sieve_script;
 
-struct sieve_script *sieve_script_create(const char *path, const char *name);
+struct sieve_script *sieve_script_create
+	(const char *path, const char *name, struct sieve_error_handler *ehandler);
 
 void sieve_script_ref(struct sieve_script *script);
 void sieve_script_unref(struct sieve_script **script);
 
 /* Stream manageement */
 
-struct istream *sieve_script_open(struct sieve_script *script, 
-	struct sieve_error_handler *ehandler);
+struct istream *sieve_script_open(struct sieve_script *script);
 void sieve_script_close(struct sieve_script *script);
 
 bool sieve_script_equals
diff --git a/src/lib-sieve/sieve.c b/src/lib-sieve/sieve.c
index ebbbd89d0..42cd6fee4 100644
--- a/src/lib-sieve/sieve.c
+++ b/src/lib-sieve/sieve.c
@@ -125,7 +125,8 @@ struct sieve_binary *sieve_compile
 	struct sieve_script *script;
 	struct sieve_binary *sbin;
 
-	script = sieve_script_create(script_path, NULL);
+	if ( (script = sieve_script_create(script_path, NULL, ehandler)) == NULL )
+		return NULL;
 	
 	sbin = sieve_compile_script(script, ehandler);
 	
-- 
GitLab