diff --git a/TODO b/TODO index 6feabb2320782b81bcfc0c1c0727d7bf7899bd75..c526512f9ec9b8f00c9a3f8991c85dab6337b504 100644 --- a/TODO +++ b/TODO @@ -8,8 +8,7 @@ Current: - Limit the number of notifications generated (on a per-method basis) * Implement mailto method for the enotify extension: - Check that URI headers are not duplicated if not allowed. -* Implement means to configure which extensions to provide and incorporate - enotify extension into default compile. +* Incorporate enotify extension into default compile. Next (in order of descending priority/precedence): diff --git a/doc/man/sieve-test.1 b/doc/man/sieve-test.1 index 0d40e0f1523ad35ba5815a01223dcea4df5acb2a..4955f1d5ce6ed4132d6f17ea992191b5c6361f1c 100644 --- a/doc/man/sieve-test.1 +++ b/doc/man/sieve-test.1 @@ -1,12 +1,9 @@ -.TH "SIEVE-TEST" "1" "11 November 2008" +.TH "SIEVE-TEST" "1" "21 December 2008" .SH NAME sieve-test \- Sieve script tester for the Dovecot secure IMAP server .SH SYNOPSIS -.TP -sieve-test [\fB-r\fR \fIrecipient-address\fR][\fB-s\fR \fIenvelope-sender\fR] -[\fB-m\fR \fImailbox\fR][\fB-d\fR \fIdump-file\fR][\fB-c\fR][\fB-t\fR] -\fIscript-file\fR \fImail-file\fR -.br +sieve-test [\fB-r\fR \fIrecipient-address\fR] [\fB-s\fR \fIenvelope-sender\fR] [\fB-m\fR \fImailbox\fR] [\fB-d\fR \fIdump-file\fR] [\fB-c\fR] [\fB-t\fR] +[\fB-x\fR "\fIextension extension ...\fR"] \fIscript-file\fR \fImail-file\fR .SH DESCRIPTION .PP The \fBsieve-test\fP command is part of the Sieve implementation for the Dovecot secure @@ -50,6 +47,10 @@ Sieve compilation. .TP \fB-t\fP Enable simple trace debugging; prints all encountered byte code instructions on \fBstdout\fP. +.TP +\fB-x\fP "\fIextension extension ...\fP" +Set the available extensions. The parameter is a space-separated list of the active extensions. +Unknown extensions are ignored, but a warning is produced. .SH AUTHOR .PP The Sieve implementation for Dovecot was written by Stephan Bosch <stephan@rename-it.nl>. diff --git a/doc/man/sievec.1 b/doc/man/sievec.1 index c8c0feb77ae95314f35ef1cc60c3eae9f345f0f6..a34b3733da97f8312164ff696dd52f6f9e1c8772 100644 --- a/doc/man/sievec.1 +++ b/doc/man/sievec.1 @@ -1,9 +1,8 @@ -.TH "SIEVEC" "1" "11 November 2008" +.TH "SIEVEC" "1" "21 December 2008" .SH NAME sievec \- Sieve script compiler for the Dovecot secure IMAP server .SH SYNOPSIS -sievec [\fB-d\fR] \fIsieve-script\fR \fIoutfile\fR -.br +sievec [\fB-d\fR] [\fB-x\fR "\fIextension extension ...\fR"] \fIsieve-script\fR \fIoutfile\fR .SH DESCRIPTION .PP The \fBsievec\fP command is part of the Sieve implementation for the Dovecot secure @@ -41,9 +40,14 @@ compiler that yield corrupt binaries. \fB-d\fP Don't write the binary to \fIoutfile\fP, but write a textual dump of the binary in stead. In this context, the \fIoutfile\fP value '-' has special meaning: it causes the the textual -dump to be written to \fBstdout\fP. The output is identical to what the +dump to be written to \fBstdout\fP. The \fIoutfile\fP argument may also be omitted when this option +is active, which has the same effect as '-'. The output is identical to what the .BR sieved (1) command produces for a compiled Sieve binary file. +.TP +\fB-x\fP "\fIextension extension ...\fP" +Set the available extensions. The \fIextensions\fP parameter is a space-separated list of the +active extensions. Unknown extensions are ignored, but a warning is produced. .SH AUTHOR .PP The Sieve implementation for Dovecot was written by Stephan Bosch <stephan@rename-it.nl>. diff --git a/src/lib-sieve-tool/sieve-tool.c b/src/lib-sieve-tool/sieve-tool.c index 04d0ade3ec43a81bbe9d31464be05ec2560d6f3e..8215648e0409b87d8d2394c716c4966a8cbd4804 100644 --- a/src/lib-sieve-tool/sieve-tool.c +++ b/src/lib-sieve-tool/sieve-tool.c @@ -55,7 +55,7 @@ void sieve_tool_init(void) lib_signals_ignore(SIGPIPE, TRUE); lib_signals_ignore(SIGALRM, FALSE); - if ( !sieve_init("") ) + if ( !sieve_init() ) i_fatal("failed to initialize sieve implementation\n"); } diff --git a/src/lib-sieve/sieve-extensions.c b/src/lib-sieve/sieve-extensions.c index 6d2e59138aca3fae10ee24b7c319cd099d2aadc9..dc2bbc824a56055e3892d1b25010f3a1ca4a834f 100644 --- a/src/lib-sieve/sieve-extensions.c +++ b/src/lib-sieve/sieve-extensions.c @@ -122,7 +122,7 @@ const unsigned int sieve_core_extensions_count = * Extensions init/deinit */ -bool sieve_extensions_init(const char *sieve_plugins ATTR_UNUSED) +bool sieve_extensions_init(void) { unsigned int i; @@ -152,14 +152,15 @@ void sieve_extensions_deinit(void) struct sieve_extension_registration { const struct sieve_extension *extension; int id; + bool disabled; }; -static ARRAY_DEFINE(extensions, const struct sieve_extension *); +static ARRAY_DEFINE(extensions, struct sieve_extension_registration); static struct hash_table *extension_index; static void sieve_extensions_init_registry(void) { - p_array_init(&extensions, default_pool, 4); + p_array_init(&extensions, default_pool, 30); extension_index = hash_table_create (default_pool, default_pool, 0, str_hash, (hash_cmp_callback_t *)strcmp); } @@ -169,11 +170,11 @@ int sieve_extension_register(const struct sieve_extension *extension) int ext_id = array_count(&extensions); struct sieve_extension_registration *ereg; - array_append(&extensions, &extension, 1); + ereg = array_append_space(&extensions); - ereg = p_new(default_pool, struct sieve_extension_registration, 1); ereg->extension = extension; ereg->id = ext_id; + ereg->disabled = FALSE; hash_table_insert(extension_index, (void *) extension->name, (void *) ereg); @@ -192,11 +193,13 @@ int sieve_extensions_get_count(void) const struct sieve_extension *sieve_extension_get_by_id(unsigned int ext_id) { - const struct sieve_extension * const *ext; + const struct sieve_extension_registration *ereg; if ( ext_id < array_count(&extensions) ) { - ext = array_idx(&extensions, ext_id); - return *ext; + ereg = array_idx(&extensions, ext_id); + + if ( !ereg->disabled ) + return ereg->extension; } return NULL; @@ -212,42 +215,44 @@ const struct sieve_extension *sieve_extension_get_by_name(const char *name) ereg = (struct sieve_extension_registration *) hash_table_lookup(extension_index, name); - if ( ereg == NULL ) + if ( ereg == NULL || ereg->disabled ) return NULL; return ereg->extension; } -static inline bool _list_extension(const struct sieve_extension *ext) +static inline bool _list_extension + (const struct sieve_extension_registration *ereg) { - return ( ext->id != NULL && *ext->name != '@' ); + return ( !ereg->disabled && ereg->extension->id != NULL && + *(ereg->extension->name) != '@' ); } const char *sieve_extensions_get_string(void) { unsigned int i, ext_count; - const struct sieve_extension *const *exts; + const struct sieve_extension_registration *eregs; string_t *extstr = t_str_new(256); - exts = array_get(&extensions, &ext_count); + eregs = array_get(&extensions, &ext_count); if ( ext_count > 0 ) { i = 0; /* Find first listable extension */ - while ( i < ext_count && !_list_extension(exts[i]) ) + while ( i < ext_count && !_list_extension(&eregs[i]) ) i++; if ( i < ext_count ) { /* Add first to string */ - str_append(extstr, exts[i]->name); + str_append(extstr, eregs[i].extension->name); i++; /* Add others */ for ( ; i < ext_count; i++ ) { - if ( _list_extension(exts[i]) ) { + if ( _list_extension(&eregs[i]) ) { str_append_c(extstr, ' '); - str_append(extstr, exts[i]->name); + str_append(extstr, eregs[i].extension->name); } } } @@ -256,6 +261,78 @@ const char *sieve_extensions_get_string(void) return str_c(extstr); } +void sieve_extensions_set_string(const char *ext_string) +{ + ARRAY_DEFINE(enabled_extensions, const struct sieve_extension_registration *); + const struct sieve_extension_registration *const *ena_eregs; + struct sieve_extension_registration *eregs; + const char *bp = ext_string; + const char *ep = bp; + unsigned int i, ext_count, ena_count; + + if ( ext_string == NULL ) { + /* Enable all */ + eregs = array_get_modifiable(&extensions, &ext_count); + + for ( i = 0; i < ext_count; i++ ) { + eregs[i].disabled = FALSE; + } + + return; + } + + t_array_init(&enabled_extensions, array_count(&extensions)); + + do { + const char *name; + + ep = strchr(bp, ' '); + if ( ep == NULL ) + name = bp; + else { + name = t_strdup_until(bp, ep); + bp = ep + 1; + } + + if ( *name != '\0' ) { + const struct sieve_extension_registration *ereg; + + if ( *name == '@' ) + ereg = NULL; + else + ereg = (const struct sieve_extension_registration *) + hash_table_lookup(extension_index, name); + + if ( ereg == NULL ) { + sieve_sys_warning("ignored unknown extension '%s' while configuring " + "available extensions", name); + continue; + } + + array_append(&enabled_extensions, &ereg, 1); + } + + } while ( *bp == '\0' || ep != NULL ); + + eregs = array_get_modifiable(&extensions, &ext_count); + ena_eregs = array_get(&enabled_extensions, &ena_count); + + /* Set new extension status */ + for ( i = 0; i < ext_count; i++ ) { + unsigned int j; + bool disabled = TRUE; + + for ( j = 0; j < ena_count; j++ ) { + if ( ena_eregs[j] == &eregs[i] ) { + disabled = FALSE; + break; + } + } + + eregs[i].disabled = disabled; + } +} + static void sieve_extensions_deinit_registry(void) { struct hash_iterate_context *itx = @@ -269,8 +346,6 @@ static void sieve_extensions_deinit_registry(void) if ( ext->unload != NULL ) ext->unload(); - - p_free(default_pool, ereg); } hash_table_iterate_deinit(&itx); diff --git a/src/lib-sieve/sieve-extensions.h b/src/lib-sieve/sieve-extensions.h index f023d1154a7d29a5450a95fbfe59865d5fa8f703..06c6569940dfd269ed91efdef31e6198eeff076c 100644 --- a/src/lib-sieve/sieve-extensions.h +++ b/src/lib-sieve/sieve-extensions.h @@ -78,7 +78,7 @@ extern const unsigned int sieve_preloaded_extensions_count; * Extensions init/deinit */ -bool sieve_extensions_init(const char *sieve_plugins ATTR_UNUSED); +bool sieve_extensions_init(void); void sieve_extensions_deinit(void); /* @@ -91,6 +91,7 @@ const struct sieve_extension *sieve_extension_get_by_id(unsigned int ext_id); const struct sieve_extension *sieve_extension_get_by_name(const char *name); const char *sieve_extensions_get_string(void); +void sieve_extensions_set_string(const char *ext_string); /* * Capability registries diff --git a/src/lib-sieve/sieve.c b/src/lib-sieve/sieve.c index 760f6eb68d68d40de7427109d7eed113a4a8aba7..2ae1c00de8547a06139e4a94d9effa4832a33edd 100644 --- a/src/lib-sieve/sieve.c +++ b/src/lib-sieve/sieve.c @@ -33,9 +33,9 @@ * Main Sieve library interface */ -bool sieve_init(const char *plugins) +bool sieve_init(void) { - return sieve_extensions_init(plugins); + return sieve_extensions_init(); } void sieve_deinit(void) @@ -43,6 +43,11 @@ void sieve_deinit(void) sieve_extensions_deinit(); } +void sieve_set_extensions(const char *extensions) +{ + sieve_extensions_set_string(extensions); +} + const char *sieve_get_capabilities(const char *name) { if ( name == NULL || *name == '\0' ) diff --git a/src/lib-sieve/sieve.h b/src/lib-sieve/sieve.h index b4f110f7b20acde0ea92f7648ac1c72100728db4..e8091a0c48438d19fb6b79225f5892751aa61877 100644 --- a/src/lib-sieve/sieve.h +++ b/src/lib-sieve/sieve.h @@ -21,18 +21,23 @@ struct sieve_binary; * Initializes the sieve engine. Must be called before any sieve functionality * is used. */ -bool sieve_init(const char *plugins); +bool sieve_init(void); /* sieve_deinit(): * Frees all memory allocated by the sieve engine. */ void sieve_deinit(void); -/* sieve_get_capabilities: +/* sieve_get_capabilities(): * */ const char *sieve_get_capabilities(const char *name); +/* sieve_set_extensions(): + * + */ +void sieve_set_extensions(const char *extensions); + /* * Script compilation */ diff --git a/src/plugins/lda-sieve/lda-sieve-plugin.c b/src/plugins/lda-sieve/lda-sieve-plugin.c index b04d48b3f55f69b143ac25b1ed81ca19cda873b4..f7709299dd4c73454b0197d1a39f29d2dd2345aa 100644 --- a/src/plugins/lda-sieve/lda-sieve-plugin.c +++ b/src/plugins/lda-sieve/lda-sieve-plugin.c @@ -297,8 +297,15 @@ static int lda_sieve_deliver_mail void sieve_plugin_init(void) { + const char *extensions = NULL; + /* Initialize Sieve engine */ - sieve_init(""); + sieve_init(); + + extensions = getenv("SIEVE_EXTENSIONS"); + if ( extensions != NULL ) { + sieve_set_extensions(extensions); + } /* Hook into the delivery process */ next_deliver_mail = deliver_mail; diff --git a/src/sieve-tools/sieve-test.c b/src/sieve-tools/sieve-test.c index 854942593451d9da38986449343e8d9bc9497bb5..d335afa330048b2dec3506e8f384aeffcf66c1a9 100644 --- a/src/sieve-tools/sieve-test.c +++ b/src/sieve-tools/sieve-test.c @@ -32,14 +32,14 @@ static void print_help(void) { #ifdef SIEVE_RUNTIME_TRACE -# define SVTRACE "[-t]" +# define SVTRACE " [-t]" #else # define SVTRACE #endif printf( -"Usage: sieve-test [-r <recipient address>][-s <envelope sender>]\n" -" [-m <mailbox>][-d <dump filename>][-c]" SVTRACE "\n" -" <scriptfile> <mailfile>\n" +"Usage: sieve-test [-r <recipient address>] [-s <envelope sender>]\n" +" [-m <mailbox>] [-d <dump filename>] [-x <extensions>]\n" +" [-c]"SVTRACE" <scriptfile> <mailfile>\n" ); } @@ -49,7 +49,8 @@ static void print_help(void) int main(int argc, char **argv) { - const char *scriptfile, *recipient, *sender, *mailbox, *dumpfile, *mailfile; + const char *scriptfile, *recipient, *sender, *mailbox, *dumpfile, *mailfile, + *extensions; const char *user; int i; struct mail_raw *mailr; @@ -65,7 +66,8 @@ int main(int argc, char **argv) struct ostream *trace_stream = FALSE; /* Parse arguments */ - scriptfile = recipient = sender = mailbox = dumpfile = mailfile = NULL; + scriptfile = recipient = sender = mailbox = dumpfile = mailfile = + extensions = NULL; for (i = 1; i < argc; i++) { if (strcmp(argv[i], "-r") == 0) { /* recipient address */ @@ -91,6 +93,12 @@ int main(int argc, char **argv) if (i == argc) i_fatal("Missing -d argument"); dumpfile = argv[i]; + } else if (strcmp(argv[i], "-x") == 0) { + /* extensions */ + i++; + if (i == argc) + i_fatal("Missing -x argument"); + extensions = argv[i]; } else if (strcmp(argv[i], "-c") == 0) { /* force compile */ force_compile = TRUE; @@ -120,6 +128,10 @@ int main(int argc, char **argv) } sieve_tool_init(); + + if ( extensions != NULL ) { + sieve_set_extensions(extensions); + } /* Compile sieve script */ if ( force_compile ) { diff --git a/src/sieve-tools/sievec.c b/src/sieve-tools/sievec.c index 317a9402d455d607f09453cfa2363d9bc97d3bca..a9c03d6a68a1aa88cd1ebb0ca2e5f006cf55cb4c 100644 --- a/src/sieve-tools/sievec.c +++ b/src/sieve-tools/sievec.c @@ -21,7 +21,7 @@ static void print_help(void) { printf( -"Usage: sievec [-d] <scriptfile> <outfile>\n" +"Usage: sievec [-d] [-x <extensions>] <scriptfile> <outfile>\n" ); } @@ -33,15 +33,19 @@ int main(int argc, char **argv) { int i; struct sieve_binary *sbin; bool dump = FALSE; - const char *scriptfile, *outfile; - - sieve_tool_init(); - - scriptfile = outfile = NULL; + const char *scriptfile, *outfile, *extensions; + + scriptfile = outfile = extensions = NULL; for (i = 1; i < argc; i++) { if (strcmp(argv[i], "-d") == 0) { /* dump file */ dump = TRUE; + } else if (strcmp(argv[i], "-x") == 0) { + /* extensions */ + i++; + if (i == argc) + i_fatal("Missing -x argument"); + extensions = argv[i]; } else if ( scriptfile == NULL ) { scriptfile = argv[i]; } else if ( outfile == NULL ) { @@ -58,8 +62,17 @@ int main(int argc, char **argv) { } if ( outfile == NULL ) { - print_help(); - i_fatal("Missing <outfile> argument"); + if ( !dump ) { + print_help(); + i_fatal("The <outfile> argument is mandatory without -d"); + } + outfile = "-"; + } + + sieve_tool_init(); + + if ( extensions != NULL ) { + sieve_set_extensions(extensions); } sbin = sieve_tool_script_compile(scriptfile);