diff --git a/target/scripts/start-mailserver.sh b/target/scripts/start-mailserver.sh index af800730..f18abdf6 100755 --- a/target/scripts/start-mailserver.sh +++ b/target/scripts/start-mailserver.sh @@ -49,6 +49,7 @@ function _register_functions() { _register_setup_function '_setup_dovecot_sieve' _register_setup_function '_setup_dovecot_dhparam' _register_setup_function '_setup_dovecot_quota' + _register_setup_function '_setup_spam_subject' _register_setup_function '_setup_spam_to_junk' _register_setup_function '_setup_spam_mark_as_read' fi diff --git a/target/scripts/startup/setup.d/security/misc.sh b/target/scripts/startup/setup.d/security/misc.sh index 5d016870..b20f3613 100644 --- a/target/scripts/startup/setup.d/security/misc.sh +++ b/target/scripts/startup/setup.d/security/misc.sh @@ -81,13 +81,9 @@ function __setup__security__spamassassin() { # shellcheck disable=SC2016 sed -i -r 's|^\$sa_kill_level_deflt (.*);|\$sa_kill_level_deflt = '"${SA_KILL}"';|g' /etc/amavis/conf.d/20-debian_defaults - if [[ -z ${SPAM_SUBJECT} ]]; then - # shellcheck disable=SC2016 - sed -i -r 's|^\$sa_spam_subject_tag (.*);|\$sa_spam_subject_tag = undef;|g' /etc/amavis/conf.d/20-debian_defaults - else - # shellcheck disable=SC2016 - sed -i -r 's|^\$sa_spam_subject_tag (.*);|\$sa_spam_subject_tag = '"'${SPAM_SUBJECT}'"';|g' /etc/amavis/conf.d/20-debian_defaults - fi + # disable rewriting the subject as this is handles by _setup_spam_subject (which uses Dovecot Sieve) + # shellcheck disable=SC2016 + sed -i -r 's|^\$sa_spam_subject_tag (.*);|\$sa_spam_subject_tag = undef;|g' /etc/amavis/conf.d/20-debian_defaults # activate short circuits when SA BAYES is certain it has spam or ham. if [[ ${SA_SHORTCIRCUIT_BAYES_SPAM} -eq 1 ]]; then @@ -245,6 +241,56 @@ function __setup__security__amavis() { fi } +# If `SPAM_SUBJECT` is not empty, we create a Sieve script that alters the `Subject` +# header, in order to prepend a user-defined string. +function _setup_spam_subject() { + if [[ -z ${SPAM_SUBJECT} ]] + then + __rspamd__log 'debug' 'Spam subject is not set - no prefix will be added to spam e-mails' + else + __rspamd__log 'debug' "Spam subject is set - the prefix '${SPAM_SUBJECT}' will be added to spam e-mails" + + __rspamd__log 'trace' "Enabling '+editheader' Sieve extension" + # check whether sieve_global_extensions is disabled (and enabled it if so) + sed -i -E 's|#(sieve_global_extensions.*)|\1|' /etc/dovecot/conf.d/90-sieve.conf + # then append the extension + sedfile -i -E 's|(sieve_global_extensions.*)|\1 +editheader|' /etc/dovecot/conf.d/90-sieve.conf + + # This directory contains Sieve scripts that are executed before user-defined Sieve + # scripts run. + local DOVECOT_SIEVE_GLOBAL_BEFORE_DIR='/usr/lib/dovecot/sieve-global/before' + local DOVECOT_SIEVE_FILE='spam_subject' + readonly DOVECOT_SIEVE_GLOBAL_BEFORE_DIR DOVECOT_SIEVE_FILE + + mkdir -p "${DOVECOT_SIEVE_GLOBAL_BEFORE_DIR}" + # ref: https://superuser.com/a/1502589 + cat >"${DOVECOT_SIEVE_GLOBAL_BEFORE_DIR}/${DOVECOT_SIEVE_FILE}.sieve" << EOF +require ["editheader","variables"]; + +if anyof (header :contains "X-Spam-Flag" "YES", + header :contains "X-Spam" "Yes") +{ + # Match the entire subject ... + if header :matches "Subject" "*" { + # ... to get it in a match group that can then be stored in a variable: + set "subject" "\${1}"; + } + + # We can't "replace" a header, but we can delete (all instances of) it and + # re-add (a single instance of) it: + deleteheader "Subject"; + + # Note that the header is added ":last" (so it won't appear before possible + # "Received" headers). + addheader :last "Subject" "${SPAM_SUBJECT}\${subject}"; +} +EOF + + sievec "${DOVECOT_SIEVE_GLOBAL_BEFORE_DIR}/${DOVECOT_SIEVE_FILE}.sieve" + chown dovecot:root "${DOVECOT_SIEVE_GLOBAL_BEFORE_DIR}/${DOVECOT_SIEVE_FILE}."{sieve,svbin} + fi +} + # We can use Sieve to move spam emails to the "Junk" folder. function _setup_spam_to_junk() { if [[ ${MOVE_SPAM_TO_JUNK} -eq 1 ]]; then diff --git a/target/scripts/startup/setup.d/security/rspamd.sh b/target/scripts/startup/setup.d/security/rspamd.sh index db455fc6..86786932 100644 --- a/target/scripts/startup/setup.d/security/rspamd.sh +++ b/target/scripts/startup/setup.d/security/rspamd.sh @@ -21,7 +21,6 @@ function _setup_rspamd() { __rspamd__setup_greylisting __rspamd__setup_hfilter_group __rspamd__setup_check_authenticated - __rspamd__setup_spam_subject _rspamd_handle_user_modules_adjustments # must run last # only performing checks, no further setup handled from here onwards @@ -305,55 +304,6 @@ function __rspamd__setup_check_authenticated() { fi } -# If `SPAM_SUBJECT` is not empty, we create a Sieve script that alters the `Subject` -# header, in order to prepend a user-defined string. -function __rspamd__setup_spam_subject() { - if [[ -z ${SPAM_SUBJECT} ]] - then - __rspamd__log 'debug' 'Spam subject is not set - no prefix will be added to spam e-mails' - else - __rspamd__log 'debug' "Spam subject is set - the prefix '${SPAM_SUBJECT}' will be added to spam e-mails" - - __rspamd__log 'trace' "Enabling '+editheader' Sieve extension" - # check whether sieve_global_extensions is disabled (and enabled it if so) - sed -i -E 's|#(sieve_global_extensions.*)|\1|' /etc/dovecot/conf.d/90-sieve.conf - # then append the extension - sedfile -i -E 's|(sieve_global_extensions.*)|\1 +editheader|' /etc/dovecot/conf.d/90-sieve.conf - - # This directory contains Sieve scripts that are executed before user-defined Sieve - # scripts run. - local DOVECOT_SIEVE_GLOBAL_BEFORE_DIR='/usr/lib/dovecot/sieve-global/before' - local DOVECOT_SIEVE_FILE='rspamd_spam_subject' - readonly DOVECOT_SIEVE_GLOBAL_BEFORE_DIR DOVECOT_SIEVE_FILE - - mkdir -p "${DOVECOT_SIEVE_GLOBAL_BEFORE_DIR}" - # ref: https://superuser.com/a/1502589 - cat >"${DOVECOT_SIEVE_GLOBAL_BEFORE_DIR}/${DOVECOT_SIEVE_FILE}.sieve" << EOF -require ["editheader","variables"]; - -if header :contains "X-Spam" "Yes" -{ - # Match the entire subject ... - if header :matches "Subject" "*" { - # ... to get it in a match group that can then be stored in a variable: - set "subject" "\${1}"; - } - - # We can't "replace" a header, but we can delete (all instances of) it and - # re-add (a single instance of) it: - deleteheader "Subject"; - - # Note that the header is added ":last" (so it won't appear before possible - # "Received" headers). - addheader :last "Subject" "${SPAM_SUBJECT}\${subject}"; -} -EOF - - sievec "${DOVECOT_SIEVE_GLOBAL_BEFORE_DIR}/${DOVECOT_SIEVE_FILE}.sieve" - chown dovecot:root "${DOVECOT_SIEVE_GLOBAL_BEFORE_DIR}/${DOVECOT_SIEVE_FILE}."{sieve,svbin} - fi -} - # This function performs a simple check: go through DKIM configuration files, acquire # all private key file locations and check whether they exist and whether they can be # accessed by Rspamd.