dovecot-lda: timeout for external scripts called by sieve
Hello,
I have a small problem with dovecot-lda. I am using Debian 12 Bookworm:
root@lnxmail01:~# dovecot --version 2.3.13 (89f716dc2)
Historically grown (probably still from sendmail times, long time ago) I always used procmail for local e-mail delivery. This also included the call for spamc for SpamAssassin.
I have now changed this and set up a route via sieve. There is a small script for this:
root@lnxmail01:~# cat /usr/lib/dovecot/sieve-filter/spamc-filter.sh #!/bin/bash
/usr/bin/spamc
My sieve configuration says (in extracts):
root@lnxmail01:~# head -12 ~meini/.dovecot.sieve ## Generated by Roundcube Webmail SieveRules Plugin ##
require ["body","comparator-i;ascii-numeric","copy","envelope","fileinto","imap4flags","include","regex","relational","spamtestplus","vacation","variables","spamtest"];
include :global "spamc";
# rule:[Spam] if spamtest :value "ge" :comparator "i;ascii-numeric" "5" { fileinto "Spam"; stop; }
In general, this has been working for many months without any problems. But sometimes the whole thing fails due to a timeout:
Jul 7 22:00:13 lnxmail01 dovecot:
lda(meini)<766014>
The worst thing is that the entire mail is lost (/dev/null)!
Then I tried to set the timeout higher (than the current 10 seconds):
root@lnxmail01:~# doveconf | grep -A 12 ^plugin plugin { sieve = file:~/sieve;active=~/.dovecot.sieve sieve_execute_exec_timeout = 60s sieve_extension_exec_timeout = 60s sieve_extensions = +vnd.dovecot.filter +spamtest +spamtestplus sieve_filter_bin_dir = /usr/lib/dovecot/sieve-filter sieve_filter_socket_dir = sieve-filter sieve_global = /usr/lib/dovecot/sieve-global sieve_plugins = sieve_extprograms sieve_spamtest_max_value = 5 sieve_spamtest_status_header = X-Spam-Level sieve_spamtest_status_type = strlen }
I have set both the values for "sieve_execute_exec_timeout" and "sieve_extension_exec_timeout" to 60 sec, but according to the log, this does not seem to affect the 10000 msec mentioned therein.
The SpamAssassin daemon has enough child processes to handle the requests (most of them were idle at the time of the error).
How can I configure that the external script gets more time for execution? And what can I do so that - should the script terminate contrary to expectations or be killed in the timeout - the mail is not lost but simply processed further?
Many thanks & best regards Meinhard
On 09/07/2024 09:02, Meinhard Schneider via dovecot wrote:
Hello,
I have a small problem with dovecot-lda. I am using Debian 12 Bookworm:
root@lnxmail01:~# dovecot --version 2.3.13 (89f716dc2)
Historically grown (probably still from sendmail times, long time ago) I always used procmail for local e-mail delivery. This also included the call for spamc for SpamAssassin.
I have now changed this and set up a route via sieve. There is a small script for this:
root@lnxmail01:~# cat /usr/lib/dovecot/sieve-filter/spamc-filter.sh #!/bin/bash
/usr/bin/spamc
My sieve configuration says (in extracts):
root@lnxmail01:~# head -12 ~meini/.dovecot.sieve ## Generated by Roundcube Webmail SieveRules Plugin ##
require ["body","comparator-i;ascii-numeric","copy","envelope","fileinto","imap4flags","include","regex","relational","spamtestplus","vacation","variables","spamtest"];
include :global "spamc";
# rule:[Spam] if spamtest :value "ge" :comparator "i;ascii-numeric" "5" { fileinto "Spam"; stop; }
In general, this has been working for many months without any problems. But sometimes the whole thing fails due to a timeout:
Jul 7 22:00:13 lnxmail01 dovecot: lda(meini)<766014>
: Error: program exec:/usr/lib/dovecot/sieve-filter/spamc-filter.sh (766016): Execution timed out (> 10000 msecs) Jul 7 22:00:13 lnxmail01 dovecot: lda(meini)<766014> : Error: program exec:/usr/lib/dovecot/sieve-filter/spamc-filter.sh (766016): Forcibly terminated with signal 15 Jul 7 22:00:13 lnxmail01 dovecot: lda(meini)<766014> : Panic: output stream (temp iostream in /tmp/dovecot.lda. for (program client seekable output)) is missing error handling Jul 7 22:00:13 lnxmail01 dovecot: lda(meini)<766014> : Error: Raw backtrace: /usr/lib/dovecot/libdovecot.so.0(backtrace_append+0x42) [0x7ff00aee04e2] -> /usr/lib/dovecot/libdovecot.so.0(backtrace_get+0x1e) [0x7ff00aee05fe] -> /usr/lib/dovecot/libdovecot.so.0(+0xfc49b) [0x7ff00aeec49b] -> /usr/lib/dovecot/libdovecot.so.0(+0xfc501) [0x7ff00aeec501] -> /usr/lib/dovecot/libdovecot.so.0(+0x53aee) [0x7ff00ae43aee] -> /usr/lib/dovecot/libdovecot.so.0(o_stream_unref+0x5e) [0x7ff00af1003e] -> /usr/lib/dovecot/libdovecot.so.0(program_client_destroy+0x8e) [0x7ff00ae6ee6e] -> /usr/lib/dovecot/modules/sieve/lib90_sieve_extprograms_plugin.so(sieve_extprogram_destroy+0x18) [0x7ff00aacd8f8] -> /usr/lib/dovecot/modules/sieve/lib90_sieve_extprograms_plugin.so(+0x556d) [0x7ff00aacb56d] -> /usr/lib/dovecot/libdovecot-sieve.so.0(sieve_interpreter_continue+0xea) [0x7ff00ab4c9ba] -> /usr/lib/dovecot/libdovecot-sieve.so.0(ext_include_execute_include+0x2c7) [0x7ff00ab72e17] -> /usr/lib/dovecot/libdovecot-sieve.so.0(sieve_interpreter_continue+0xea) [0x7ff00ab4c9ba] -> /usr/lib/dovecot/libdovecot-sieve.so.0(sieve_multiscript_run+0x82) [0x7ff00ab62b32] -> /usr/lib/dovecot/modules/lib90_sieve_plugin.so(+0x37a3) [0x7ff00abd47a3] -> /usr/lib/dovecot/libdovecot-lda.so.0(mail_deliver+0x176) [0x7ff00b11f906] -> /usr/lib/dovecot/dovecot-lda(main+0x879) [0x55ef085e4fb9] -> /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xea) [0x7ff00ac3ad0a] -> /usr/lib/dovecot/dovecot-lda(_start+0x2a) [0x55ef085e56ea] The worst thing is that the entire mail is lost (/dev/null)!
Then I tried to set the timeout higher (than the current 10 seconds):
root@lnxmail01:~# doveconf | grep -A 12 ^plugin plugin { sieve = file:~/sieve;active=~/.dovecot.sieve sieve_execute_exec_timeout = 60s sieve_extension_exec_timeout = 60s sieve_extensions = +vnd.dovecot.filter +spamtest +spamtestplus sieve_filter_bin_dir = /usr/lib/dovecot/sieve-filter sieve_filter_socket_dir = sieve-filter sieve_global = /usr/lib/dovecot/sieve-global sieve_plugins = sieve_extprograms sieve_spamtest_max_value = 5 sieve_spamtest_status_header = X-Spam-Level sieve_spamtest_status_type = strlen }
I have set both the values for "sieve_execute_exec_timeout" and "sieve_extension_exec_timeout" to 60 sec, but according to the log, this does not seem to affect the 10000 msec mentioned therein.
The SpamAssassin daemon has enough child processes to handle the requests (most of them were idle at the time of the error).
How can I configure that the external script gets more time for execution? And what can I do so that - should the script terminate contrary to expectations or be killed in the timeout - the mail is not lost but simply processed further?
Many thanks & best regards Meinhard
Hi Mainhard
I can see the error in the log lines you posted above, but I don't see anything in your configuration that invokes /usr/lib/dovecot/sieve-filter/spamc-filter.sh script.
John
On 10/07/2024 09:40, John Fawcett via dovecot wrote:
On 09/07/2024 09:02, Meinhard Schneider via dovecot wrote:
Hello, ....
I have set both the values for "sieve_execute_exec_timeout" and "sieve_extension_exec_timeout" to 60 sec, but according to the log, this does not seem to affect the 10000 msec mentioned therein.
The SpamAssassin daemon has enough child processes to handle the requests (most of them were idle at the time of the error).
How can I configure that the external script gets more time for execution? And what can I do so that - should the script terminate contrary to expectations or be killed in the timeout - the mail is not lost but simply processed further?
Many thanks & best regards Meinhard
Hi Mainhard
I can see the error in the log lines you posted above, but I don't see anything in your configuration that invokes /usr/lib/dovecot/sieve-filter/spamc-filter.sh script.
John
Just one thing I noticed which could well be relevant to the issue. Seems there is no setting called "|sieve_extension_exec_timeout|".
|For sieve_extension_socket_dir|and |sieve_extension_bin_dir| you correctly substituted extension with filter, but you did not do the same with sieve_extension_exec_timeout which should be sieve_pipe_exec_timeout
https://doc.dovecot.org/configuration_manual/sieve/plugins/extprograms/
The three extensions introduced by this plugin
-|vnd.dovecot.pipe|,|vnd.dovecot.filter|and|vnd.dovecot.execute|-
each have separate but similar configuration. The following
configuration settings are used, for which “<extension>” in the
setting name is replaced by
either|pipe|,|filter|or|execute|depending on which extension is
being configured:
|sieve_extension_socket_dir|=
Points to a directory relative to the Dovecot base_dir where the
plugin looks for script service sockets.
|sieve_extension_bin_dir|=
Points to a directory where the plugin looks for programs (shell
scripts) to execute directly and pipe messages to.
|sieve_extension_exec_timeout|= 10s
Configures the maximum execution time after which the program is
forcibly terminated.
John
Corrected a typo in the previous message, should have read sieve_filter_exec_timeout and not sieve_pipe_exec_timeout
On 10/07/2024 10:41, John Fawcett wrote:
On 10/07/2024 09:40, John Fawcett via dovecot wrote:
On 09/07/2024 09:02, Meinhard Schneider via dovecot wrote:
Hello, ....
I have set both the values for "sieve_execute_exec_timeout" and "sieve_extension_exec_timeout" to 60 sec, but according to the log, this does not seem to affect the 10000 msec mentioned therein.
The SpamAssassin daemon has enough child processes to handle the requests (most of them were idle at the time of the error).
How can I configure that the external script gets more time for execution? And what can I do so that - should the script terminate contrary to expectations or be killed in the timeout - the mail is not lost but simply processed further?
Many thanks & best regards Meinhard
Hi Mainhard
I can see the error in the log lines you posted above, but I don't see anything in your configuration that invokes /usr/lib/dovecot/sieve-filter/spamc-filter.sh script.
John
Just one thing I noticed which could well be relevant to the issue. Seems there is no setting called "|sieve_extension_exec_timeout|".
|For sieve_extension_socket_dir|and |sieve_extension_bin_dir| you correctly substituted extension with filter, but you did not do the same with sieve_extension_exec_timeout which should be sieve_filter_exec_timeout
https://doc.dovecot.org/configuration_manual/sieve/plugins/extprograms/
The three extensions introduced by this plugin -|vnd.dovecot.pipe|,|vnd.dovecot.filter|and|vnd.dovecot.execute|- each have separate but similar configuration. The following configuration settings are used, for which “<extension>” in the setting name is replaced by either|pipe|,|filter|or|execute|depending on which extension is being configured: |sieve_extension_socket_dir|= Points to a directory relative to the Dovecot base_dir where the plugin looks for script service sockets. |sieve_extension_bin_dir|= Points to a directory where the plugin looks for programs (shell scripts) to execute directly and pipe messages to. |sieve_extension_exec_timeout|= 10s Configures the maximum execution time after which the program is forcibly terminated.
John
Hello,
I have now adjusted the values accordingly:
root@lnxmail01:~# doveconf | grep -A 13 ^plugin plugin { sieve = file:~/sieve;active=~/.dovecot.sieve sieve_execute_exec_timeout = 60s sieve_extensions = +vnd.dovecot.filter +spamtest +spamtestplus sieve_filter_bin_dir = /usr/lib/dovecot/sieve-filter sieve_filter_exec_timeout = 60s sieve_filter_socket_dir = sieve-filter sieve_global = /usr/lib/dovecot/sieve-global sieve_pipe_exec_timeout = 60s sieve_plugins = sieve_extprograms sieve_spamtest_max_value = 5 sieve_spamtest_status_header = X-Spam-Level sieve_spamtest_status_type = strlen }
I will observe whether the problems continue to occur.
Nevertheless, I would like to know if there is a way to prevent the e-mails from being completely discarded if an error occurs.
The program /usr/lib/dovecot/sieve-filter/spamc-filter.sh is executed because there is an include in the file .dovecot.sieve: include :global “spamc”; This is sufficient to start the filter “spamc-filter.sh” (I got this from a guide on the Internet, but I can't find the link to it now).
The problem is that only spamc is started in the script and STDIN and STDOUT are connected to dovecot-lda. It would be easy to abort the call of spamc after X seconds (man 'timeout(1)'). But then the input provided by dovecot-lda and piped into spamc would be lost. You would therefore have to cache all input in the script that comes via STDIN in a file. If spamc is aborted, the script would have to recognize this and output the contents of this file again via STDOUT. spamc must be called using 'timeout' and the timeout used must be less than what was set for sieve_filter_exec_timeout. This would then save the mail from /dev/null.
Unfortunately, I currently see no other way to solve this problem.
Or does anyone have another idea how to tackle this issue?
Many thanks & best regards Meinhard
On 27/07/2024 21:26, Meinhard Schneider via dovecot wrote:
Hello,
I have now adjusted the values accordingly:
root@lnxmail01:~# doveconf | grep -A 13 ^plugin plugin { sieve = file:~/sieve;active=~/.dovecot.sieve sieve_execute_exec_timeout = 60s sieve_extensions = +vnd.dovecot.filter +spamtest +spamtestplus sieve_filter_bin_dir = /usr/lib/dovecot/sieve-filter sieve_filter_exec_timeout = 60s sieve_filter_socket_dir = sieve-filter sieve_global = /usr/lib/dovecot/sieve-global sieve_pipe_exec_timeout = 60s sieve_plugins = sieve_extprograms sieve_spamtest_max_value = 5 sieve_spamtest_status_header = X-Spam-Level sieve_spamtest_status_type = strlen }
I will observe whether the problems continue to occur.
I guess that the possibility of problems happening is still there since whatever timeout you put, it could be exceeded. It doesn't seem like a robust way of filtering.
Nevertheless, I would like to know if there is a way to prevent the e-mails from being completely discarded if an error occurs.
I would expect Dovecot and Pigeonhole not to discard emails in the case of errors. My expectation would be that if the script returns an error code then the email will be kept by default. Do you have any evidence of discarding email in the case of errors, where the scripts is returning an error to dovecot but it is ignored?
As for discarding emails when the script times out, I believe you are right about that. On the face of it it seems the wrong thing to do but I guess there may be an explanation that I don't know as to why it works that way.
The program /usr/lib/dovecot/sieve-filter/spamc-filter.sh is executed because there is an include in the file .dovecot.sieve: include :global “spamc”; This is sufficient to start the filter “spamc-filter.sh” (I got this from a guide on the Internet, but I can't find the link to it now).
My understanding is that this will include another sieve script called "spamc", not directly call an external comamnd.
The problem is that only spamc is started in the script and STDIN and STDOUT are connected to dovecot-lda. It would be easy to abort the call of spamc after X seconds (man 'timeout(1)'). But then the input provided by dovecot-lda and piped into spamc would be lost. You would therefore have to cache all input in the script that comes via STDIN in a file. If spamc is aborted, the script would have to recognize this and output the contents of this file again via STDOUT. spamc must be called using 'timeout' and the timeout used must be less than what was set for sieve_filter_exec_timeout. This would then save the mail from /dev/null.
Unfortunately, I currently see no other way to solve this problem.
Or does anyone have another idea how to tackle this issue?
Maybe you could work out how to return an error code from the script after a timeout (before the dovecot timeout kicks in and kills it). I'm not convinced you'd need to worry about STDIN and STDOUT. You could check this easily by having a test script which returns a non zero value (e.g. exit 1).
John
participants (2)
-
John Fawcett
-
Meinhard Schneider