From 62e28636566eefb0c1f8c36f69ad29f7b59222b6 Mon Sep 17 00:00:00 2001 From: Suraj Patil Date: Sun, 9 Aug 2026 22:09:30 +0530 Subject: [PATCH] [clamav] Add plugin for ClamAV ClamAV is packaged for Fedora, RHEL via EPEL, Debian and Ubuntu, but sos has no plugin for it and no other plugin references it. Neither the daemon configuration, the freshclam update state nor the signature database age reaches an sosreport. The configuration layout differs by distribution: Red Hat splits the daemon configuration into /etc/clamd.d/ while Debian keeps everything under /etc/clamav/, so both are collected. Defaults are taken from the upstream samples in etc/, which set DatabaseDirectory to /var/lib/clamav and UpdateLogFile to /var/log/freshclam.log. clamconf is ClamAV's own configuration dump utility and is run in preference to parsing the files directly. The signature database is not copied. It is hundreds of megabytes of binary .cvd data; a directory listing still shows which definitions are present and how old they are. etc/freshclam.conf.sample documents HTTPProxyUsername and HTTPProxyPassword for outbound proxy access, so postproc() redacts both. HTTPProxyServer is left intact. Example of the substitution: HTTPProxyPassword mypass -> HTTPProxyPassword ******** Signed-off-by: Suraj Patil --- sos/report/plugins/clamav.py | 80 ++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 sos/report/plugins/clamav.py diff --git a/sos/report/plugins/clamav.py b/sos/report/plugins/clamav.py new file mode 100644 index 0000000000..34d6564d77 --- /dev/null +++ b/sos/report/plugins/clamav.py @@ -0,0 +1,80 @@ +# Copyright (C) 2026 Suraj Patil + +# This file is part of the sos project: https://github.com/sosreport/sos +# +# This copyrighted material is made available to anyone wishing to use, +# modify, copy, or redistribute it subject to the terms and conditions of +# version 2 of the GNU General Public License. +# +# See the LICENSE file in the source distribution for further information. + +from sos.report.plugins import Plugin, IndependentPlugin + + +class ClamAV(Plugin, IndependentPlugin): + + short_desc = 'ClamAV antivirus' + + plugin_name = 'clamav' + profiles = ('security', 'services') + + packages = ('clamav', 'clamd', 'clamav-freshclam', 'clamav-daemon') + files = ('/etc/clamd.conf', '/etc/clamav/clamd.conf') + services = ('clamav-daemon', 'clamav-freshclam', 'freshclam') + + def setup(self): + # Red Hat splits the daemon configuration into /etc/clamd.d/, + # Debian keeps everything under /etc/clamav/. + self.add_copy_spec([ + '/etc/clamd.conf', + '/etc/clamd.d/', + '/etc/freshclam.conf', + '/etc/clamav/', + '/etc/sysconfig/clamav-milter', + ]) + + self.add_copy_spec([ + '/var/log/clamav/*.log', + '/var/log/freshclam.log', + '/var/log/clamd.scan', + ]) + + if self.get_option('all_logs'): + self.add_copy_spec([ + '/var/log/clamav/', + '/var/log/freshclam.log*', + ]) + + # DatabaseDirectory is configurable; fall back to the upstream + # default if freshclam.conf does not set it or cannot be read. + db_dir = '/var/lib/clamav' + config_files = ( + '/etc/freshclam.conf', + '/etc/clamav/freshclam.conf', + ) + for config_file in config_files: + try: + with open(config_file, 'r', encoding='UTF-8') as cfile: + for line in cfile.read().splitlines(): + words = line.split() + if words and words[0] == 'DatabaseDirectory': + db_dir = words[1] + except IOError: + continue + + # The signature database is large and binary; a listing is enough + # to show which definitions are present and how old they are. + self.add_dir_listing(db_dir, tags='clamav_database') + + self.add_cmd_output('clamconf', tags='clamconf') + + def postproc(self): + # freshclam.conf may hold credentials for an outbound proxy. + # + # HTTPProxyPassword mypass -> HTTPProxyPassword ******** + self.do_path_regex_sub( + r'/etc/(clamav/)?freshclam\.conf', + r'(HTTPProxy(?:Password|Username)\s+)\S+', + r'\1********') + +# vim: set et ts=4 sw=4 :