diff --git a/src/plugins/settings/Makefile.am b/src/plugins/settings/Makefile.am index 9b41a2cd76bdea9e5efdab929f01f50c27e1a9b1..35b08c4b271cbb3e670413a7d0238603d81bf118 100644 --- a/src/plugins/settings/Makefile.am +++ b/src/plugins/settings/Makefile.am @@ -7,6 +7,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/lib-sieve/util \ -I$(top_srcdir)/src/lib-sieve/storage/ldap \ -I$(top_srcdir)/src/lib-managesieve \ + -I$(top_srcdir)/src/plugins/sieve-extprograms \ -DSETTINGS_PLUGIN if LDAP_PLUGIN AM_CPPFLAGS += -DPLUGIN_BUILD -DLDAP_PLUGIN diff --git a/src/plugins/settings/settings-get.pl b/src/plugins/settings/settings-get.pl index 6398408d54e81c83843a45ed31ef2f3986668596..0cbc276c932fb4aef20ba2384768c91f31c682f5 100755 --- a/src/plugins/settings/settings-get.pl +++ b/src/plugins/settings/settings-get.pl @@ -29,6 +29,7 @@ print '#include "sieve-common.h"'."\n"; print '#include "sieve-limits.h"'."\n"; print '#include "sieve-address-source.h"'."\n"; print '#include "managesieve-url.h"'."\n"; +print '#include "sieve-extprograms-limits.h"'."\n"; print '#include "pigeonhole-settings.h"'."\n"; print '#include <unistd.h>'."\n"; print "#ifdef LDAP_PLUGIN\n"; diff --git a/src/plugins/sieve-extprograms/Makefile.am b/src/plugins/sieve-extprograms/Makefile.am index ab7844f380825f59639d9511d2629d247a48f6e5..b495ef6777b79a85f8850d14bd30f773e87e09ae 100644 --- a/src/plugins/sieve-extprograms/Makefile.am +++ b/src/plugins/sieve-extprograms/Makefile.am @@ -25,10 +25,13 @@ extensions = \ lib90_sieve_extprograms_plugin_la_SOURCES = \ $(commands) \ $(extensions) \ + sieve-extprograms-settings.c \ sieve-extprograms-common.c \ sieve-extprograms-plugin.c noinst_HEADERS = \ + sieve-extprograms-limits.h \ + sieve-extprograms-settings.h \ sieve-extprograms-common.h \ sieve-extprograms-plugin.h diff --git a/src/plugins/sieve-extprograms/cmd-execute.c b/src/plugins/sieve-extprograms/cmd-execute.c index c105087e775676922b8f230d742a65795393ae2d..1d77f6a7e8eb210904b34883f7b60980a21cb8e2 100644 --- a/src/plugins/sieve-extprograms/cmd-execute.c +++ b/src/plugins/sieve-extprograms/cmd-execute.c @@ -167,7 +167,9 @@ cmd_execute_validate_output_tag(struct sieve_validator *valdtr, struct sieve_ast_argument *tag = *arg; struct sieve_extprograms_ext_context *extctx = cmd->ext->context; - if (extctx == NULL || extctx->var_ext == NULL || + if (extctx == NULL) + return FALSE; + if (extctx->var_ext == NULL || !sieve_ext_variables_is_active(extctx->var_ext, valdtr)) { sieve_argument_validate_error( valdtr,*arg, diff --git a/src/plugins/sieve-extprograms/sieve-extprograms-common.c b/src/plugins/sieve-extprograms/sieve-extprograms-common.c index 401fb2ef019c2cecb3b23eb519b4a41a3d57b2d1..a4f7b33c77170ddc7610764ca04be8dffef7a9a9 100644 --- a/src/plugins/sieve-extprograms/sieve-extprograms-common.c +++ b/src/plugins/sieve-extprograms/sieve-extprograms-common.c @@ -14,6 +14,7 @@ #include "istream-crlf.h" #include "istream-header-filter.h" #include "ostream.h" +#include "settings.h" #include "mail-user.h" #include "mail-storage.h" @@ -35,6 +36,8 @@ #include "sieve-ext-copy.h" #include "sieve-ext-variables.h" +#include "sieve-extprograms-limits.h" +#include "sieve-extprograms-settings.h" #include "sieve-extprograms-common.h" #include <unistd.h> @@ -42,16 +45,6 @@ #include <sys/wait.h> #include <sys/socket.h> -/* - * Limits - */ - -#define SIEVE_EXTPROGRAMS_MAX_PROGRAM_NAME_LEN 128 -#define SIEVE_EXTPROGRAMS_MAX_PROGRAM_ARG_LEN 1024 - -#define SIEVE_EXTPROGRAMS_DEFAULT_EXEC_TIMEOUT_SECS 10 -#define SIEVE_EXTPROGRAMS_CONNECT_TIMEOUT_MSECS 5 - /* * Context */ @@ -62,21 +55,19 @@ int sieve_extprograms_ext_load(const struct sieve_extension *ext, struct sieve_instance *svinst = ext->svinst; const struct sieve_extension *copy_ext = NULL; const struct sieve_extension *var_ext = NULL; + const struct sieve_extprograms_settings *set; struct sieve_extprograms_ext_context *extctx; - const char *extname = sieve_extension_name(ext); - const char *bin_dir, *socket_dir, *input_eol; - sieve_number_t execute_timeout; - - extname = strrchr(extname, '.'); - i_assert(extname != NULL); - extname++; - - bin_dir = sieve_setting_get( - svinst, t_strdup_printf("sieve_%s_bin_dir", extname)); - socket_dir = sieve_setting_get( - svinst, t_strdup_printf("sieve_%s_socket_dir", extname)); - input_eol = sieve_setting_get( - svinst, t_strdup_printf("sieve_%s_input_eol", extname)); + const char *extname = sieve_extension_name(ext), *error; + const struct setting_parser_info *set_info; + + if (sieve_extension_is(ext, sieve_ext_vnd_pipe)) + set_info = &sieve_ext_vnd_pipe_setting_parser_info; + else if (sieve_extension_is(ext, sieve_ext_vnd_filter)) + set_info = &sieve_ext_vnd_filter_setting_parser_info; + else if (sieve_extension_is(ext, sieve_ext_vnd_execute)) + set_info = &sieve_ext_vnd_execute_setting_parser_info; + else + i_unreached(); if (sieve_extension_is(ext, sieve_ext_vnd_pipe)) { if (sieve_ext_copy_get_extension(ext->svinst, ©_ext) < 0) @@ -88,32 +79,23 @@ int sieve_extprograms_ext_load(const struct sieve_extension *ext, return -1; } - extctx = i_new(struct sieve_extprograms_ext_context, 1); - extctx->execute_timeout = - SIEVE_EXTPROGRAMS_DEFAULT_EXEC_TIMEOUT_SECS; - extctx->copy_ext = copy_ext; - extctx->var_ext = var_ext; - - if (bin_dir == NULL && socket_dir == NULL) { + if (settings_get(svinst->event, set_info, 0, &set, &error) < 0) { + e_error(svinst->event, "%s", error); + return -1; + } + if (*set->bin_dir == '\0' && *set->socket_dir == '\0') { e_debug(svinst->event, "%s extension: " - "no bin or socket directory specified; extension is unconfigured " + "No bin or socket directory specified; " + "extension is unconfigured " "(both sieve_%s_bin_dir and sieve_%s_socket_dir are not set)", - sieve_extension_name(ext), extname, extname); - } else { - extctx->bin_dir = i_strdup(bin_dir); - extctx->socket_dir = i_strdup(socket_dir); - - if (sieve_setting_get_duration_value( - svinst, t_strdup_printf("sieve_%s_exec_timeout", - extname), &execute_timeout)) - extctx->execute_timeout = execute_timeout; - - extctx->default_input_eol = SIEVE_EXTPROGRAMS_EOL_CRLF; - if (input_eol != NULL && strcasecmp(input_eol, "lf") == 0) { - extctx->default_input_eol = SIEVE_EXTPROGRAMS_EOL_LF; - } + extname, extname, extname); } + extctx = i_new(struct sieve_extprograms_ext_context, 1); + extctx->copy_ext = copy_ext; + extctx->var_ext = var_ext; + extctx->set = set; + *context_r = extctx; return 0; } @@ -124,9 +106,7 @@ void sieve_extprograms_ext_unload(const struct sieve_extension *ext) if (extctx == NULL) return; - - i_free(extctx->bin_dir); - i_free(extctx->socket_dir); + settings_free(extctx->set); i_free(extctx); } @@ -247,11 +227,20 @@ _arg_validate(void *context, struct sieve_ast_argument *item) bool sieve_extprogram_command_validate(struct sieve_validator *valdtr, struct sieve_command *cmd) { + struct sieve_extprograms_ext_context *extctx = cmd->ext->context; struct sieve_ast_argument *arg = cmd->first_positional; struct sieve_ast_argument *stritem; struct _arg_validate_context actx; string_t *program_name; + if (extctx == NULL) { + sieve_command_validate_error( + valdtr, cmd, "the %s extension is not configured " + "(refer to server log for more information)", + sieve_extension_name(cmd->ext)); + return FALSE; + } + if (arg == NULL) { sieve_command_validate_error( valdtr, cmd, @@ -426,7 +415,8 @@ sieve_extprogram_create(const struct sieve_extension *ext, "running program: %s", action, program_name); if (extctx == NULL || - (extctx->bin_dir == NULL && extctx->socket_dir == NULL)) { + (*extctx->set->bin_dir == '\0' && + *extctx->set->socket_dir == '\0')) { e_error(svinst->event, "action %s: " "failed to execute program '%s': " "vnd.dovecot.%s extension is unconfigured", @@ -436,9 +426,9 @@ sieve_extprogram_create(const struct sieve_extension *ext, } /* Try socket first */ - if (extctx->socket_dir != NULL) { + if (*extctx->set->socket_dir != '\0') { path = t_strconcat(senv->user->set->base_dir, "/", - extctx->socket_dir, "/", program_name, + extctx->set->socket_dir, "/", program_name, NULL); if (stat(path, &st) < 0) { switch (errno) { @@ -471,9 +461,9 @@ sieve_extprogram_create(const struct sieve_extension *ext, } /* Try executable next */ - if (path == NULL && extctx->bin_dir != NULL) { + if (path == NULL && *extctx->set->bin_dir != '\0') { fork = TRUE; - path = t_strconcat(extctx->bin_dir, "/", program_name, NULL); + path = t_strconcat(extctx->set->bin_dir, "/", program_name, NULL); if (stat(path, &st) < 0) { switch (errno) { case ENOENT: @@ -528,7 +518,7 @@ sieve_extprogram_create(const struct sieve_extension *ext, struct program_client_parameters pc_params = { .client_connect_timeout_msecs = SIEVE_EXTPROGRAMS_CONNECT_TIMEOUT_MSECS, - .input_idle_timeout_msecs = extctx->execute_timeout * 1000, + .input_idle_timeout_msecs = extctx->set->exec_timeout * 1000, }; if (fork) { @@ -592,7 +582,7 @@ void sieve_extprogram_set_output(struct sieve_extprogram *sprog, void sieve_extprogram_set_input(struct sieve_extprogram *sprog, struct istream *input) { - switch (sprog->extctx->default_input_eol) { + switch (sprog->extctx->set->parsed.input_eol) { case SIEVE_EXTPROGRAMS_EOL_LF: input = i_stream_create_lf(input); break; diff --git a/src/plugins/sieve-extprograms/sieve-extprograms-common.h b/src/plugins/sieve-extprograms/sieve-extprograms-common.h index 881b7d467585419c97f11dd7c0b42841145847c1..bd71c0f44111fc3ba416f3240ce49b55ef3b626a 100644 --- a/src/plugins/sieve-extprograms/sieve-extprograms-common.h +++ b/src/plugins/sieve-extprograms/sieve-extprograms-common.h @@ -2,26 +2,17 @@ #define SIEVE_EXTPROGRAMS_COMMON_H #include "sieve-common.h" +#include "sieve-extprograms-settings.h" /* * Extension configuration */ -enum sieve_extprograms_eol { - SIEVE_EXTPROGRAMS_EOL_CRLF = 0, - SIEVE_EXTPROGRAMS_EOL_LF -}; - struct sieve_extprograms_ext_context { + const struct sieve_extprograms_settings *set; + const struct sieve_extension *copy_ext; const struct sieve_extension *var_ext; - - char *socket_dir; - char *bin_dir; - - enum sieve_extprograms_eol default_input_eol; - - unsigned int execute_timeout; }; int sieve_extprograms_ext_load(const struct sieve_extension *ext, diff --git a/src/plugins/sieve-extprograms/sieve-extprograms-limits.h b/src/plugins/sieve-extprograms/sieve-extprograms-limits.h new file mode 100644 index 0000000000000000000000000000000000000000..c77d2466d9cb57be625597658e1ec106b2c9c85a --- /dev/null +++ b/src/plugins/sieve-extprograms/sieve-extprograms-limits.h @@ -0,0 +1,9 @@ +#ifndef SIEVE_EXTPROGRAMS_LIMITS_H +#define SIEVE_EXTPROGRAMS_LIMITS_H + +#define SIEVE_EXTPROGRAMS_MAX_PROGRAM_NAME_LEN 128 +#define SIEVE_EXTPROGRAMS_MAX_PROGRAM_ARG_LEN 1024 + +#define SIEVE_EXTPROGRAMS_CONNECT_TIMEOUT_MSECS 5 + +#endif diff --git a/src/plugins/sieve-extprograms/sieve-extprograms-settings.c b/src/plugins/sieve-extprograms/sieve-extprograms-settings.c new file mode 100644 index 0000000000000000000000000000000000000000..0d33f13b43b3d792bcea1824f4a189d82884c853 --- /dev/null +++ b/src/plugins/sieve-extprograms/sieve-extprograms-settings.c @@ -0,0 +1,121 @@ +/* Copyright (c) 2024 Pigeonhole authors, see the included COPYING file + */ + +#include "lib.h" +#include "array.h" +#include "settings.h" +#include "settings-parser.h" + +#include "sieve-extprograms-limits.h" +#include "sieve-extprograms-settings.h" + +static bool +sieve_extprograms_settings_check(void *_set, pool_t pool, const char **error_r); + +#undef DEF +#define DEF(type, name) \ + SETTING_DEFINE_STRUCT_##type("sieve_pipe_"#name, name, \ + struct sieve_extprograms_settings) + +static const struct setting_define ext_pipe_setting_defines[] = { + DEF(STR, bin_dir), + DEF(STR, socket_dir), + DEF(ENUM, input_eol), + + DEF(TIME, exec_timeout), + + SETTING_DEFINE_LIST_END, +}; + +#undef DEF +#define DEF(type, name) \ + SETTING_DEFINE_STRUCT_##type("sieve_filter_"#name, name, \ + struct sieve_extprograms_settings) + +static const struct setting_define ext_filter_setting_defines[] = { + DEF(STR, bin_dir), + DEF(STR, socket_dir), + DEF(ENUM, input_eol), + + DEF(TIME, exec_timeout), + + SETTING_DEFINE_LIST_END, +}; + +#undef DEF +#define DEF(type, name) \ + SETTING_DEFINE_STRUCT_##type("sieve_execute_"#name, name, \ + struct sieve_extprograms_settings) + +static const struct setting_define ext_execute_setting_defines[] = { + DEF(STR, bin_dir), + DEF(STR, socket_dir), + DEF(ENUM, input_eol), + + DEF(TIME, exec_timeout), + + SETTING_DEFINE_LIST_END, +}; + +static const struct sieve_extprograms_settings sieve_extprograms_default_settings = { + .bin_dir = "", + .socket_dir = "", + .input_eol = "crlf:lf", + .exec_timeout = 10, +}; + +const struct setting_parser_info sieve_ext_vnd_pipe_setting_parser_info = { + .name = "sieve_ext_pipe", + + .defines = ext_pipe_setting_defines, + .defaults = &sieve_extprograms_default_settings, + + .struct_size = sizeof(struct sieve_extprograms_settings), + + .check_func = sieve_extprograms_settings_check, + + .pool_offset1 = 1 + offsetof(struct sieve_extprograms_settings, pool), +}; + +const struct setting_parser_info sieve_ext_vnd_filter_setting_parser_info = { + .name = "sieve_ext_filter", + + .defines = ext_filter_setting_defines, + .defaults = &sieve_extprograms_default_settings, + + .struct_size = sizeof(struct sieve_extprograms_settings), + + .check_func = sieve_extprograms_settings_check, + + .pool_offset1 = 1 + offsetof(struct sieve_extprograms_settings, pool), +}; + +const struct setting_parser_info sieve_ext_vnd_execute_setting_parser_info = { + .name = "sieve_ext_execute", + + .defines = ext_execute_setting_defines, + .defaults = &sieve_extprograms_default_settings, + + .struct_size = sizeof(struct sieve_extprograms_settings), + + .check_func = sieve_extprograms_settings_check, + + .pool_offset1 = 1 + offsetof(struct sieve_extprograms_settings, pool), +}; + +/* <settings checks> */ +static bool +sieve_extprograms_settings_check(void *_set, pool_t pool ATTR_UNUSED, + const char **error_r ATTR_UNUSED) +{ + struct sieve_extprograms_settings *set = _set; + + if (strcasecmp(set->input_eol, "crlf") == 0) + set->parsed.input_eol = SIEVE_EXTPROGRAMS_EOL_CRLF; + else if (strcasecmp(set->input_eol, "lf") == 0) + set->parsed.input_eol = SIEVE_EXTPROGRAMS_EOL_LF; + else + i_unreached(); + return TRUE; +} +/* </settings checks> */ diff --git a/src/plugins/sieve-extprograms/sieve-extprograms-settings.h b/src/plugins/sieve-extprograms/sieve-extprograms-settings.h new file mode 100644 index 0000000000000000000000000000000000000000..3f2db7a31b82b18f228b0ee0e9fde508837b1b1b --- /dev/null +++ b/src/plugins/sieve-extprograms/sieve-extprograms-settings.h @@ -0,0 +1,29 @@ +#ifndef SIEVE_EXTPROGRAMS_SETTINGS_H +#define SIEVE_EXTPROGRAMS_SETTINGS_H + +/* <settings checks> */ +enum sieve_extprograms_eol { + SIEVE_EXTPROGRAMS_EOL_CRLF = 0, + SIEVE_EXTPROGRAMS_EOL_LF +}; +/* </settings checks> */ + +struct sieve_extprograms_settings { + pool_t pool; + + const char *bin_dir; + const char *socket_dir; + const char *input_eol; + + unsigned int exec_timeout; + + struct { + enum sieve_extprograms_eol input_eol; + } parsed; +}; + +extern const struct setting_parser_info sieve_ext_vnd_pipe_setting_parser_info; +extern const struct setting_parser_info sieve_ext_vnd_filter_setting_parser_info; +extern const struct setting_parser_info sieve_ext_vnd_execute_setting_parser_info; + +#endif