Installing and automating ClamAV on macOS
18 August 2017
What’s going down
ClamAV is anti-virus software developed by Cisco. It runs on macOS, the BSDs, Linux, Windows etc.
Even though you’re obviously exercising caution in your daily computing, sometimes it’s worth scanning for software to see if you’ve picked up any malware, even if it hasn’t been able to affect you.
All of the ClamAV setup can be found in the manual.
Throughout, the macOS directory Users
can be substituted by home
on BSD or Linux and use of $
means that you type what follows.
Manual
To view the manual at any time, just man clamscan
or use the link above.
Install
Installation is easier with Homebrew.
$ brew install clamav
Create and edit configuration files
$ cd /usr/local/etc/clamav
$ cp freshclam.conf.sample freshclam.conf
$ vi freshclam.conf
Comment/Uncomment the following lines, so they look like this:
# Example
SubmitDetectionStats /var/logs/clamav
Update database
$ freshclam
If the output is OK, create a log file in /var/log (owned by clamav or another user freshclam will be running as):
$ touch /var/log/freshclam.log
$ chmod 600 /var/log/freshclam.log
$ chown clamav /var/log/freshclam.log
Then run the following to start the freshclam daemon:
$ freshclam -d
However, we may find that we get the error:
ERROR: Can't open /var/log/freshclam.log in append mode (check permissions!).
ERROR: Problem with internal logger (UpdateLogFile = /var/log/freshclam.log).
In which case, we need to edit the following file and comment out the lines so they appear as indicated:
$ vi /usr/local/etc/clamav/freshclam.conf
DatabaseOwner clamav
UpdateLogFile /var/log/freshclam.log
We need to make a similar edit to clamd.conf
, but first we need to make it from the provided sample:
$ cd /usr/local/etc/clamav
$ cp clamd.conf.sample clamd.conf
$ vi clamd.conf
User clamav
chown clamav:wheel clamd.conf freshclam.conf
This will run the daemon in the background – until shutdown.
To make it persist, it’s suggested to use cron
and have it run 2+ times per hour.
This is fine for BSD and Linux environments but, seeing as cron
’s deprecated in macOS, we ought to be using launchd
.
To run under cron
, you have to add the following to the crontab
of either root
or the user clamav
, where ‘N’ is the minutes past the hour at which you want the task to run:
N * * * * /usr/local/bin/freshclam --quiet
The launchd
approach is to paste the following into a LaunchDaemon located at /Library/LaunchDaemons, named something like com.personal.freshclam.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.personal.freshclam</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/freshclam</string>
<string>-d</string>
</array>
<key>KeepAlive</key>
<false/>
<key>RunAtLoad</key>
<true/>
<key>StartInterval</key>
<integer>1800</integer>
</dict>
</plist>
This will run every 30 minutes and check for updates to the database.
Now start the freshclam
service:
$ sudo launchctl load /Library/LaunchDaemons/com.personal.freshclam.plist
To check if it’s launched:
$ sudo launchctl list | grep com.personal.freshclam
There should be an item listed as follows, which indicates that: the job is loaded; the pid
(currently ‘-‘ as it’s not running) and the exit code (0 is successful, positive is an error, negative means it was terminated after a termination signal):
- 0 com.personal.freshclam
And to check that it’s actually updated the av database:
$ ls -l freshclam.log
The file should have been updated in the last minute, or when you loaded the LaunchDaemon.
Scanning
Running a full system scan uses the familiar layout of command flags target
, flags -r is recursive, –bell shows a Terminal bell when an infection is found and -i will only print the infected files.
$ clamscan -r --bell -i /
The output will show you any infected files, with their locations.
Other options are available, such as the flag --move=/Users/[username]/quarantine
which moves viruses to a specified location.
Dealing with infections
When an infection is found, the options depend on which flags you used previously.
ClamAV’s --remove
flag should remove any infections during the scan.
This can be dangerous (and even carries a warning in the manual) as it can/will remove files that an infection is part of.
It re-runs the scan and deals with the infections as it finds them.
$ clamscan -r --remove /Users/[username]
Alternatively, if you used the --move
flag then you could go straight to the specified folder and remove them manually.
Lastly, you can just read the locations from the output.
Automated daily scans
The next thing to do is make sure all this is automated so it runs in the background without input. We’ll write a script, courtesy of centosblog.
$ vi ~/scripts/ClamAV
SCAN_DIR="/Users"
LOG_FILE="/var/log/clamscan.log"
echo `date +%F-%H%M` >> $LOG_FILE
/usr/local/bin/clamscan -i -r --move=/Users/[username]/quarantine $SCAN_DIR >> $LOG_FILE
# on BSD/Linux the location might be /usr/bin, so instead:
/usr/bin/clamscan -i -r --move=/home/[username]/quarantine $SCAN_DIR >> $LOG_FILE
The script needs to be executable:
$ chmod u+x ~/scripts/ClamAV
Finally, since we told it to write a logfile in /var/log
we need to make sure it can be written, so create the file and set the permissions on it to match the user who will be running the script:
$ sudo touch /var/log/clamscan.log
$ sudo chown [username]:[group] /var/log/clamscan.log
Now, for BSD/Linux we just need to install it to crontab and make sure it runs regularly:
$ crontab -e
05 * * * * ~/scripts/ClamAV
Or, for macOS, it’s back to launchd:
$ sudo vi /Library/LaunchDaemons/com.personal.clamav.plist
And paste:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.personal.clamscan</string>
<key>Program</key>
<string>/Users/[you]/Scripts/clamscan</string>
<key>KeepAlive</key>
<false/>
<key>RunAtLoad</key>
<false/>
<key>StartCalendarInterval</key>
<dict>
<key>Hour</key>
<integer>18</integer>
<key>Minute</key>
<integer>28</integer>
</dict>
<key>StandardErrorPath</key>
<string>/var/log/clamscan.stderr</string>
</dict>
</plist>
Finally, let’s just make sure we get system emails telling us if there’s anything found.
First, we write a simple script named clam-mail
located at ~/Scripts:
echo "There are new items for review in /Users/[you]/tmp/quarantine" | mail -s "URGENT! Clamscan Found Infections!" root
This will send an email to root
using the postfix
setup process that we’ve already been through.
Then we create the LaunchDaemon:
$ sudo vi /Library/LaunchDaemons/com.personal.clammail.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.personal.clammail</string>
<key>ProgramArguments</key>
<array>
<string>/Users/[you]/Scripts/clam-mail</string>
</array>
<key>WatchPaths</key>
<array>
<string>/Users/[you]/tmp/quarantine</string>
</array>
<key>AbandonProcessGroup</key>
<true/>
<key>StandardErrorPath</key>
<string>/var/log/clamscanqmail.stderr</string>
</dict>
</plist>
What this last daemon does is watches the directory specified under WatchPaths
and as soon as there’s any modification of that directory it will send an email to root
.
Test it, to make sure it’s all working (you should receive an email warning you of infections):
$ touch /Users/you/tmp/quarantine/test.txt