diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 09:51:24 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 09:51:24 +0000 |
commit | f7548d6d28c313cf80e6f3ef89aed16a19815df1 (patch) | |
tree | a3f6f2a3f247293bee59ecd28e8cd8ceb6ca064a /pigeonhole/src/lib-sieve/plugins/include/cmd-include.c | |
parent | Initial commit. (diff) | |
download | dovecot-upstream.tar.xz dovecot-upstream.zip |
Adding upstream version 1:2.3.19.1+dfsg1.upstream/1%2.3.19.1+dfsg1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'pigeonhole/src/lib-sieve/plugins/include/cmd-include.c')
-rw-r--r-- | pigeonhole/src/lib-sieve/plugins/include/cmd-include.c | 406 |
1 files changed, 406 insertions, 0 deletions
diff --git a/pigeonhole/src/lib-sieve/plugins/include/cmd-include.c b/pigeonhole/src/lib-sieve/plugins/include/cmd-include.c new file mode 100644 index 0000000..92aefb4 --- /dev/null +++ b/pigeonhole/src/lib-sieve/plugins/include/cmd-include.c @@ -0,0 +1,406 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +#include "lib.h" +#include "str-sanitize.h" + +#include "sieve-common.h" +#include "sieve-script.h" +#include "sieve-storage.h" +#include "sieve-ast.h" +#include "sieve-code.h" +#include "sieve-extensions.h" +#include "sieve-commands.h" +#include "sieve-validator.h" +#include "sieve-binary.h" +#include "sieve-generator.h" +#include "sieve-interpreter.h" +#include "sieve-dump.h" + +#include "ext-include-common.h" +#include "ext-include-binary.h" + +/* + * Include command + * + * Syntax: + * include [LOCATION] [":once"] [":optional"] <value: string> + * + * [LOCATION]: + * ":personal" / ":global" + */ + +static bool cmd_include_registered + (struct sieve_validator *valdtr, const struct sieve_extension *ext, + struct sieve_command_registration *cmd_reg); +static bool cmd_include_pre_validate + (struct sieve_validator *valdtr ATTR_UNUSED, struct sieve_command *cmd); +static bool cmd_include_validate + (struct sieve_validator *valdtr, struct sieve_command *cmd); +static bool cmd_include_generate + (const struct sieve_codegen_env *cgenv, struct sieve_command *ctx); + +const struct sieve_command_def cmd_include = { + .identifier = "include", + .type = SCT_COMMAND, + .positional_args = 1, + .subtests = 0, + .block_allowed = FALSE, + .block_required = FALSE, + .registered = cmd_include_registered, + .pre_validate = cmd_include_pre_validate, + .validate = cmd_include_validate, + .generate = cmd_include_generate +}; + +/* + * Include operation + */ + +static bool opc_include_dump + (const struct sieve_dumptime_env *denv, sieve_size_t *address); +static int opc_include_execute + (const struct sieve_runtime_env *renv, sieve_size_t *address); + +const struct sieve_operation_def include_operation = { + .mnemonic = "include", + .ext_def = &include_extension, + .code = EXT_INCLUDE_OPERATION_INCLUDE, + .dump = opc_include_dump, + .execute = opc_include_execute +}; + +/* + * Context structures + */ + +struct cmd_include_context_data { + enum ext_include_script_location location; + + struct sieve_script *script; + enum ext_include_flags flags; + + bool location_assigned:1; +}; + +/* + * Tagged arguments + */ + +static bool cmd_include_validate_location_tag + (struct sieve_validator *valdtr, struct sieve_ast_argument **arg, + struct sieve_command *cmd); + +static const struct sieve_argument_def include_personal_tag = { + .identifier = "personal", + .validate = cmd_include_validate_location_tag +}; + +static const struct sieve_argument_def include_global_tag = { + .identifier = "global", + .validate = cmd_include_validate_location_tag +}; + +static bool cmd_include_validate_boolean_tag + (struct sieve_validator *valdtr, struct sieve_ast_argument **arg, + struct sieve_command *cmd); + +static const struct sieve_argument_def include_once_tag = { + .identifier = "once", + .validate = cmd_include_validate_boolean_tag +}; + +static const struct sieve_argument_def include_optional_tag = { + .identifier = "optional", + .validate = cmd_include_validate_boolean_tag +}; + +/* + * Tag validation + */ + +static bool cmd_include_validate_location_tag +(struct sieve_validator *valdtr, struct sieve_ast_argument **arg, + struct sieve_command *cmd) +{ + struct cmd_include_context_data *ctx_data = + (struct cmd_include_context_data *) cmd->data; + + if ( ctx_data->location_assigned) { + sieve_argument_validate_error(valdtr, *arg, + "include: cannot use location tags ':personal' and ':global' " + "multiple times"); + return FALSE; + } + + if ( sieve_argument_is(*arg, include_personal_tag) ) + ctx_data->location = EXT_INCLUDE_LOCATION_PERSONAL; + else if ( sieve_argument_is(*arg, include_global_tag) ) + ctx_data->location = EXT_INCLUDE_LOCATION_GLOBAL; + else + return FALSE; + + ctx_data->location_assigned = TRUE; + + /* Delete this tag (for now) */ + *arg = sieve_ast_arguments_detach(*arg, 1); + + return TRUE; +} + +static bool cmd_include_validate_boolean_tag +(struct sieve_validator *valdtr ATTR_UNUSED, struct sieve_ast_argument **arg, + struct sieve_command *cmd) +{ + struct cmd_include_context_data *ctx_data = + (struct cmd_include_context_data *) cmd->data; + + if ( sieve_argument_is(*arg, include_once_tag) ) + ctx_data->flags |= EXT_INCLUDE_FLAG_ONCE; + else + ctx_data->flags |= EXT_INCLUDE_FLAG_OPTIONAL; + + /* Delete this tag (for now) */ + *arg = sieve_ast_arguments_detach(*arg, 1); + + return TRUE; +} + +/* + * Command registration + */ + +static bool cmd_include_registered +(struct sieve_validator *valdtr, const struct sieve_extension *ext, + struct sieve_command_registration *cmd_reg) +{ + sieve_validator_register_tag(valdtr, cmd_reg, ext, &include_personal_tag, 0); + sieve_validator_register_tag(valdtr, cmd_reg, ext, &include_global_tag, 0); + sieve_validator_register_tag(valdtr, cmd_reg, ext, &include_once_tag, 0); + sieve_validator_register_tag(valdtr, cmd_reg, ext, &include_optional_tag, 0); + + return TRUE; +} + +/* + * Command validation + */ + +static bool cmd_include_pre_validate +(struct sieve_validator *valdtr ATTR_UNUSED, struct sieve_command *cmd) +{ + struct cmd_include_context_data *ctx_data; + + /* Assign context */ + ctx_data = p_new(sieve_command_pool(cmd), struct cmd_include_context_data, 1); + ctx_data->location = EXT_INCLUDE_LOCATION_PERSONAL; + cmd->data = ctx_data; + + return TRUE; +} + +static bool cmd_include_validate +(struct sieve_validator *valdtr, struct sieve_command *cmd) +{ + const struct sieve_extension *this_ext = cmd->ext; + struct sieve_ast_argument *arg = cmd->first_positional; + struct cmd_include_context_data *ctx_data = + (struct cmd_include_context_data *) cmd->data; + struct sieve_storage *storage; + struct sieve_script *script; + const char *script_name; + enum sieve_error error = SIEVE_ERROR_NONE; + int ret; + + /* Check argument */ + if ( !sieve_validate_positional_argument + (valdtr, cmd, arg, "value", 1, SAAT_STRING) ) { + return FALSE; + } + + if ( !sieve_validator_argument_activate(valdtr, cmd, arg, FALSE) ) + return FALSE; + + /* + * Variables are not allowed. + */ + if ( !sieve_argument_is_string_literal(arg) ) { + sieve_argument_validate_error(valdtr, arg, + "the include command requires a constant string for its value argument"); + return FALSE; + } + + /* Find the script */ + + script_name = sieve_ast_argument_strc(arg); + + if ( !sieve_script_name_is_valid(script_name) ) { + sieve_argument_validate_error(valdtr, arg, + "include: invalid script name '%s'", + str_sanitize(script_name, 80)); + return FALSE; + } + + storage = ext_include_get_script_storage + (this_ext, ctx_data->location, script_name, &error); + if ( storage == NULL ) { + // FIXME: handle ':optional' in this case + if (error == SIEVE_ERROR_NOT_FOUND) { + sieve_argument_validate_error(valdtr, arg, + "include: %s location for included script `%s' is unavailable " + "(contact system administrator for more information)", + ext_include_script_location_name(ctx_data->location), + str_sanitize(script_name, 80)); + } else { + sieve_argument_validate_error(valdtr, arg, + "include: failed to access %s location for included script `%s' " + "(contact system administrator for more information)", + ext_include_script_location_name(ctx_data->location), + str_sanitize(script_name, 80)); + } + return FALSE; + } + + /* Create script object */ + script = sieve_storage_get_script + (storage, script_name, &error); + if ( script == NULL ) + return FALSE; + + ret = sieve_script_open(script, &error); + if ( ret < 0 ) { + if ( error != SIEVE_ERROR_NOT_FOUND ) { + sieve_argument_validate_error(valdtr, arg, + "failed to access included %s script '%s': %s", + ext_include_script_location_name(ctx_data->location), + str_sanitize(script_name, 80), + sieve_script_get_last_error_lcase(script)); + sieve_script_unref(&script); + return FALSE; + + /* Not found */ + } else { + enum sieve_compile_flags cpflags = + sieve_validator_compile_flags(valdtr); + + if ( (ctx_data->flags & EXT_INCLUDE_FLAG_OPTIONAL) != 0 ) { + /* :optional */ + + } else if ( (cpflags & SIEVE_COMPILE_FLAG_UPLOADED) != 0 ) { + /* Script is being uploaded */ + sieve_argument_validate_warning(valdtr, arg, + "included %s script '%s' does not exist (ignored during upload)", + ext_include_script_location_name(ctx_data->location), + str_sanitize(script_name, 80)); + ctx_data->flags |= EXT_INCLUDE_FLAG_MISSING_AT_UPLOAD; + + } else { + /* Should have existed */ + sieve_argument_validate_error(valdtr, arg, + "included %s script '%s' does not exist", + ext_include_script_location_name(ctx_data->location), + str_sanitize(script_name, 80)); + sieve_script_unref(&script); + return FALSE; + } + } + } + + ext_include_ast_link_included_script(cmd->ext, cmd->ast_node->ast, script); + ctx_data->script = script; + + (void)sieve_ast_arguments_detach(arg, 1); + return TRUE; +} + +/* + * Code Generation + */ + +static bool cmd_include_generate +(const struct sieve_codegen_env *cgenv, struct sieve_command *cmd) +{ + struct cmd_include_context_data *ctx_data = + (struct cmd_include_context_data *) cmd->data; + const struct ext_include_script_info *included; + int ret; + + /* Compile (if necessary) and include the script into the binary. + * This yields the id of the binary block containing the compiled byte code. + */ + if ( (ret=ext_include_generate_include + (cgenv, cmd, ctx_data->location, ctx_data->flags, ctx_data->script, + &included)) < 0 ) + return FALSE; + + if ( ret > 0 ) { + (void)sieve_operation_emit(cgenv->sblock, cmd->ext, &include_operation); + (void)sieve_binary_emit_unsigned(cgenv->sblock, included->id); + (void)sieve_binary_emit_byte(cgenv->sblock, ctx_data->flags); + } + + return TRUE; +} + +/* + * Code dump + */ + +static bool opc_include_dump +(const struct sieve_dumptime_env *denv, sieve_size_t *address) +{ + const struct ext_include_script_info *included; + struct ext_include_binary_context *binctx; + unsigned int include_id, flags; + + sieve_code_dumpf(denv, "INCLUDE:"); + + sieve_code_mark(denv); + if ( !sieve_binary_read_unsigned(denv->sblock, address, &include_id) ) + return FALSE; + + if ( !sieve_binary_read_byte(denv->sblock, address, &flags) ) + return FALSE; + + binctx = ext_include_binary_get_context(denv->oprtn->ext, denv->sbin); + included = ext_include_binary_script_get_included(binctx, include_id); + if ( included == NULL ) + return FALSE; + + sieve_code_descend(denv); + sieve_code_dumpf(denv, "script: `%s' from %s %s%s[ID: %d, BLOCK: %d]", + sieve_script_name(included->script), sieve_script_location(included->script), + ((flags & EXT_INCLUDE_FLAG_ONCE) != 0 ? "(once) " : ""), + ((flags & EXT_INCLUDE_FLAG_OPTIONAL) != 0 ? "(optional) " : ""), + include_id, sieve_binary_block_get_id(included->block)); + + return TRUE; +} + +/* + * Execution + */ + +static int opc_include_execute +(const struct sieve_runtime_env *renv, sieve_size_t *address) +{ + unsigned int include_id, flags; + + if ( !sieve_binary_read_unsigned(renv->sblock, address, &include_id) ) { + sieve_runtime_trace_error(renv, "invalid include-id operand"); + return SIEVE_EXEC_BIN_CORRUPT; + } + + if ( !sieve_binary_read_unsigned(renv->sblock, address, &flags) ) { + sieve_runtime_trace_error(renv, "invalid flags operand"); + return SIEVE_EXEC_BIN_CORRUPT; + } + + return ext_include_execute_include + (renv, include_id, (enum ext_include_flags)flags); +} + + + + + |