From 6a7c9ebd0b62a37019a89687dc83badda5cd2487 Mon Sep 17 00:00:00 2001 From: Andrea Dell'Amico Date: Wed, 23 Sep 2020 18:52:10 +0200 Subject: [PATCH] Fixes #904. ole, dmarc and clamav plugins --- README.md | 2 +- defaults/main.yml | 31 +++++ meta/main.yml | 7 +- tasks/spamassassin.yml | 107 ++++++++++++++++++ templates/clamav-github-plugin-conf.cf.j2 | 16 +++ templates/clamav-plugin-conf.cf.j2 | 5 + .../clamav-plugin-multiple-scores-conf.cf.j2 | 61 ++++++++++ templates/clamav-plugin.pm.j2 | 53 +++++++++ templates/dmarc.cf.j2 | 37 ++++++ templates/ole2macro.cf.j2 | 7 ++ 10 files changed, 324 insertions(+), 2 deletions(-) create mode 100644 templates/clamav-github-plugin-conf.cf.j2 create mode 100644 templates/clamav-plugin-conf.cf.j2 create mode 100644 templates/clamav-plugin-multiple-scores-conf.cf.j2 create mode 100644 templates/clamav-plugin.pm.j2 create mode 100644 templates/dmarc.cf.j2 create mode 100644 templates/ole2macro.cf.j2 diff --git a/README.md b/README.md index 569e504..dd93b5b 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ There are a lot of them, see the `defaults/main.yml` file Dependencies ------------ -None +clamav, when `spamassassin_clamav_plugin` is set to `True` License ------- diff --git a/defaults/main.yml b/defaults/main.yml index 091d9e3..802ec4b 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -115,6 +115,37 @@ spamassassin_local_rules: [] spamassassin_spamd_ssl_enabled: True spamassassin_spamd_ssl_opts: '--ssl --server-key {{ spamassassin_home }}/client-key.pem --server-cert {{ spamassassin_home }}/client-cert.pem' +# https://cwiki.apache.org/confluence/display/SPAMASSASSIN/ClamAVPlugin +# https://cwiki.apache.org/confluence/display/SPAMASSASSIN/ClamAVMultipleScores +spamassassin_clamav_old_plugin: False +spamassassin_clamav_multiple_scores: False +spamassassin_clamav_plugin_score: '4' +spamassassin_clamav_ms_heuristics_score: '3.0' + +# https://github.com/bigio/spamassassin-clamav +spamassassin_clamav_github_plugin: False +spamassassin_clamav_github_plugin_url: 'https://raw.githubusercontent.com/bigio/spamassassin-clamav/master/clamav.pm' + +# https://github.com/bigio/spamassassin-vba-macro +spamassassin_ole2macro_github_plugin: True +spamassassin_ole2macro_github_plugin_url: 'https://raw.githubusercontent.com/bigio/spamassassin-vba-macro/master/ole2macro.pm' +spamassassin_ole2macro_github_plugin_score: '3' + +# https://github.com/bigio/spamassassin-dmarc +spamassassin_dmarc_github_plugin: True +spamassassin_dmarc_github_plugin_url: 'https://raw.githubusercontent.com/bigio/spamassassin-dmarc/master/dmarc.pm' +spamassassin_dmarc_github_reject_score: '0.3' +spamassassin_dmarc_github_qar_score: '0.2' +spamassassin_dmarc_github_dmarc_none_score: '0.1' +spamassassin_dmarc_github_dmarc_missing_score: '0.0' +spamassassin_dmarc_github_dmarc_pass_score: '-0.1' + +spamassassin_dmarc_perl_packages: + - 'perl-IO-Compress' + - 'perl-IO-Compress-Lzma' + - 'perl-MIME-tools' + - 'perl-OLE-Storage_Lite' + psql_db_data: - { name: '{{ spamassassin_db_name }}', encoding: 'UTF8', user: '{{ spamassassin_db_user }}', roles: 'NOCREATEDB,NOSUPERUSER', pwd: '{{ spamassassin_db_pwd }}', managedb: True, allowed_hosts: '{{ spamassassin_db_allowed_hosts }}', extensions: [ '' ], schema_file: '/srv/spamassassin.sql' } diff --git a/meta/main.yml b/meta/main.yml index d48c856..4b0efb3 100644 --- a/meta/main.yml +++ b/meta/main.yml @@ -13,4 +13,9 @@ galaxy_info: - mail - antispam -dependencies: [] +dependencies: + - src: git+https://gitea-s2i2s.isti.cnr.it/ISTI-ansible-roles/ansible-role-clamav.git + version: master + name: clamav + state: latest + when: spamassassin_clamav_plugin diff --git a/tasks/spamassassin.yml b/tasks/spamassassin.yml index b3ca375..4ce4d20 100644 --- a/tasks/spamassassin.yml +++ b/tasks/spamassassin.yml @@ -24,16 +24,123 @@ block: - name: Install the pyzor pip packages pip: name={{ spamassassin_pyzor_pip_packages }} state=present + notify: Restart spamassassin - name: Create the pyzor home file: dest={{ spamassassin_conf_dir }}/pyzor state=directory owner={{ spamassassin_user }} mode=0750 - name: Install the pyzor configuration template: src=pyzor-config.j2 dest={{ spamassassin_conf_dir }}/pyzor/config owner=root group={{ spamassassin_user }} mode=0440 + notify: Restart spamassassin when: spamassassin_enable_pyzor tags: [ 'spamassassin', 'pyzor', 'spamassassin_conf' ] +- name: Clamav plugin from the spamassassin site + block: + - name: Install the Clamav plugin code + template: src=clamav-plugin.pm.j2 dest={{ spamassassin_conf_dir }}/clamav.pm owner=root group=root mode='0644' + notify: Restart spamassassin + + - name: Install the Clamav plugin configuration. Single score + template: src=clamav-plugin-conf.cf.j2 dest={{ spamassassin_conf_dir }}/clamav.cf owner=root group=root mode='0644' + notify: Restart spamassassin + when: not spamassassin_clamav_multiple_scores + + - name: Install the Clamav plugin configuration. Multiple scores + template: src=clamav-plugin-multiple-scores-conf.cf.j2 dest={{ spamassassin_conf_dir }}/clamav.cf owner=root group=root mode='0644' + notify: Restart spamassassin + when: spamassassin_clamav_multiple_scores + + when: + - spamassassin_clamav_old_plugin + - not spamassassin_clamav_github_plugin + tags: [ 'spamassassin', 'clamav', 'spamassassin_conf', 'clamav_spamassassin' ] + +- name: Clamav plugin, from github + block: + - name: Get the clamav plugin code from github + get_url: url={{ spamassassin_clamav_github_plugin_url }} dest={{ spamassassin_conf_dir }}/clamav.pm owner=root group=root mode='0644' + notify: Restart spamassassin + + - name: Install the Clamav github plugin configuration + template: src=clamav-github-plugin-conf.cf.j2 dest={{ spamassassin_conf_dir }}/clamav.cf owner=root group=root mode='0644' + notify: Restart spamassassin + + when: + - not spamassassin_clamav_old_plugin + - spamassassin_clamav_github_plugin + tags: [ 'spamassassin', 'clamav', 'spamassassin_conf', 'clamav_spamassassin' ] + +- name: Remove the clamav plugin + block: + - name: Remove the clamav plugin files + file: dest={{ spamassassin_conf_dir }}/{{ item }} state=absent + with_items: + - 'clamav.cf' + - 'clamav.pm' + notify: Restart spamassassin + + when: + - not spamassassin_clamav_old_plugin + - not spamassassin_clamav_github_plugin + tags: [ 'spamassassin', 'clamav', 'spamassassin_conf', 'clamav_spamassassin' ] + +- name: OLE2macro plugin, from github + block: + - name: Get the OLE2macro plugin code from github + get_url: url={{ spamassassin_ole2macro_github_plugin_url }} dest={{ spamassassin_conf_dir }}/ole2macro.pm owner=root group=root mode='0644' + notify: Restart spamassassin + + - name: Install the OLE2macro plugin configuration + template: src=ole2macro.cf.j2 dest={{ spamassassin_conf_dir }}/ole2macro.cf owner=root group=root mode='0644' + notify: Restart spamassassin + + - name: spamassassin packages, RH/CentOS + yum: pkg={{ spamassassin_dmarc_perl_packages }} state=present + when: ansible_distribution_file_variety == "RedHat" + + + when: spamassassin_ole2macro_github_plugin + tags: [ 'spamassassin', 'spamassassin_conf', 'spamassassin_ole2macro' ] + +- name: Remove the ole2macro plugin + block: + - name: Remove the clamav plugin files + file: dest={{ spamassassin_conf_dir }}/{{ item }} state=absent + with_items: + - 'ole2macro.cf' + - 'ole2macro.pm' + notify: Restart spamassassin + + when: not spamassassin_ole2macro_github_plugin + tags: [ 'spamassassin', 'spamassassin_conf', 'spamassassin_ole2macro' ] + +- name: dmarc plugin, from github + block: + - name: Get the dmarc plugin code from github + get_url: url={{ spamassassin_dmarc_github_plugin_url }} dest={{ spamassassin_conf_dir }}/dmarc.pm owner=root group=root mode='0644' + notify: Restart spamassassin + + - name: Install the dmarc plugin configuration + template: src=dmarc.cf.j2 dest={{ spamassassin_conf_dir }}/dmarc.cf owner=root group=root mode='0644' + notify: Restart spamassassin + + when: spamassassin_dmarc_github_plugin + tags: [ 'spamassassin', 'spamassassin_conf', 'spamassassin_dmarc' ] + +- name: Remove the ole2macro plugin + block: + - name: Remove the clamav plugin files + file: dest={{ spamassassin_conf_dir }}/{{ item }} state=absent + with_items: + - 'dmarc.cf' + - 'dmarc.pm' + notify: Restart spamassassin + + when: not spamassassin_dmarc_github_plugin + tags: [ 'spamassassin', 'spamassassin_conf', 'spamassassin_dmarc' ] + - name: Manage the letsencrypt configuration block: - name: Check if the letsencrypt certificates are in place diff --git a/templates/clamav-github-plugin-conf.cf.j2 b/templates/clamav-github-plugin-conf.cf.j2 new file mode 100644 index 0000000..81713f8 --- /dev/null +++ b/templates/clamav-github-plugin-conf.cf.j2 @@ -0,0 +1,16 @@ +loadplugin Mail::SpamAssassin::Plugin::Clamav clamav.pm + +clamd_sock {{ clamav_clamd_spamassassin_local_socket }} + +full AV_CLAMAV eval:check_clamav('OFFICIAL') +describe AV_CLAMAV Clamav AntiVirus detected a virus +score AV_CLAMAV {{ spamassassin_clamav_plugin_score }} + +full AV_CLAMAV_S eval:check_clamav('SecuriteInfo') +describe AV_CLAMAV_S Clamav AntiVirus detected a virus +score AV_CLAMAV_S 2.5 + +if can(Mail::SpamAssassin::Conf::feature_subjprefix) + subjprefix AV_CLAMAV ***VIRUS*** + subjprefix AV_CLAMAV_S ***VIRUS*** +endif diff --git a/templates/clamav-plugin-conf.cf.j2 b/templates/clamav-plugin-conf.cf.j2 new file mode 100644 index 0000000..e10ecf7 --- /dev/null +++ b/templates/clamav-plugin-conf.cf.j2 @@ -0,0 +1,5 @@ +loadplugin ClamAV clamav.pm +full CLAMAV eval:check_clamav() +describe CLAMAV Clam AntiVirus detected a virus +score CLAMAV {{ spamassassin_clamav_plugin_score }} +add_header all Virus _CLAMAVRESULT_ diff --git a/templates/clamav-plugin-multiple-scores-conf.cf.j2 b/templates/clamav-plugin-multiple-scores-conf.cf.j2 new file mode 100644 index 0000000..235f8dd --- /dev/null +++ b/templates/clamav-plugin-multiple-scores-conf.cf.j2 @@ -0,0 +1,61 @@ +loadplugin ClamAV clamav.pm +full CLAMAV eval:check_clamav() +describe CLAMAV Clam AntiVirus detected something... +score CLAMAV 0.001 + +# Look for specific types of ClamAV detections +header __CLAMAV_PHISH X-Spam-Virus =~ /Yes.{1,30}Phishing/i +header __CLAMAV_PHISH_HEUR X-Spam-Virus =~ /Yes.{1,30}Phishing\.Heuristics\.Email/ +header __CLAMAV_SANE X-Spam-Virus =~ /Yes.{1,30}Sanesecurity/i +header __CLAMAV_MBL X-Spam-Virus =~ /Yes.{1,30}MBL/ +header __CLAMAV_MSRBL X-Spam-Virus =~ /Yes.{1,30}MSRBL/ +header __CLAMAV_VX X-Spam-Virus =~ /Yes.{1,30}VX\./ + +# Give the above rules a very late priority so that they can see the output +# of previous rules - otherwise they don't work! Not sure what the correct +# priority should be but this seems to work... +priority __CLAMAV_PHISH 9999 +priority __CLAMAV_PHISH_HEUR 9999 +priority __CLAMAV_SANE 9999 +priority __CLAMAV_MBL 9999 +priority __CLAMAV_MSRBL 9999 +priority __CLAMAV_VX 9999 + +# Work out what ClamAV detected and score accordingly + +# ClamAV general signatures +meta CLAMAV_VIRUS (CLAMAV && !__CLAMAV_PHISH && !__CLAMAV_SANE && !__CLAMAV_MBL && !__CLAMAV_MSRBL && !__CLAMAV_VX) +describe CLAMAV_VIRUS Virus found by ClamAV default signatures +score CLAMAV_VIRUS 20.0 + +# ClamAV phishing signatures +meta CLAMAV_PHISH (CLAMAV && __CLAMAV_PHISH && !__CLAMAV_SANE && !__CLAMAV_PHISH_HEUR) +describe CLAMAV_PHISH Phishing email found by ClamAV default signatures +score CLAMAV_PHISH 10.0 + +# ClamAV phishing with heuristic engine (not signatures based, may lead to false positives) +# Available since ClamAV 0.91 +meta CLAMAV_PHISH_HEUR (CLAMAV && __CLAMAV_PHISH_HEUR) +describe CLAMAV_PHISH_HEUR Phishing email found by ClamAV heuristic engine +score CLAMAV_PHISH_HEUR {{ spamassassin_clamav_ms_heuristics_score }} + +# ClamAV SaneSecurity signatures from http://www.sanesecurity.com/clamav/ +meta CLAMAV_SANE (CLAMAV && __CLAMAV_SANE) +describe CLAMAV_SANE SPAM found by ClamAV SaneSecurity signatures +score CLAMAV_SANE 7.5 + +# ClamAV MBL signatures from http://www.malware.com.br/ +meta CLAMAV_MBL (CLAMAV && __CLAMAV_MBL) +describe CLAMAV_MBL Malware found by ClamAV MBL signatures +score CLAMAV_MBL 7.5 + +# ClamAV MSRBL signatures from http://www.msrbl.com/ +meta CLAMAV_MSRBL (CLAMAV && __CLAMAV_MSRBL) +describe CLAMAV_MSRBL SPAM found by ClamAV MSRBL signatures +score CLAMAV_MSRBL 2.0 + +# ClamAV SecuriteInfo.com VX malware signatures from +# http://www.securiteinfo.com/services/clamav_unofficial_malwares_signatures.shtml +meta CLAMAV_VX (CLAMAV && __CLAMAV_VX) +describe CLAMAV_VX Malware found by SecuriteInfo.com VX signatures +score CLAMAV_VX 5.0 diff --git a/templates/clamav-plugin.pm.j2 b/templates/clamav-plugin.pm.j2 new file mode 100644 index 0000000..d0c3b3d --- /dev/null +++ b/templates/clamav-plugin.pm.j2 @@ -0,0 +1,53 @@ +package ClamAV; +use strict; + +# version 2.0, 2010-01-07 +# - use SA public interface set_tag() and add_header, instead of +# pushing a header field directly into $conf->{headers_spam} + +# our $CLAMD_SOCK = 3310; # for TCP-based usage +our $CLAMD_SOCK = "{{ clamav_clamd_spamassassin_local_socket }}"; + +use Mail::SpamAssassin; +use Mail::SpamAssassin::Plugin; +use Mail::SpamAssassin::Logger; +use File::Scan::ClamAV; +our @ISA = qw(Mail::SpamAssassin::Plugin); + +sub new { + my ($class, $mailsa) = @_; + $class = ref($class) || $class; + my $self = $class->SUPER::new($mailsa); + bless($self, $class); + $self->register_eval_rule("check_clamav"); + return $self; +} + +sub check_clamav { + my($self, $pms, $fulltext) = @_; + dbg("ClamAV: invoking File::Scan::ClamAV, port/socket: %s", $CLAMD_SOCK); + my $clamav = new File::Scan::ClamAV(port => $CLAMD_SOCK); + my($code, $virus) = $clamav->streamscan(${$fulltext}); + my $isspam = 0; + my $header = ""; + if (!$code) { + my $errstr = $clamav->errstr(); + $header = "Error ($errstr)"; + } elsif ($code eq 'OK') { + $header = "No"; + } elsif ($code eq 'FOUND') { + $header = "Yes ($virus)"; + $isspam = 1; + # include the virus name in SpamAssassin's report + $pms->test_log($virus); + } else { + $header = "Error (Unknown return code from ClamAV: $code)"; + } + dbg("ClamAV: result - $header"); + $pms->set_tag('CLAMAVRESULT', $header); + # add a metadatum so that rules can match against the result too + $pms->{msg}->put_metadata('X-Spam-Virus',$header); + return $isspam; +} + +1; diff --git a/templates/dmarc.cf.j2 b/templates/dmarc.cf.j2 new file mode 100644 index 0000000..34d99bc --- /dev/null +++ b/templates/dmarc.cf.j2 @@ -0,0 +1,37 @@ +loadplugin Mail::SpamAssassin::Plugin::Dmarc dmarc.pm + +ifplugin Mail::SpamAssassin::Plugin::Dmarc + ifplugin Mail::SpamAssassin::Plugin::DKIM + ifplugin Mail::SpamAssassin::Plugin::SPF + dmarc_save_reports 0 + + meta __DKIM_DEP ( DKIM_VALID || DKIM_INVALID || __DKIM_DEPENDABLE ) + meta __SPF_DEP ( SPF_NONE || SPF_FAIL || SPF_SOFTFAIL || SPF_PASS ) + + header __DMARC_REJECT eval:check_dmarc_reject() + meta DMARC_REJECT ( ( __DKIM_DEP || __SPF_DEP ) && __DMARC_REJECT ) + describe DMARC_REJECT DMARC fail with reject policy + score DMARC_REJECT {{ spamassassin_dmarc_github_reject_score }} + + header __DMARC_QUAR eval:check_dmarc_quarantine() + meta DMARC_QUAR ( ( __DKIM_DEP || __SPF_DEP ) && __DMARC_QUAR ) + describe DMARC_QUAR DMARC fail with quarantine policy + score DMARC_QUAR {{ spamassassin_dmarc_github_qar_score }} + + header __DMARC_NONE eval:check_dmarc_none() + meta DMARC_NONE ( ( __DKIM_DEP || __SPF_DEP ) && __DMARC_NONE ) + describe DMARC_NONE DMARC fail with none policy + score DMARC_NONE {{ spamassassin_dmarc_github_dmarc_none_score }} + + header __DMARC_MISSING eval:check_dmarc_missing() + meta DMARC_MISSING ( ( __DKIM_DEP || __SPF_DEP ) && __DMARC_MISSING ) + describe DMARC_MISSING DMARC policy missing + score DMARC_MISSING {{ spamassassin_dmarc_github_dmarc_missing_score }} + + header __DMARC_PASS eval:check_dmarc_pass() + meta DMARC_PASS ( ( __DKIM_DEP || __SPF_DEP ) && __DMARC_PASS ) + describe DMARC_PASS DMARC tests pass + score DMARC_PASS {{ spamassassin_dmarc_github_dmarc_pass_score }} + endif + endif +endif diff --git a/templates/ole2macro.cf.j2 b/templates/ole2macro.cf.j2 new file mode 100644 index 0000000..d21b486 --- /dev/null +++ b/templates/ole2macro.cf.j2 @@ -0,0 +1,7 @@ +loadplugin Mail::SpamAssassin::Plugin::OLE2Macro ole2macro.pm + +ifplugin Mail::SpamAssassin::Plugin::OLE2Macro +body MICROSOFT_OLE2MACRO eval:check_microsoft_ole2macro() +describe MICROSOFT_OLE2MACRO Has an attachment that contains an OLE2 Macro +score MICROSOFT_OLE2MACRO {{ spamassassin_vbamacro_github_plugin_score }} +endif