diff --git a/src/lib-sieve/plugins/include/cmd-include.c b/src/lib-sieve/plugins/include/cmd-include.c index d6331a599f39f18b7af18dc23799ce4292bad932..a76477b571f164ef84e4cea8e8c991b25cc9b96b 100644 --- a/src/lib-sieve/plugins/include/cmd-include.c +++ b/src/lib-sieve/plugins/include/cmd-include.c @@ -12,6 +12,7 @@ #include "sieve-dump.h" #include "ext-include-common.h" +#include "ext-include-binary.h" /* * Include command @@ -213,17 +214,17 @@ static bool cmd_include_generate { struct cmd_include_context_data *ctx_data = (struct cmd_include_context_data *) cmd->data; - unsigned int block_id; + const struct ext_include_script_info *included; /* Compile (if necessary) and include the script into the binary. * This yields the id of the binary block containing the compiled byte code. */ if ( !ext_include_generate_include - (cgenv, cmd, ctx_data->location, ctx_data->script, &block_id) ) + (cgenv, cmd, ctx_data->location, ctx_data->script, &included) ) return FALSE; sieve_operation_emit_code(cgenv->sbin, &include_operation); - sieve_binary_emit_offset(cgenv->sbin, block_id); + sieve_binary_emit_offset(cgenv->sbin, included->id); return TRUE; } @@ -236,12 +237,18 @@ static bool opc_include_dump (const struct sieve_operation *op ATTR_UNUSED, const struct sieve_dumptime_env *denv, sieve_size_t *address) { - int block; + const struct ext_include_script_info *included; + int include_id; - if ( !sieve_binary_read_offset(denv->sbin, address, &block) ) + if ( !sieve_binary_read_offset(denv->sbin, address, &include_id) ) + return FALSE; + + included = ext_include_binary_script_get_included(denv->sbin, include_id); + if ( included == NULL ) return FALSE; - sieve_code_dumpf(denv, "INCLUDE [BLOCK: %d]", block); + sieve_code_dumpf(denv, "INCLUDE %s [ID: %d, BLOCK: %d]", + sieve_script_name(included->script), include_id, included->block_id); return TRUE; } @@ -254,16 +261,14 @@ static int opc_include_execute (const struct sieve_operation *op ATTR_UNUSED, const struct sieve_runtime_env *renv, sieve_size_t *address) { - int block; + int include_id; - if ( !sieve_binary_read_offset(renv->sbin, address, &block) ) { - sieve_runtime_trace_error(renv, "invalid block operand"); + if ( !sieve_binary_read_offset(renv->sbin, address, &include_id) ) { + sieve_runtime_trace_error(renv, "invalid include-id operand"); return SIEVE_EXEC_BIN_CORRUPT; } - sieve_runtime_trace(renv, "INCLUDE command (BLOCK: %d)", block); - - return ext_include_execute_include(renv, (unsigned int) block); + return ext_include_execute_include(renv, (unsigned int) include_id); } diff --git a/src/lib-sieve/plugins/include/ext-include-binary.c b/src/lib-sieve/plugins/include/ext-include-binary.c index 202bdc209ee560bd62dbbc6937bc3d9d80b2de57..9ce2770405ba547d195c2a3da59eecff05f54083 100644 --- a/src/lib-sieve/plugins/include/ext-include-binary.c +++ b/src/lib-sieve/plugins/include/ext-include-binary.c @@ -19,18 +19,13 @@ * Types */ -struct _included_script { - struct sieve_script *script; - enum ext_include_script_location location; - - unsigned int block_id; -}; - struct ext_include_binary_context { struct sieve_binary *binary; unsigned int dependency_block; struct hash_table *included_scripts; + ARRAY_DEFINE(include_index, struct ext_include_script_info *); + struct sieve_variable_scope *global_vars; }; @@ -71,6 +66,7 @@ static struct ext_include_binary_context *ext_include_binary_create_context ctx->included_scripts = hash_create(default_pool, pool, 0, (hash_callback_t *) sieve_script_hash, (hash_cmp_callback_t *) sieve_script_cmp); + p_array_init(&ctx->include_index, pool, 128); return ctx; } @@ -116,14 +112,19 @@ struct ext_include_binary_context *ext_include_binary_init return ctx; } -void ext_include_binary_script_include +/* + * Script inclusion + */ + +const struct ext_include_script_info *ext_include_binary_script_include (struct ext_include_binary_context *binctx, struct sieve_script *script, enum ext_include_script_location location, unsigned int block_id) { pool_t pool = sieve_binary_pool(binctx->binary); - struct _included_script *incscript; + struct ext_include_script_info *incscript; - incscript = p_new(pool, struct _included_script, 1); + incscript = p_new(pool, struct ext_include_script_info, 1); + incscript->id = array_count(&binctx->include_index); incscript->script = script; incscript->location = location; incscript->block_id = block_id; @@ -132,39 +133,64 @@ void ext_include_binary_script_include sieve_script_ref(script); hash_insert(binctx->included_scripts, (void *) script, (void *) incscript); + array_append(&binctx->include_index, &incscript, 1); + + return incscript; } bool ext_include_binary_script_is_included (struct ext_include_binary_context *binctx, struct sieve_script *script, - unsigned int *block_id) + const struct ext_include_script_info **script_info_r) { - struct _included_script *incscript = (struct _included_script *) + struct ext_include_script_info *incscript = (struct ext_include_script_info *) hash_lookup(binctx->included_scripts, script); if ( incscript == 0 ) return FALSE; - *block_id = incscript->block_id; + *script_info_r = incscript; return TRUE; } +const struct ext_include_script_info *ext_include_binary_script_get_included +(struct sieve_binary *sbin, unsigned int include_id) +{ + struct ext_include_binary_context *binctx = + ext_include_binary_get_context(sbin); + + if ( include_id < array_count(&binctx->include_index) ) { + struct ext_include_script_info *const *sinfo = + array_idx(&binctx->include_index, include_id); + + return *sinfo; + } + + return NULL; +} + +/* + * Binary extension + */ + static bool ext_include_binary_save(struct sieve_binary *sbin) { struct ext_include_binary_context *binctx = ext_include_binary_get_context(sbin); - struct hash_iterate_context *hctx = - hash_iterate_init(binctx->included_scripts); - void *key, *value; + struct ext_include_script_info *const *scripts; + unsigned int script_count, i; unsigned int prvblk; bool result = TRUE; sieve_binary_block_clear(sbin, binctx->dependency_block); if ( !sieve_binary_block_set_active(sbin, binctx->dependency_block, &prvblk) ) return FALSE; - - sieve_binary_emit_integer(sbin, hash_count(binctx->included_scripts)); - while ( hash_iterate(hctx, &key, &value) ) { - struct _included_script *incscript = (struct _included_script *) value; + + scripts = array_get(&binctx->include_index, &script_count); + + sieve_binary_emit_integer(sbin, script_count); + + for ( i = 0; i < script_count; i++ ) { + struct ext_include_script_info *incscript = scripts[i]; sieve_binary_emit_integer(sbin, incscript->block_id); sieve_binary_emit_byte(sbin, incscript->location); @@ -175,8 +201,6 @@ static bool ext_include_binary_save(struct sieve_binary *sbin) (void) sieve_binary_block_set_active(sbin, prvblk, NULL); - hash_iterate_deinit(&hctx); - return result; } @@ -236,7 +260,7 @@ static bool ext_include_binary_open(struct sieve_binary *sbin) return FALSE; } - ext_include_binary_script_include(binctx, script, location, block_id); + (void)ext_include_binary_script_include(binctx, script, location, block_id); sieve_script_unref(&script); } @@ -260,7 +284,7 @@ static bool ext_include_binary_up_to_date(struct sieve_binary *sbin) /* Release references to all included script objects */ hctx = hash_iterate_init(binctx->included_scripts); while ( hash_iterate(hctx, &key, &value) ) { - struct _included_script *incscript = (struct _included_script *) value; + struct ext_include_script_info *incscript = (struct ext_include_script_info *) value; /* Is the binary newer than this dependency? */ if ( !sieve_binary_script_older(sbin, incscript->script) ) { @@ -283,7 +307,7 @@ static void ext_include_binary_free(struct sieve_binary *sbin) /* Release references to all included script objects */ hctx = hash_iterate_init(binctx->included_scripts); while ( hash_iterate(hctx, &key, &value) ) { - struct _included_script *incscript = (struct _included_script *) value; + struct ext_include_script_info *incscript = (struct ext_include_script_info *) value; sieve_script_unref(&incscript->script); } @@ -325,7 +349,7 @@ bool ext_include_binary_dump(struct sieve_dumptime_env *denv) hctx = hash_iterate_init(binctx->included_scripts); while ( hash_iterate(hctx, &key, &value) ) { - struct _included_script *incscript = (struct _included_script *) value; + struct ext_include_script_info *incscript = (struct ext_include_script_info *) value; sieve_binary_dump_sectionf(denv, "Included %s script '%s' (block: %d)", _script_location(incscript->location), diff --git a/src/lib-sieve/plugins/include/ext-include-binary.h b/src/lib-sieve/plugins/include/ext-include-binary.h index 36c27306c9e1a43e4b8901e0c2358a7e2a49c33c..06c7bbcb84a9daacd4abbc5f22a98274bab613cf 100644 --- a/src/lib-sieve/plugins/include/ext-include-binary.h +++ b/src/lib-sieve/plugins/include/ext-include-binary.h @@ -8,12 +8,27 @@ struct ext_include_binary_context; struct ext_include_binary_context *ext_include_binary_init (struct sieve_binary *sbin, struct sieve_ast *ast); -void ext_include_binary_script_include +/* + * Including scripts + */ + +struct ext_include_script_info { + unsigned int id; + + struct sieve_script *script; + enum ext_include_script_location location; + + unsigned int block_id; +}; + +const struct ext_include_script_info *ext_include_binary_script_include (struct ext_include_binary_context *binctx, struct sieve_script *script, enum ext_include_script_location location, unsigned int block_id); bool ext_include_binary_script_is_included (struct ext_include_binary_context *binctx, struct sieve_script *script, - unsigned int *block_id); + const struct ext_include_script_info **script_info_r); +const struct ext_include_script_info *ext_include_binary_script_get_included + (struct sieve_binary *sbin, unsigned int include_id); bool ext_include_binary_dump(struct sieve_dumptime_env *denv); diff --git a/src/lib-sieve/plugins/include/ext-include-common.c b/src/lib-sieve/plugins/include/ext-include-common.c index 86a676652137dd0485dff763ad2b1961837bafa3..184d3907d3eff8accf7f28b083baf8fdaaa4d81b 100644 --- a/src/lib-sieve/plugins/include/ext-include-common.c +++ b/src/lib-sieve/plugins/include/ext-include-common.c @@ -284,7 +284,7 @@ void ext_include_interpreter_context_init bool ext_include_generate_include (const struct sieve_codegen_env *cgenv, struct sieve_command_context *cmd, enum ext_include_script_location location, struct sieve_script *script, - unsigned *blk_id_r) + const struct ext_include_script_info **included_r) { bool result = TRUE; struct sieve_ast *ast; @@ -296,9 +296,9 @@ bool ext_include_generate_include ext_include_get_generator_context(gentr); struct ext_include_generator_context *pctx; struct sieve_error_handler *ehandler = sieve_generator_error_handler(gentr); - unsigned this_block_id, inc_block_id; + const struct ext_include_script_info *included; - *blk_id_r = 0; + *included_r = NULL; /* Just to be sure: do not include more scripts when errors have occured * already. @@ -330,14 +330,16 @@ bool ext_include_generate_include binctx = ext_include_binary_init(sbin, cgenv->ast); /* Is the script already compiled into the current binary? */ - if ( !ext_include_binary_script_is_included(binctx, script, &inc_block_id) ) + if ( !ext_include_binary_script_is_included(binctx, script, &included) ) { + unsigned int inc_block_id, this_block_id; const char *script_name = sieve_script_name(script); /* No, allocate a new block in the binary and mark the script as included. */ inc_block_id = sieve_binary_block_create(sbin); - ext_include_binary_script_include(binctx, script, location, inc_block_id); + included = ext_include_binary_script_include + (binctx, script, location, inc_block_id); /* Parse */ if ( (ast = sieve_parse(script, ehandler)) == NULL ) { @@ -381,7 +383,7 @@ bool ext_include_generate_include sieve_ast_unref(&ast); } - if ( result ) *blk_id_r = inc_block_id; + if ( result ) *included_r = included; return result; } @@ -391,11 +393,25 @@ bool ext_include_generate_include */ bool ext_include_execute_include - (const struct sieve_runtime_env *renv, unsigned int block_id) + (const struct sieve_runtime_env *renv, unsigned int include_id) { int result = TRUE; - struct ext_include_interpreter_context *ctx = - ext_include_get_interpreter_context(renv->interp); + struct ext_include_interpreter_context *ctx; + const struct ext_include_script_info *included; + unsigned int block_id; + + /* Check for invalid include id (== corrupt binary) */ + included = ext_include_binary_script_get_included(renv->sbin, include_id); + if ( included == NULL ) { + sieve_runtime_trace_error(renv, "invalid include id: %d", include_id); + return SIEVE_EXEC_BIN_CORRUPT; + } + + ctx = ext_include_get_interpreter_context(renv->interp); + block_id = included->block_id; + + sieve_runtime_trace(renv, "INCLUDE command (id: %d, script: %s, block: %d)", + include_id, sieve_script_name(included->script), block_id); if ( ctx->parent == NULL ) { struct ext_include_interpreter_context *curctx; @@ -424,15 +440,17 @@ bool ext_include_execute_include result = ( sieve_interpreter_start (subinterp, renv->msgdata, renv->scriptenv, renv->msgctx, renv->result, &interrupted) == 1 ); - else - result = FALSE; + else { + sieve_runtime_trace_error(renv, "invalid block id: %d", block_id); + result = SIEVE_EXEC_BIN_CORRUPT; + } /* Included scripts can have includes of their own. This is not implemented * recursively. Rather, the sub-interpreter interrupts and defers the * include to the top-level interpreter, which is here. */ - if ( result && interrupted && !curctx->returned ) { - while ( result ) { + if ( result > 0 && interrupted && !curctx->returned ) { + while ( result > 0 ) { if ( ( (interrupted && curctx->returned) || (!interrupted) ) && curctx->parent != NULL ) { @@ -477,8 +495,10 @@ bool ext_include_execute_include result = ( sieve_interpreter_start (subinterp, renv->msgdata, renv->scriptenv, renv->msgctx, renv->result, &interrupted) == 1 ); - } else - result = FALSE; + } else { + sieve_runtime_trace_error(renv, "invalid block id: %d", curctx->block_id); + result = SIEVE_EXEC_BIN_CORRUPT; + } } else { /* Sub-interpreter was interrupted outside this extension, probably * stop command was executed. Generate an interrupt ourselves, diff --git a/src/lib-sieve/plugins/include/ext-include-common.h b/src/lib-sieve/plugins/include/ext-include-common.h index fa005e49fad5982650e1d22b386623cebf3dff3c..91666d6efb28a2e2376ae4c517b30c98e64649bc 100644 --- a/src/lib-sieve/plugins/include/ext-include-common.h +++ b/src/lib-sieve/plugins/include/ext-include-common.h @@ -10,6 +10,12 @@ #define EXT_INCLUDE_MAX_NESTING_LEVEL 10 +/* + * Forward declarations + */ + +struct ext_include_script_info; + /* Extension */ extern int ext_include_my_id; @@ -74,7 +80,7 @@ void ext_include_register_generator_context bool ext_include_generate_include (const struct sieve_codegen_env *cgenv, struct sieve_command_context *cmd, enum ext_include_script_location location, struct sieve_script *script, - unsigned *blk_id_r); + const struct ext_include_script_info **included_r); /* * Interpreter context